Nuxt.js まとめ

Nuxt.js インストール

yarn をダウンロード

https://yarnpkg.com/lang/en/docs/install/#windows-stable

vue-cli のインストール

グローバルインストールすることで vue コマンドが使えるようになる。

yarn global add @vue/cli

インストールできたら、バージョンを確認してみる

vue --version

テンプレートダウンロード

①starter-template

サクッと作りたいときに使う。starter-template には Babel と ESLint が含まれる

vue init nuxt-community/starter-template <projectName>

②create-nuxt-app

本格的なアプリを作るときはこれが良いらしい。

npx create-nuxt-app <projectName>

モジュールインストール

プロジェクトディレクトリに移動し、package.json にあるモジュールをインストールする

cd <projectName>
yarn
yarn dev

yarn devで起動したら、http://localhost:3000でアクセス。

環境変数を設定する

nuxt.js 内で使うグローバルな変数。

nuxt.config.js の env プロパティに設定する。サーバーの環境変数があればprocess.envを優先し、そうでなければ直書きした方を設定する。

...
env: {
     baseUrl: process.env.BASE_URL || 'http://localhost:3000' 
}
...

スタイルの設定

scss の導入

yarn add -D node-sass sass-loader

グローバル領域の scss ファイルは nuxt.config.js に記述

  ...
  css: [
    // CSS file in the project
    '@/assets/css/main.css',
    // SCSS file in the project
    '@/assets/css/main.scss'
  ],
  ...

Chrome アドオン

vue 用のデベロッパーツール拡張アドオン。あるとデバッグが捗る。

https://chrome.google.com/webstore/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd?hl=ja

サーバーサイドレンダリング(SSR)

asyncData() で非同期処理

axios を使った非同期処理をサーバーサイドでレンダリングして返す。pages/index.vueでの適当な例。

<template>
    <div>
        <ul>
            <li v-for="item in items" :key="item.id">{{ item.適当なプロパティ名 }}</li> 
        </ul> 
    </div>
</template> 

<script>
export default {
    async asyncData({app}) {
        const items = await app.$axios.$get('適当なAPIURL')
        return { items }
    }
}
</script> 

これでソースコードを見ると、既に vue のコードがレンダリングされ、データが反映されていることが分かる。

  • asyncData()はコンポーネントの初期化前に実行されるので this を使うことができない
  • asyncData()の引数は context で定義されているプロパティを受け取ることが出来るので、https://nuxtjs.org/api/context#the-context を参考にしてほしいデータを使う。
  • 例えば app にはモジュールが格納されているので、this.$axios の代わりに app.$axios でモジュールを呼び出す(import axios from 'asxios'での呼び出しとは違う)。
  • asyncData()で return したものは data() にマージされる。なので、 data() が無くても template 内で使用できている(上の例でいうとitems

メタの設定

nuxt.config.js で設定をする。%sで呼び出す。

module.exports = {
    head: {
        title: '適当なタイトル',
        titleTemplate: '%s'
    },
    ...
}

head.title はそれぞれのテンプレートで上書きできる。例えば、data に page.title というプロパティがあるとすると…

export default {
  head() {
    return {
      title: this.page.title,
      meta: [ 
        { hid: 'description', name: 'description', content: '説明だ' } 
      ]
    }
  },
}

タイトル以外は meta 配列に定義していく。

Vuex で管理

一度読み込んだデータをキャッシュしておいたりできる?クラシックモードとモジュールモードがあり、クラシックモードは3系で廃止されるらしい。モジュールモードでとてもハマった。

例:store/todos.js

export const state = () => ({
   items: [],
 })
 export const getters = {
   items: state => state.items,
 }
 export const mutations = {
   setItems(state, {items}) {
     state.items = items
   },
 }
 export const actions = {
   async fetchItems({commit}) {
     const items = await this.$axios.$get(適当なAPIURL)
     commit('setItems', {items})
   },
 }
  • state … 関数になる点に注意。ここにデータを保存する。
  • getters … ゲッター。それぞれのpageではこのgetterを使ってstateの値を呼び出す。
  • mutations … state を唯一変更できる。store.commit('mutation名')で呼び出す。
  • actions … mutation に commit メソッドを送る。非同期処理はここに書く。page側ではstore.dispatch('action名')で action を呼び出す

page/index.vue

<template>
    <div>
        <p v-for="todo in todoList" :key="todo.id">{{ todo.name }}</p>
    </div>
</template>

<script>
import { mapGetters } from 'vuex'

 export default {
   async asyncData({store}) {
     if (store.getters['todos/items'].length) {
       return
     }
     await store.dispatch('todos/fetchItems')
   },
   computed: {
     …mapGetters({
       todoList: 'todos/items'
     })
   }
 }
  • 基本的に「storeのファイル名/関数名」みたいな形で呼び出す
  • index.js に書いてたら「関数名」だけで呼べる(たぶん)けど、モジュールモードならあまり使わないのかも?
  • ...mapGetters({ ... }) で、ゲッターでゲットしてきたプロパティ名を変更できる。

エラー

Error: EPERM: operation not permitted, lstat “******”

パーミッションエラーでコンパイルできない?

特にパーミッションに関する変更などは行っていなかったので、エディタの排他制御か何かの影響だったのか、とりあえずテキストエディタを閉じてからyarn devしたら正常にコンパイルできた。.nuxtディレクトリ内のファイルを開いていたのがいけなかったのかも

Classic mode for store/ is deprecated and will be removed in Nuxt 3.

vuex のクラシックモードは廃止予定らしい。store/index.jsにて、Vuex インスタンスを return しているものはクラシックモードなので言われてしまう。なので、モジュールモードで書こう。

export default () => {
    return new Vuex.Store({ ... })
}

参考

axiosモジュール
https://uncle-javascript.com/weird-nuxt-3-axios-data-fetch