Nuxt.jsの開発環境構築の手順（最初の一歩）

## はじめに

Nuxt.jsでの開発をいくつかおこなった際にスタティックサイトの構築手順は割と汎用的だと感じたので、振り返りの意味も込めてまとめました。
Nuxt.jsの公式は日本語で情報量が充実している反面、JavaScriptフレームワークに慣れていない方にとってはどこから着手していけばいいのかわからずさまよってしまう印象を受けます。
公式の参考ページのリンクも併載しておくので合わせて読み進めると理解が捗るかもしれません。
Nuxt.jsに初めて挑戦する方やまだNuxt.js経験の浅い方などにこの記事が参考になればと思います。


## 前提

yarnを使用します。npmのコマンドを使用する方は適宜読み替えてください。

参考： [npm互換のJavaScriptパッケージマネージャーYarn入門 - ICS MEDIA](https://ics.media/entry/13838)


## 足場ツール create-nuxt-app の導入

[インストール - Nuxt.js](https://ja.nuxtjs.org/guide/installation)

Nuxt.jsチームが用意してくれている足場ツールを使用するとすばやくスタートできます。
以下のコマンドで導入しましょう。

```bash
$ yarn create nuxt-app <my-project>
```

コマンド実行後、いくつか質問されます。
今回は以下で進めますが、必要に応じて選択してください。

* サーバサイドのフレームワーク　→　None
* UIフレームワーク　→　None
* Nuxtのモード →　SPA
* axios, ESLint, Prettier　→　使用する


## プリプロセッサを使えるようにする

[プリプロセッサ - Nuxt.js](https://ja.nuxtjs.org/faq/pre-processors/)

今回は、HTMLはPug、CSSはSass（SCSS）を使用します。
以下のパッケージを追加します。

```bash
$ yarn add -D pug@2.0.3 pug-plain-loader node-sass sass-loader
```

使用したい場所にそれぞれlang属性で指定すれば使用できるようになります。

```html
<template lang="pug">
  ...
</template>

<style lang="scss">
  ...
</style>
```


## 単一ファイルコンポーネントの分離

[単一ファイルコンポーネント](https://jp.vuejs.org/v2/guide/single-file-components.html)

一つのvueファイルにtemplate(HTML), style(CSS), script(JavaScript)を記述することができますが、記述量が多くなった時に見通しが悪くなったりするのでそれぞれ別ファイルに分けます。
一つのディレクトリに各ファイルを格納してvueファイルで読み込むようにすれば分離して使用できます。
今回は HTML → Pug、CSS → SCSS として進めます。
これはcomponents, pages, layoutsディレクトリ内すべてに反映します。
※不要であればこの項目は無視して構いません。

```txt:ディレクトリサンプル
/dir
  └index.js
  └index.pug
  └index.scss
  └index.vue
```

```html:index.vue
<template
  lang="pug"
  src="./index.pug"
/>

<script src="./index.js" />

<style
  lang="scss"
  src="./index.scss"
  scoped
/>

```

styleはscopedを使用しています。

参考：[スコープ付き CSS · vue-loader](https://vue-loader-v14.vuejs.org/ja/features/scoped-css.html)

HTML・CSSのコードをPugやSCSSに変換したい場合、以下のようなツールを使用すると簡単です。

* [html2pug - convert your html code to jade](https://html2pug.herokuapp.com/)
* [css2sass | Convert CSS Snippets to Syntactically Awesome StyleSheets code](http://css2sass.herokuapp.com/)


## グローバルCSSの追加

[API: css プロパティ - Nuxt.js](https://ja.nuxtjs.org/api/configuration-css)

ページ単位（pagesディレクトリ内）やコンポーネント単位（componentsディレクトリ内）、レイアウト単位（layoutsディレクトリ内）ではそれ自体にスタイルをあてるCSS（SCSS）ファイルを格納しましたが、汎用的に設定したいスタイルもあります。（normalize, mixin, function, 変数など）
そういったものはassetsディレクトリに格納し、nuxt.config.jsに記述していくことになります。

汎用的に使用するscssファイル一式をassets/cssディレクトリに格納してnuxt.config.jsで読み込みます。
scssはインポート機能があるのでstyle.scssに必要に応じてインポートさせ、以下のように記述します。

```js:nuxt.config.js
module.exports = {
  css: [
    { src: '~assets/css/style.scss', lang: 'scss' }
  ]
}
```

上記では、一つにまとまったcssファイルとして使用できますがSass独自機能の変数などを使用する場合、pagesやcomponents、layoutsなどには個別で指定しない限り使用できません。
各ファイルに読み込みの記述をおこなうのは非効率的なので、必要に応じて一括で使用できるように設定します。
パッケージを使用して必要なファイルを読み込ませます。

```bash
$ yarn add -D nuxt-sass-resources-loader
```

nuxt.config.jsに追加

```js:nuxt.config.js
module.exports = {
  modules: [
    ['nuxt-sass-resources-loader', [
      '@/assets/sass/foundation/variable.scss',
      '@/assets/sass/foundation/mixin.scss',
    ]]
  ],
  // 省略
}
```

参考：[《Nuxt.js》Sassの共通の変数やmixinを一括で各コンポーネントに読み込む方法。 - Qiita](https://qiita.com/uto-usui/items/6b745203fa6fad577877)


## stylelintの追加

stylelintは、CSSのコーディングスタイルのルールを統一することができます。
例えば、半角をコロン「:」後に入れる・入れない、とかプロパティの順番などです。
ルールに反している部分があれば警告やエラーを表示したり、自動補正できるものは機械に修正させたりと非常に便利です。
複数人でコーディングするプロジェクトであっても一人がコーディングしているかのように統一した記述になるし、一人のプロジェクトであっても視認性が向上して快適にコーディングできます。

パッケージを追加します。

```bash
$ yarn add -D stylelint stylelint-scss stylelint-order
```

設定ファイル（stylelint.config.js）を用意します。
詳しくは以下の記事をご参考ください。

参考：[PostCSSとstylelintの環境構築 - Qiita](https://qiita.com/buchiya4th/items/01b4ad050b7c59b48539)

「詳しいことは後だ。今は早く環境構築したい」という方、
手前味噌ですが、自作したファイルがあるのでこちらを使用していただいて構いません。

[stylelintの設定ファイル](https://gist.github.com/buchiya4th/f4ca1be2ab98ee5a8098fa68a93e752c)

normalizeなどの外部から持ってきたものでstylelintから除外したい場合、.stylelintignore というファイルにパスを記述してルートディレクトリに格納しておけば除外されます。
持ってきたものは /assets/css/vendor/ に入れて以下の設定をしておけば楽です。

```txt:.stylelintignore
/assets/css/vendor/**/*.scss
```


## ESLintとPrettierの追加

[開発ツール - Nuxt.js](https://ja.nuxtjs.org/guide/development-tools)

ESLintとPrettierは、JavaScriptの構文解析やコーディングスタイルのルールを統一することができます。
Nuxt.js公式では以下のように説明があります。

> ESLint はコードをきれいに保つ優れたツールです。
> Prettier はとても人気のあるコードフォーマッタです。

今回はどちらも導入します。

パッケージを追加します。

```bash
$ yarn add -D babel-eslint eslint eslint-config-prettier eslint-loader eslint-plugin-vue eslint-plugin-prettier prettier
```

ここまで同じ手順で進めた方はすでに.eslintrc.jsがルートディレクトリに格納されているかと思います。
公式を参考に内容を変更します。

```js:.eslintrc.js
module.exports = {
  root: true,
  env: {
    browser: true,
    node: true
  },
  parserOptions: {
    parser: 'babel-eslint'
  },
  extends: [
    "eslint:recommended",
    // https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention
    // より厳しいルールにするには`plugin:vue/strongly-recommended` もしくは `plugin:vue/recommended` に切り替えることを検討してください。
    "plugin:vue/recommended",
    "plugin:prettier/recommended"
  ],
  // *.vue ファイルを lint にかけるために必要
  plugins: [
    'vue'
  ],
  // ここにカスタムルールを追加します。
  rules: {
    "semi": [2, "never"],
    "no-console": "off",
    "vue/max-attributes-per-line": "off",
    "prettier/prettier": ["error", { "semi": false }]
  }
}

```

package.jsonのscriptsに "lint", "lintfix"が記述されているかと思いますが、今回は改良します。
git commit時にlint（ESLint, stylelint）を実行させ、修正ファイル内にルールに反している記述があればcommitを取り消しエラー文を表示させます。
以下のパッケージを追加します。

```bash
$ yarn add -D husky lint-staged
```

package.jsonのscriptsのlint部分を変更し、lint-stagedの部分を追加します。

```js:package.json
  "scripts": {
    // 省略
    "lint": "run-p eslint stylelint",
    "lint-fix": "run-p eslint-fix stylelint-fix",
    "eslint": "eslint --ext .js,.vue --ignore-path .eslintignore .",
    "eslint-fix": "eslint --fix --ext .js,.vue --ignore-path .eslintignore .",
    "stylelint": "stylelint \"**/*.scss\"",
    "stylelint-fix": "stylelint \"**/*.scss\" --fix"
  },
  "lint-staged": {
    "*.js": [
      "eslint --fix",
      "git add"
    ],
    "*.scss": [
      "stylelint --fix",
      "git add"
    ]
  },
  // 省略
}
```

git commit時に自動でlintが実行されますが、手動で実行したい場合、適宜コマンドを実行させてチェックすることができます。

```bash
# ESLintとstylelint両方
$ yarn lint

# ESLintとstylelint両方（自動修正したい場合）
$ yarn lint-fix

# ESLintのみ
$ yarn eslint

# ESLintのみ（自動修正したい場合）
$ yarn eslint-fix

# stylelintのみ
$ yarn stylelint

# stylelintのみ（自動修正したい場合）
$ yarn stylelint-fix
```


## babelの設定

* [API: build プロパティ - Nuxt.js](https://ja.nuxtjs.org/api/configuration-build/)

babelは、最新のECMAScript（JavaScript）の記法に対応していないブラウザにも対応させるパッケージです。
これを導入しておくことで安心して最新の記法でコーディングしていくことができます。
polyfillも合わせて導入しておくと良いでしょう。

パッケージを追加します。

```bash
$ yarn add -D @babel/runtime @babel/plugin-syntax-dynamic-import @babel/plugin-transform-runtime @babel/preset-env babel-polyfill
```

nuxt.config.jsのbabelを変更します。

```js:nuxt.config.js
// 省略
  build: {
    babel: {
      presets: [
        [
          '@babel/preset-env',
          {
            targets: { ie: 11, uglify: true },
            useBuiltIns: 'usage'
          }
        ]
      ],
      plugins: [
        '@babel/transform-runtime',
        '@babel/plugin-syntax-dynamic-import'
      ]
    },
    vendor: [ 'babel-polyfill' ],
    // 省略
  }
}
```

#### 参考

* [Babelの設定を見直すための逆引きガイド](https://aloerina01.github.io/blog/2018-03-19-1)
* [Nuxt.jsでIE11対応のPolyfill | Hypertext Candy](https://www.hypertextcandy.com/nuxt-ie11-polyfill)


## vue-metaの設定

ページごとにtitle, meta, link要素などhead要素に記述する内容を設定でき、初期設定をnuxt.config.jsに設定します。
※pagesのページコンポーネントで指定していない場合に適用されます。

### 全体の設定

```js:nuxt.config.js
module.exports = {
  head: {
    titleTemplate: titleChunk => {
      return titleChunk
        ? `${titleChunk} | サイト名`
        : 'サイト名'
    },
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      { hid: 'description', name: 'description', content: 'Nuxt.js project' },
      { hid: 'og:url', property: 'og:url', content: '' },
      { hid: 'og:title', property: 'og:title', content: '' },
      { hid: 'og:type', property: 'og:type', content: '' },
      { hid: 'og:description', property: 'og:description', content: '' },
      { hid: 'og:image', property: 'og:image', content: '' },
      {
        hid: 'format-detection',
        name: 'format-detection',
        content: 'email=no,telephone=no,address=no'
      }
    ],
    link: [
      { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
    ]
  },
  // ...
}
```

#### 補足説明

titleTemplate：
ページコンポーネント側にtitleが設定されていなければ `'サイト名'` の部分を表示し、設定されていれば `${titleChunk} | サイト名` の部分を表示します。
${titleChunk} はページコンポーネントに設定したtitleの値が入ります。
区切り文字として「 | 」を使用していますが、使用したい文字に変更すると良いでしょう。


## 各ページの設定

[ビュー - Nuxt.js](https://ja.nuxtjs.org/guide/views#html-%E3%81%AE-head-%E6%83%85%E5%A0%B1)

pagesディレクトリ内に入れたページのjsファイルに記述します。

```js:/pages/xxxx.js
export default {
  data() {
    return {
      title: 'ページ名',
      description: 'ページの説明文',
      bodyClass: `page-category page-pageName`
    }
  },
  head() {
    return {
      title: this.title,
      meta: [
        {
          hid: 'description',
          name: 'description',
          content: this.description
        }
      ],
      bodyAttrs: {
        class: this.bodyClass
      }
    }
  },
  // 省略
```

#### 補足説明

bodyAttrs：
data内のbodyClassに設定した値をbodyのclassとして指定できます。
特定のページに対して設定したい場合に有効です。
上記では、カテゴリなどの複数ページ用のclass（page-category）と個別ページ用のclass（page-pageName）の2つを記述しています。
こうすることでカテゴリ用・特定ページ用のclassをbodyに設定することができます。


## さいごに

以上の手順で環境構築していけば割と本格的な開発環境になるのではないかと思います。
もちろん、ここに挙げていない設定もたくさんあります。
初めの取っ掛かりとして参考にしていただき、必要なものを肉付けしていくと良いかと思います。