Nuxt.js + TypeScript 俺的Day1対応

Day１対応とカッコつけて言ってみましたが、要はNuxt.js + TypeScriptプロジェクト作成後の初期環境構築です。
毎回似たようなことをやっているので、ググらなくても良いようにまとめました。

# Nuxt.jsプロジェクトの作成
プロジェクト作成の設定自体は任意ですが、今回は下記設定で作成しました。

```sh
$ npx create-nuxt-app sample-app

create-nuxt-app v3.6.0
✨  Generating Nuxt.js project in sample-app
? Project name: sample-app
? Programming language: TypeScript
? Package manager: Npm
? UI framework: Element
? Nuxt.js modules: Axios - Promise based HTTP client
? Linting tools: ESLint
? Testing framework: Jest
? Rendering mode: Single Page App
? Deployment target: Static (Static/Jamstack hosting)
? Development tools: jsconfig.json (Recommended for VS Code if you're not using typescript)
? Continuous integration: None
? Version control system: Git
```

# ESLintの設定

Linterを設定します。

まず、`.eslintrc.js` にルールを設定します。
今回は例として下記のように設定しました。

```js:.eslintrc.js
module.exports = {
  root: true,
  env: {
    browser: true,
    node: true
  },
  parserOptions: {
  },
  extends: [
    '@nuxtjs/eslint-config-typescript',
    "eslint:recommended",
    "plugin:vue/recommended"
  ],
  plugins: [
    'vue'
  ],
  rules: {
    "object-curly-spacing": [2, "always"],
    "space-before-blocks": "error",
    "space-infix-ops": "error",
    "space-before-function-paren": ["error", "never"],
    "keyword-spacing": ["error", { "overrides": {
      "if": { "after": false },
      "else": { "after": true },
      "switch": { "after": false },
      "for": { "after": false },
      "while": { "after": false }
    } }],
    "no-empty-pattern": "off",
    "no-return-await": "off",
    "indent": [2, 2],
    "semi": "off",
    "@typescript-eslint/semi": ["error"],
    "curly": ["error", "multi-line"],
    "eqeqeq": "error",
    "no-trailing-spaces": "error",
    "block-spacing": ["error", "always"],
    "brace-style": ["error", "1tbs", { "allowSingleLine": false }],
    "no-multi-spaces": "error",
    "no-multiple-empty-lines": [1, { "max": 1 }],
    "comma-spacing": [2, { "before": false, "after": true }]
  }
}
```

次に、ホットリロード時に自動でlinterが走るように設定します。

`eslint-loader` をインストールします。

```sh
$ npm i --save eslint-loader
```

`nuxt.config.js` に下記を追記します。

```js:nuxt.config.js
export default {
  build: {
    extend(config, ctx) {
      if (ctx.isDev && ctx.isClient) {
        config.module.rules.push({
          enforce: "pre",
          test: /\.(js|vue)$/,
          loader: "eslint-loader",
          exclude: /(node_modules)/
        })
      }
    }
  },
}
```

以上で完了です。
ホットリロード時にルールを満たしていない記述がある場合はエラーになるので、修正しておきましょう。

# scssの導入

必要なパッケージをインストールします。
ついでにscssで色などを変数で扱う際に便利な `style-resources` もインストールしています。

```sh
$ npm i --save-dev sass sass-loader@10 fibers @nuxtjs/style-resources
```

`style-resources` 用の変数を記述するファイルを作成します。

```sh
$ mkdir assets/scss
$ touch assets/scss/variable.scss
```

作成したファイルを読み込むように、 `nuxt.config.js` に追記します。

```js:nuxt.config.js
export default {
  styleResources: {
    scss: [
      '@/assets/scss/variable.scss'
    ]
  },
  modules: [
    '@nuxtjs/style-resources'
  ],
}
```

コンポーネント間で共通で使用可能になるscssを定義するファイルも作成しておきます。

```
$ touch assets/scss/common.scss
```

こちらも、 `nuxt.config.js` に追記します。

```js:nuxt.config.js
export default {
  css: [
    '@/assets/scss/common.scss'
  ],
}
```

以上で完了です。

# pugの導入

自分は[pug](https://github.com/pugjs/pug)を使うことがちょくちょくあるので、記述しておきます。
必要なパッケージをインストールします。

```
$ npm i --save-dev pug pug-plain-loader
```

pugを導入することで、プロジェクト作成時の `pages/index.vue` のtemplate部分を下記のように書き換え可能です。

```vue:pages/index.vue
<template lang="pug">
  .container
    div
      logo
      h1.title sample-app
      .links
        a(href="https://nuxtjs.org/"
          target="_blank"
          rel="noopener noreferrer"
          class="button--green") Documentation
        a(href="https://github.com/nuxt/nuxt.js"
          target="_blank"
          rel="noopener noreferrer"
          class="button--grey") GitHub
</template>
```

# nuxt-property-decoratorの導入

これも好みではありますが、 [nuxt-property-decorator](https://github.com/nuxt-community/nuxt-property-decorator)をインストールします。

```
$ npm i --save nuxt-property-decorator
```

`nuxt-property-decorator` を導入することで、プロジェクト作成時の `pages/index.vue` のscript部分を下記のように書き換え可能です。

```vue:pages/index.vue
<script lang="ts">
import { Component, Vue } from 'nuxt-property-decorator';

@Component
export default class Index extends Vue {}
</script>
```

# cross-envの導入

[cross-env](https://github.com/kentcdodds/cross-env)を導入して、環境毎に変数を分けられるようにします。

```sh
$ npm i --save-dev cross-env
```

今回は例として、 `development`、 `staging`、 `production` という環境を作成するものとします。
まず環境ファイルを格納する用のディレクトリを作成し、各環境ファイルを作成します。

```sh
$ mkdir environments
$ touch environments/env.development.js
$ touch environments/env.staging.js
$ touch environments/env.production.js
```

各ファイルは、例として下記のようにします。
APIの向き先などを、環境毎に変更可能となります。

```js:environments/env.development.js
module.exports = {
  NODE_ENV: 'development',
  API_BASE_URL: 'https://api.development.com/',
};
```

```js:environments/env.staging.js
module.exports = {
  NODE_ENV: 'staging',
  API_BASE_URL: 'https://api.staging.com/',
};
```

```js:environments/env.production.js
module.exports = {
  NODE_ENV: 'production',
  API_BASE_URL: 'https://api.production.com/',
};
```

次に、`nuxt.config.js` ファイルに追記します。

```js:nuxt.config.js
const envSet = require(`./environments/env.${process.env.NODE_ENV || 'development'}.js`);
export default {
  env: envSet
}
```

`package.json` の `script` 部分を修正し、環境毎の `generate` コマンドなどを作成可能です。

```json:package.json
{
  "scripts": {
    "generate": "nuxt generate",
    "generate:staging": "cross-env NODE_ENV=staging nuxt generate",
    "generate:production": "cross-env NODE_ENV=production nuxt generate"
  },
}
```

# i18n対応

多言語化には [nuxt/i18n](https://i18n.nuxtjs.org/)が便利です。
多言語化しないプロジェクトでも、文字列を一箇所にまとめて管理できるのは便利なので、自分は基本的に設定するようにしています。

まずはパッケージをインストールします。

```sh
$ npm i --save nuxt-i18n
```

各言語を管理するためのファイルと、そのファイルを格納するディレクトリを作成します。

```sh
$ mkdir locales
$ touch locales/ja.json
```

`nuxt.config.js` に設定を追記します。

```js:nuxt.config.js
export default {
  i18n: {
    locales: [
      { code: 'ja', iso: 'ja_JP', file: 'ja.json' }
    ],
    defaultLocale: 'ja',
    langDir: 'locales/',
    vueI18n: {
      fallbackLocale: 'ja'
    },
    vueI18nLoader: true,
    lazy: true
  },

  modules: [
    'nuxt-i18n'
  ],
}
```

`tsconfig.json` に設定を追記します。

```json:tsconfig.json
{
  "compilerOptions": {
    "types": [
      "@nuxt/types",
      "nuxt-i18n",
    ]
  }
}
```

以上で完了です。

---

上記以外にも、`vuex`や `axios` まわりの設定や、プロジェクトによっては `storybook` を入れるなど色々とあるかもしれませんが、割と毎回やるものだけまとめました。
これから追記などもしていくかもしれません。