Nuxt.jsチートシート

関連:
- [Vue.jsチートシート(基礎編)](https://qiita.com/morrr/items/289b6e7ac82e969a7a58)
- [Vue.jsチートシート(コンポーネントと構成編)](https://qiita.com/morrr/items/2642135a927d6a3e7584)

Vueチートシートに引き続き公式チュートリアルの抜粋です。


参照
------------------------------------------------------------
- [Nuxt.js日本語公式](https://ja.nuxtjs.org)
    - [ガイド](https://ja.nuxtjs.org/guide)

概要
------------------------------------------------------------
- Nuxt.js = Vue.jsおよびそのプラグインに基づくサーバサイドフレームワーク
    - NuxtはVue.js, vue-router, vuex, Vue Server Render, Vue Metaなどを包含する
    - Vueと同じく部分的に利用することができる(Progressive Framework)

- 公式によると以下のような機能を提供している:

    > - Vue ファイルで記述できること（*.vue）
    > - コードを自動的に分割すること
    > - サーバーサイドレンダリング
    > - 非同期データをハンドリングするパワフルなルーティング
    > - 静的ファイルの配信
    > - ES2015+ のトランスパイレーション
    > - JS と CSS のバンドル及びミニファイ化
    > - <head> 要素（<title>、<meta> など）の管理
    > - 開発モードにおけるホットリローディング
    > - プリプロセッサ: Sass, Less, Stylus など
    > - HTTP/2 push headers ready
    > - モジュール構造で拡張できること

- SSRの実現を主目的として導入されることが多いが、単純なSPAとして動作させることもできる
- jekyllのようにVueコンポーネントから静的サイトをビルドすることもできる
- Node.jsベースで動作する
    - AppフレームワークとしてExpressをはじめとした複数を選択できる
    - UIフレームワークも同様にBootstrap, Element UIなどを選択できる
    - テストフレームワークも同様

導入
------------------------------------------------------------
- [npx](https://www.npmjs.com/package/npx) を使ってNuxtプロジェクトを簡単に作成できる

    ```sh
    # npm5.2+はデフォルト
    $ npm install -g npx

    # インタラクティブに入力してプロジェクトを作成する
    # App/UI/テストフレームワークもここで選べる
    # yarn create nuxt-app <project-name> でも同じ
    $ npx create-nuxt-app <project-name>

    # 開発環境を起動
    $ npm run dev
    ```

- 既存のプロジェクトに導入する場合はnpmパッケージとしてインストールする

    ```js:package.json
    // npm run devでnuxtが立ち上がるように設定しておく
    {
      "name": "my-app",
      "scripts": {
        "dev": "nuxt"
      }
    }
    ```

    ```sh
    $ npm install --save nuxt
    ```


基礎
------------------------------------------------------------
### ディレクトリ構造
Nuxtのプロジェクトは以下のようなディレクトリ構成をとる:

path | includes | memo
--- | --- | ---
`/assets/` | CSS(SASS), 画像, フォントファイルなど静的なファイル | 
`/components/` | Vueコンポーネント | 
`/layouts/` | アプリケーションレイアウト | 
`/middleware/` | ミドルウェア(ページレンダリング以前に実行される処理) | 
`/pages/` | ViewおよびRouter | これ以下のファイル構成をもとにしてRoutingを作成する
`/plugins/` | Vueのinstanciateより前に実行したい処理 | 
`/static/` | サーバのroot直下に直接配置されるファイル | faviconやrobots.txtなど
`/store/` | Vuexストアファイル
`/nuxt.config.js` | Nuxtの設定


### ディレクトリエイリアス
- Nuxt Appにおいて `~` あるいは `@` はソースが格納されるディレクトリ(srcDir) を示す
    - `~~`, `@@` はrootDir
    - srcDirとrootDirはデフォルトでは等値


### 設定の分類
`/nuxt.config.js` の設定は以下のようなトップレベルのキー以下に分類される:

category | includes | memo
--- | --- | ---
`build` | webpackを含むビルドオプション | 
`css` | 共有するCSSファイル/ライブラリの設定 | 
`dev` | Dev/Prodモード | 
`env` | 環境変数  
`generate` | routing | 
`head` | meta-tagの設定 | 
`loading` | ローディングコンポーネントの設定 | 
`modules` | Nuxtモジュールの設定 | 
`modulesDir` | node_modulesの所在 | 
`plugins` | plugins/ 以下の設定 | 
`rootDir` | Nuxtアプリケーションのroot | 
`router` | Vue Router設定 | 
`server` | サーバの設定 | 
`srcDir` | ソースの所在| 
`dir` | カスタムディレクトリの設定 | 
`transition` | トランジションの設定 | 


Routing
------------------------------------------------------------
Nuxtはvue-routerを用いてページをルーティングする

### ルーティングの自動生成
- `/pages/` 内のファイル・ディレクトリ構造に基づいて、自動的に設定を生成する

    ```:たとえばこんなファイル構成だと
    pages/
        index.vue
        users/
            index.vue
    ```

    ```js:このようになる
    router: {
      routes: [
        { name: 'index', path: '/', component: 'pages/index.vue' },
        { name: 'users', path: '/users', component: 'pages/users/index.vue' },
      ]
    }
    ```

### Link
- ページ間の遷移は `<router-link>` ではなく `<nuxt-link>` を使う

    ```html
    <nuxt-link to="/">Home</nuxt-link>
    ```

### パラメータ
- URLにパラメータを含める場合はファイル名にアンダースコアをつける

    ```
    pages/
        users/
            _id.vue
        posts/
            _id/
                index.vue
    ```

    ```js
    router: {
      routes: [
        // こうするとパラメータが必須でなくなる(?)
        { name: 'users-id', path: '/users/:id?', component: 'pages/users/_id.vue' },

        // 必須にしたい場合はディレクトリを切る
        { name: 'posts-id', path: '/posts/:id', component: 'pages/posts/_id/index.vue' },
      ]
    }
    ```

- パラメータを検証することができる
    - 検証失敗した場合、Nuxtサーバは404を返す
    - あるいはエラーがthrowされた場合は500を返す

    ```js:アンダースコアから始まる(パラメータを含む)ページの.vueファイル
    export default {
      validate({ params }){
        // 戻り地の真偽をもって検証の可否とする
        return params.id > 0
      }
    }
    ```

### ネスト
- ページをネストする場合は、リンクと同様に `<router-view>` ではなく `<nuxt-child>` を親コンポーネントに配置する

    ```
    pages/
        users/
            _id.vue
            index.vue
        users.vue
    ```

    ```js
    // users.vueに <nuxt-child> を配置しておく必要がある
    router: {
      routes: [
        {
          path: '/users',
          component: 'pages/users.vue',
          children: [
            { path: '', component: 'pages/users/index.vue', name: 'users' },
            { path: ':id', component: 'pages/users/_id.vue', name: 'users-id' }
          ]
        }
      ]
    }
    ```

### 未知のパスをハンドルする
- `_.vue` ファイルを配置すると、その他にマッチしなかった全てをハンドルできる

    ```
    # / はindex.vue
    # /users/ はusers/
    # /foo などそれ以外は _.vue
    pages/
        _.vue
        index.vue
        users/
    ```

View
------------------------------------------------------------
### Appテンプレート
- 全てのViewに共通するHTML(Appテンプレート)を定義できる
    - Appテンプレートは `/<rootDir>/app.html` として配置する

    ```html:/app.html
    <!-- こんなふうに定義しておく(以下はNuxtのデフォルトのAppテンプレート -->
    <!DOCTYPE html>
    <html {{ HTML_ATTRS }}>
      <head {{ HEAD_ATTRS }}>
        {{ HEAD }}
      </head>
      <body {{ BODY_ATTRS }}>
        {{ APP }}
      </body>
    </html>
    ```

### Layout
- デフォルトのレイアウトは `/layouts/default.vue` である

    ```html:/layouts/default.vue
    <!-- nuxtタグにページがレンダリングされる -->
    <template>
      <nuxt />
    </template>
    ```

- レイアウトをカスタムしたい場合は `/layouts` にファイルを配置する

    ```html:/layouts/custom.vue
    <template>
      <!-- ...カスタムされたレイアウト -->
      <nuxt />
    </template>
    ```

- カスタムレイアウトはページ側で指定することで利用できる

    ```js
    export default{
      layout: 'custom'
    }
    ```

- App内でエラーが発生した場合のエラーページは、レイアウトのひとつ(`error.vue`)として定義しカスタムできる
    - エラーページの例は [公開されている](https://github.com/nuxt/nuxt.js/blob/dev/packages/vue-app/template/components/nuxt-error.vue)

### ページ
- Nuxt上のページ(Vueコンポーネント)は、SSRのために追加の機能が提供されている

    ```vue:page.vue
    <template>
      <h1 class="red">Hello {{ name }}!</h1>
    </template>

    <script>
    export default {
      // コンポーネントのロードの都度呼ばれる
      // 非同期で実行でき、戻り値はdataオブジェクトとマージされる
      asyncData (context) {
        return ...
      },

      // ページの描画前にstoreを初期化する
      fetch () {
        // ...
      },

      // <meta> を設定する
      head () {
        // ...
      },

      // レイアウトを設定する
      layout: 'custom',

      // 遷移時のアニメーションを設定する
      loading: false,

      // 遷移時にスクロールを一番上に戻すか
      scrollToTop: true,

      // トランジションの設定
      //transition: ...,

      // ミドルウェアの設定
      //middleware: ...
    }
    </script>
    
    <style>
    .red {
      color: red;
    }
    </style>
    ```

### メタタグ
- `<meta>` の内容はすべて `nuxt.config.js` に定義できる
    - ページ単位でカスタムしたい場合はコンポーネントにheadプロパティを定義する

    ```js:nuxt.config.js
    head: {
      meta: [
        { charset: 'utf-8' },
      ],
      link: [
        { rel: 'stylesheet', href: 'https://fonts.googleapis.com/css?family=Roboto' }
      ]
    }
    ```

非同期データ処理
------------------------------------------------------------
### asyncDataとコンテキスト
コンポーネントの `asyncData` プロパティ(メソッド)は、ページのロードとは非同期的なデータの読み込みのために用いる。

- asyncDataが呼ばれるたびに、その結果がdataにマージされる
    - サーバサイドでは、ページがリクエストされた際に一度だけ呼ばれる
    - クライアントサイドでは、ページ遷移のたびに呼ばれる

- asyncDataは `this` を使えない
    - コンポーネントがinstanciateされる前に、別のスコープで(非同期に)呼び出されるため
    - 代わりに引数の `context` を介して必要なデータを取得できる


- Promiseオブジェクトを返すほか、async/awaitを使って書くこともできる

    ```js
    // Promise
    export default {
      asyncData ({ params }) {
        return axios.get('https://...')
        .then((res) => {
          return { ... }
        })
      }
    }

    // async/await
    export default {
      async asyncData ({ params }) {
        let { data } = await axios.get('...')
        return { title: data.title }
      }
    }
    ```

- Promiseによってエラーの制御もできる

    ```js
    export default {
      asyncData ({ params, error }) {
        return axios.get('...')
        .then((res) => {
          return { ... }
        })
        .catch((e) => {
          error({ statusCode: 404, message: 'Not Found' })
        })
      }
    }
    ```

Asset/Static
------------------------------------------------------------
### Asset
- `assets/` に配置されたファイルは vue-loader, file-loaderなどwebpackの機能を利用して「アセット」として参照できる
    - アセットはvueファイルから、 `~assets/...` の形式で参照できる

        ```html
        <template>
          <img src="~/assets/image.png">
        </template>
        ```

    - file-loaderの場合、アセットファイルはサーバ上にバージョン付きのファイル名で配置される
    - url-loaderの場合、アセットファイル(画像)はURL-encodingされてHTML上にインライン展開される

### Static
- `static/` に配置されたファイルは Assetの機能を利用することなく、単に静的なファイルとして配置・公開される
    - faviconなどはここに置く


Plugin
------------------------------------------------------------
- npmパッケージをNuxtで利用したい場合、インストールするだけでそのまま利用できる

    ```sh
    $ npm install --save axios
    ```

    ```vue
    <template>
      ...
    </template>
    
    <script>
    import axios from 'axios'
    
    export default {
      async asyncData ({ params }) {
        let { data } = await axios.get('...')
        // ...
      }
    }
    </script>
    ```

- Vueのプラグインを利用したい場合、 `plugins/` 以下に設定を追加する必要がある

    ```js:plugins/some-vue-plugin.js
    import Vue from 'vue'
    import SomeVuePlugin from 'some-vue-plugin'

    Vue.use(SomeVuePlugin)
    ```

    ```js:nuxt.config.js
    export default {
      // ...
      plugins: [
        '~/plugins/some-vue-plugin'

        // クライアント/サーバサイドにそれぞれ限定のプラグインはモードを指定できる
        { src: '~/plugins/some-client-only-plugin', mode: 'client' }
      ]


      // プラグインがES6などで書かれている場合はビルドの指定も必要になる
      build: {
        transpile: ['some-vue-plugin']
      }
    }
    ```

Module
------------------------------------------------------------
- Module = Nuxt自体の機能拡張
    - 例:
        - `@nuxtjs/axios` : Nuxtとaxiosの統合
        - `@nuxtjs/auth` : 認証機能を提供する

- Moduleはnpmパッケージとして公開するほか、プロジェクトローカルに独自定義することもできる

    ```js:modules/some-module.js
    export default function SomeModule(options){
      // ...
    }
    ```

ビルド/デプロイ
------------------------------------------------------------
- NuxtはCLIを提供しており、これによってビルドやデプロイができる
    
    ```js:package.json
    {
      // ...

      // グローバルインストールした場合は $ nuxt で直接呼べる
      // ローカルインストールした状態で利用したい場合はpackage.jsonにscriptを設定する
      // $ npm run dev などとして利用可能
      "scripts": {
        "dev": "nuxt",
        "build": "nuxt build",
        "start": "nuxt start",
        "generate": "nuxt generate",
        "test": "jest"
      },
    }
    ```

- Appの提供形式によって利用するコマンドが変わってくる
    - 開発環境では `nuxt` でサーバを起動する
    - SSRの場合は `nuxt start` によって本番モードでサーバを起動する
    - 静的サイトの場合は `nuxt generate` でページをビルドする
    - SPAの場合も同様に `nuxt generate` でビルドする(SPAモード指定が必要)