Nuxt(v2.4未満) + Typescriptセットアップ

Nuxt v2.4で公式にTypescriptがサポートされた。
この記事はそれ以前のNuxtでTypescriptを使うための方法について記述している。
これから始めるなら[Nuxt\(v2\.4以降\) \+ Typescriptセットアップ](https://qiita.com/HeRo/items/56308a38388a05bdd550)を参照いただきたい。

----
最近、Nuxtについてよく見かけるので、やってみようとちょっと触ってみた。
どうせなら、Typescriptでやりたい。PugやSassを使えたほうがいいだろうとセットアップしてみた。

このエントリの結果できあがる構成の
2018/10/06 時点での主なモジュールのバージョンは次の通り。

- nuxt: 2.1.0
- typescript: 3.1.1
- pug: 2.0.3
- node-sass: 4.9.3

## セットアップ

最初に vue-cli をインストールする。`vue init`を使うには`@vue/cli-init`のインストールも必要らしい。
```bash
$ npm i @vue/cli @vue/cli-init
```

続いて、typescript のセットアップされたテンプレートを利用してプロジェクトを作成する。
最初にプロジェクト名等を聞いてくる。適当に入力して進む。

```bash
$ vue init nuxt-community/typescript-template my-project

? Project name my-project
? Project description Nuxt.js TypeScript project
? Author HeRo <hero@example.com>

   vue-cli · Generated "my-project".

   To get started:
   
     cd my-project
     npm install # Or yarn
     npm run dev
```

`vue init`の実行出力の最後に次に実行すべきコマンドが示されるのでそれに従う。

まずはディレクトリを移動して、モジュールのインストール

```bash
$ cd my-project
$ yarn
yarn install v1.3.2
info No lockfile found.
[1/4] 🔍  Resolving packages...
warning nuxt > postcss-cssnext@3.1.0: 'postcss-cssnext' has been deprecated in favor of 'postcss-preset-env'. Read more at https://moox.io/blog/deprecating-cssnext/
warning nuxt > autoprefixer > browserslist@2.11.3: Browserslist 2 could fail on reading Browserslist >3.0 config used in other tools.
warning nuxt > css-loader > cssnano > autoprefixer > browserslist@1.7.7: Browserslist 2 could fail on reading Browserslist >3.0 config used in other tools.
warning nuxt > postcss-cssnext > caniuse-api > browserslist@2.11.3: Browserslist 2 could fail on reading Browserslist >3.0 config used in other tools.
warning nuxt > webpack-bundle-analyzer > bfj-node4@5.3.1: Switch to the `bfj` package for fixes and new features!
warning nuxt > css-loader > cssnano > postcss-merge-rules > browserslist@1.7.7: Browserslist 2 could fail on reading Browserslist >3.0 config used in other tools.
warning nuxt > css-loader > cssnano > postcss-merge-rules > caniuse-api > browserslist@1.7.7: Browserslist 2 could fail on reading Browserslist >3.0 config used in other tools.
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
warning " > vuex-class@0.3.1" has unmet peer dependency "vue@^2.5.0".
warning " > vuex-class@0.3.1" has unmet peer dependency "vuex@^3.0.0".
warning " > vuex-class@0.3.1" has unmet peer dependency "vue-class-component@^6.0.0".
[4/4] 📃  Building fresh packages...
success Saved lockfile.
warning Your current version of Yarn is out of date. The latest version is "1.10.1" while you're on "1.3.2".
info To upgrade, run the following command:
$ curl -o- -L https://yarnpkg.com/install.sh | bash
✨  Done in 35.84s.
```

続いて `npm run dev`を実行。

```bash
$ npm run dev

> my-project@1.0.0 dev /Users/hoge/nuxt-lesson/my-project
> nuxt

… debug nuxt › axios › baseURL: http://localhost:3000/
… debug nuxt › axios › browserBaseURL: http://localhost:3000/
  nuxt:build App root: /Users/hoge/nuxt-lesson/my-project +0ms
  nuxt:build Generating /Users/hoge/nuxt-lesson/my-project/.nuxt files... +0ms
  nuxt:build Generating files... +30ms
  nuxt:build Generating routes... +13ms
  nuxt:build Building files... +33ms
  nuxt:build Adding webpack middleware... +1s
  ████████████████████ 100%

Build completed in 6.942s

 DONE  Compiled successfully in -4054ms                                                                                            

 OPEN  http://localhost:3000
```

最後にURLが示されるので、それをブラウザで開いてみる。
次のページが表示される。

![localhost_3000_.png](https://qiita-image-store.s3.amazonaws.com/0/32533/82bca8f5-4608-4aed-73b3-fdb4d8111fbb.png)

## もろもろアップグレード
とりあえず、動く状態になったものの、2018/10/06 時点ではこんな感じ。

```bash
$ yarn outdated
yarn outdated v1.3.2
info Color legend :
 "<red>"    : Major Update backward-incompatible updates
 "<yellow>" : Minor Update backward-compatible features
 "<green>"  : Patch Update backward-compatible bug fixes
Package     Current Wanted Latest  Package Type    URL
@types/node 9.6.34  9.6.34 10.11.4 devDependencies https://github.com/DefinitelyTyped/DefinitelyTyped.git
nuxt        1.4.2   1.4.2  2.1.0   dependencies    https://github.com/nuxt/nuxt.js#readme
ts-loader   3.5.0   3.5.0  5.2.1   devDependencies https://github.com/TypeStrong/ts-loader
typescript  2.9.2   2.9.2  3.1.1   devDependencies http://typescriptlang.org/
✨  Done in 0.44s.
```
いろいろ古い。

### 

まずは差し障り少なそうなところからアップグレード。

```bash
$ yarn upgrade @types/node@^10.11.4
$ yarn upgrade typescript@^3.1.1
```

この時点で、`npm run dev`を試しても動作に問題はない。

```bash
yarn upgrade nuxt@^2.1.0
```

この時点で、`npm run dev`を試すと次のようなエラーが発生する。

```bash
$ npm run dev

> my-project@1.0.0 dev /Users/hero/Develop/typescritp/my-project
> nuxt



 INFO  Building project

✔ success Builder initialized
✔ success Nuxt files generated
✖ error TypeError: Cannot set property 'ts' of undefined
  at Builder.extendBuild.config (/Users/hero/nuxt-lesson/my-project/modules/typescript.js:24:33)
  at Builder.<anonymous> (/Users/hero/nuxt-lesson/node_modules/nuxt/dist/nuxt.js:158:17)
  at WebpackClientConfig.extendConfig (/Users/hero/nuxt-lesson/my-project/node_modules/nuxt/dist/nuxt.js:3144:56)
  at WebpackClientConfig.extendConfig (/Users/hero/nuxt-lesson/my-project/node_modules/nuxt/dist/nuxt.js:3286:26)
  at WebpackClientConfig.config (/Users/hero/nuxt-lesson/my-project/node_modules/nuxt/dist/nuxt.js:3182:33)
  at WebpackClientConfig.config (/Users/hero/nuxt-lesson/my-project/node_modules/nuxt/dist/nuxt.js:3325:26)
  at Builder.webpackBuild (/Users/hero/nuxt-lesson/my-project/node_modules/nuxt/dist/nuxt.js:3922:56)
  at Builder.build (/Users/hero/nuxt-lesson/my-project/node_modules/nuxt/dist/nuxt.js:3632:16)
```

*modules/typescript.js*が悪そうなので、次のように1行足してみる。

```javascript:modules/typescript.js
// Add TypeScript loader for vue files
for (let rule of config.module.rules) {
  if (rule.loader === "vue-loader") {
    rule.options.loaders = rule.options.loaders || {}; // <=この行を追加
    rule.options.loaders.ts = tsLoader
  }
}
```

再度`npm run dev`を実行すると今度は次のようなエラー。

```bash
$ npm run dev

> my-project@1.0.0 dev /Users/hero/Develop/typescritp/my-project
> nuxt



 INFO  Building project

✔ success Builder initialized
✔ success Nuxt files generated


 ERROR  Failed to compile with 2 errors                                                                                                    12:23:10 PM

 error  in (webpack)-hot-middleware/client.js?name=client&reload=true&timeout=30000&path=/__webpack_hmr

Module build failed (from ./node_modules/ts-loader/index.js):
TypeError: Cannot read property 'ts' of undefined
    at getLoaderOptions (/Users/hero/Develop/typescritp/my-project/node_modules/ts-loader/dist/index.js:70:44)
    at Object.loader (/Users/hero/Develop/typescritp/my-project/node_modules/ts-loader/dist/index.js:23:19)

 @ multi webpack-hot-middleware/client?name=client&reload=true&timeout=30000&path=/__webpack_hmr ./.nuxt/client.js

 error  in ./.nuxt/client.js

Module build failed (from ./node_modules/ts-loader/index.js):
TypeError: Cannot read property 'ts' of undefined
    at getLoaderOptions (/Users/hero/Develop/typescritp/my-project/node_modules/ts-loader/dist/index.js:70:44)
    at Object.loader (/Users/hero/Develop/typescritp/my-project/node_modules/ts-loader/dist/index.js:23:19)

 @ multi webpack-hot-middleware/client?name=client&reload=true&timeout=30000&path=/__webpack_hmr ./.nuxt/client.js



 READY  Listening on http://localhost:3000



 ERROR  Failed to compile with 2 errors                                                                                                    12:23:10 PM

 error  in (webpack)-hot-middleware/client.js?name=client&reload=true&timeout=30000&path=/__webpack_hmr

Module build failed (from ./node_modules/ts-loader/index.js):
TypeError: Cannot read property 'ts' of undefined
    at getLoaderOptions (/Users/hero/Develop/typescritp/my-project/node_modules/ts-loader/dist/index.js:70:44)
    at Object.loader (/Users/hero/Develop/typescritp/my-project/node_modules/ts-loader/dist/index.js:23:19)

 @ multi webpack-hot-middleware/client?name=client&reload=true&timeout=30000&path=/__webpack_hmr ./.nuxt/client.js

 error  in ./.nuxt/client.js

Module build failed (from ./node_modules/ts-loader/index.js):
TypeError: Cannot read property 'ts' of undefined
    at getLoaderOptions (/Users/hero/Develop/typescritp/my-project/node_modules/ts-loader/dist/index.js:70:44)
    at Object.loader (/Users/hero/Develop/typescritp/my-project/node_modules/ts-loader/dist/index.js:23:19)

 @ multi webpack-hot-middleware/client?name=client&reload=true&timeout=30000&path=/__webpack_hmr ./.nuxt/client.js
```

ts-loaderが悪そう。どうせ古いし、アップグレードしてしまおう。

```
$ yarn ts-loader@^5.2.1
```

そして、`npm run dev`を実行すると、エラーがなくなった。アップグレード成功！

## Pugの導入

まずは必要なモジュールのインストール

```bash
$ yarn add -D pug pug-plain-loader
```

で、*nuxt-community/typescript-template* には次の3つの`*.vue`モジュールがある。

- components/Card.vue
- layouts/default.vue
- pages/index.vue

この中の`<template>`タグの中を HTMLから Pugに変更していく。
[html2pug \- convert your html code to jade](https://html2pug.herokuapp.com/)などオンラインの変換サイトを利用すれば簡単だ。

### components/Card.vue
最初のファイル。

```html:components/Card.vue
<template>
  <div class="card">
    <h2> </h2>
    <img :src="'https://robohash.org/' + person.first_name + '_' + person.last_name" />
  </div>
</template>
```

pugに書き換えると次のようになる。

```slim:components/Card.vue
<template lang="pug">
  .card
      h2  
      img(:src="'https://robohash.org/' + person.first_name + '_' + person.last_name")
</template>
```

### layouts/default.vue
次のファイル。

```html:layouts/default.vue
<template>
  <div>
    <nuxt/>
  </div>
</template>
```

これをPugに書き換えると次の通り。

```slim:layouts/default.vue
<template lang="pug">
  div
    nuxt
</template>
```

### pages/index.vue
最後のファイル。

```html:pages/index.vue
<template>
  <section>
    <h1 class="header">Nuxt TypeScript Starter</h1>
    <div class="cards">
      <Card v-for="person in people" :key="person.id" :person="person"></Card>
    </div>
  </section>
</template>
```
これも Pugに書き換えるとこの通り。

```slim:pages/index.vue
<template lang="pug">
  section
    h1.header Nuxt TypeScript Starter
      .cards
        card(v-for="person in people" :key="person.id" :person="person")
</template>
```
で、再度、`npm run dev`を実行すると、何も変わらず表示できる。

## SASSの導入

とりあえず、必要なモジュールのインストール

```bash
$ yarn add -D node-sass sass-loader
```

で、Pugの場合と同じように3ファイルを書き換えればよいわけだが、*layouts/default.vue*には`<style>`はないので次の2ファイルを変換する。

- components/Card.vue
- pages/index.vue

これも、[css2sass \| Convert CSS Snippets to Syntactically Awesome StyleSheets code](http://css2sass.herokuapp.com/)などを使うと簡単。

### components/Card.vue

```css
<style scoped>
.card {
  font-family: "Segoe UI", Tahoma, Geneva, Verdana,
    sans-serif;
  padding: 1rem;
  margin: 0.25rem;
  border: 0.25rem solid gainsboro;
}
</style>
```
これをSASSに変換すると次の通り。

```sass
<style scoped lang="sass">
.card
  font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif
  padding: 1rem
  margin: 0.25rem
  border: 0.25rem solid gainsboro
</style>
```

### pages/index.vue

```css
<style scoped>
.header {
  font-family: "Segoe UI", Tahoma, Geneva, Verdana,
    sans-serif;
}

.cards {
  display: flex;
  flex-wrap: wrap;
}
</style>
```

```sass
<style scoped lang="sass">
.header
  font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif

.cards
  display: flex
  flex-wrap: wrap
</style>
```

以上、 Nuxt ＋ Typescript with Pug ＆ SASS の出来上がり。

## 参考
- [Nuxt\.jsのプロジェクトをNuxt\.js2にバージョンアップしてみた \- Crieit](https://crieit.net/posts/Nuxt-js-Nuxt-js2)
- [プリプロセッサ \- Nuxt\.js](https://ja.nuxtjs.org/faq/pre-processors/)