そのNuxt、TypeScriptで。

年末！楽しんでますか！
[TUT Advent Calendar 2019](https://adventar.org/calendars/4174) 15日目の記事です！

Vue.jsベースで**SPAが手軽に作れると評判のNuxt**...
ビルド時に型検査が入り、**絶大な安心感を提供するTypeScript**...

これらふたつを組み合わせた**モダンなフロントエンド開発で寒い冬を乗り切ろう！！！**
npmのビルドで、きっと物理的な暖もとれるはず！！

**Nuxt.ts、やっていくぞ！！**

# お品書き
- [Nuxtをインストールしよう！](#nuxtをインストールしよう)
- [NuxtをTypeScriptに対応させよう（nuxt-property-decoratorを利用）](#typescriptにしてみよう)
- [Jestをセットアップしよう！](#jestをセットアップしよう)

# Nuxtとは

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273517/bc6e1305-bff3-c92e-c867-aa4532f30dcf.png)
Source : [Nuxt.js - ユニバーサル Vue.js アプリケーション](https://ja.nuxtjs.org/)

Vue.jsにVue Router、VuexなどがバンドルされているJavaScriptのフレームワーク。
サーバーサイドレンダリングをするアプリケーションを簡単に作れることでよく話題になるけど、設定ひとつで静的サイト、Single Page Applicationとしてもビルドできるスグレモノ。

## Nuxtの好きなところ
### Vue Routerのルーティングに手間かからなさすぎ
プロジェクトルートに`pages`というディレクトリを作って、その中にComponentを突っ込んであげるだけでルーティングされちゃう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273517/b42f3727-338e-57ef-e20e-5891874457ae.png)

全体を通して使うテンプレート的なものは`layouts/default.vue`に作れます。

[ビュー - NuxtJS](https://ja.nuxtjs.org/guide/views)

### ホットリロード便利すぎ
エディタでソースを変更すると何もせずともブラウザに反映されます。

### TypeScriptもしっかりサポート
ギリ使えるとかじゃない。
`nuxt-property-decorator`もあるし、 そもそも`@nuxt/typescript-build`っていうパッケージがある。

最高。

# Nuxtをインストールしよう！
TypeScriptを使うにしろ、まずはNuxtをインストールしないことには始まらない。
Nuxtをインストールするには`npm`が実行できる環境、すなわちNode.jsが必要だ。

おっさんはDockerを使って楽しているのでNode.jsのセットアップは省きます。~~知らないし。~~

以下、[インストール - NuxtJS](https://ja.nuxtjs.org/guide/installation)の「スクラッチから始める」に沿って、NuxtをTypeScriptではじめて行きますよー

## package.jsonの作成
`package.json`はnpmの設定ファイル。
npmコマンドはNodeに同梱されていて、Nodeのパッケージマネージャなのです。

どうビルドするのかとか、必要なパッケージなんかを記す。
早速ファイルを追加して、nuxtの起動コマンドを書こう。

```json
{
  "name": "my-app",
  "scripts": {
    "dev": "nuxt"
  }
}
```

ほいっと。
`name`はなんでもいいです。けど、npm的には小文字ケバブケースがいいみたい。

### Dockerでやるならホストを指定しよう
デフォルトが`localhost:3000`になってしまって、Docker内にうまくマッピングされない。
ホストを`0.0.0.0`に指定して解決しよう。

```json
{
    "name": "how-to-setup-nuxt",
    "scripts": {
        "dev": "HOST=0.0.0.0 nuxt"
    }
}
```

ちなみに、ポート番号も指定したくば、`PORT=3939`みたいな感じで追加すればできる。

[コマンド - NuxtJS](https://ja.nuxtjs.org/guide/commands/#codefund_ad)

## Nuxtを追加
`nuxt`パッケージをプロジェクトに追加しよう。

```bash
npm install --save nuxt
```

## `pages/index.vue`を作成
デフォルトのページとして表示される`pages/index.vue`を作って試しにNuxtを起動してみよう！

```vue:pages/index.vue
<template>
    <h1>Hello, Nuxt!</h1>
</template>
```

## Nuxtを開発モードで起動
Nuxtを動かそう！！

```bash
npm run dev
```

`localhost:3000`へアクセーーーーーース

Hello world!できたらよしです。

# TypeScriptにしてみよう！！

## TypeScriptとは？
Microsoftが開発した**JavaScriptに静的型付けを加えたようなメタ言語**。
JavaScriptと相互互換があるらしい。

構文のスタイルはKotlinとかそのへんのモダン言語のような雰囲気がある。

## TypeScriptに対応させる
じゃあ続いてTypeScriptに対応させちゃおっか。

[Setup | Nuxt TypeScript](https://typescript.nuxtjs.org/guide/setup.html) に従います。うー、英語！

## インストール

`@nuxt/typescript-build`と`@nuxt/typescript-runtime`、`nuxt-property-decorator`をインストールしましょう。

```bash
npm install --save-dev @nuxt/typescript-build
npm install --save @nuxt/typescript-runtime

npm install --save nuxt-property-decorator
```

`@nuxt/typescript-build`はNuxtをTypeScriptでコンパイルさせるために、`@nuxt/typescript-runtime`はサーバーとしてTypeScriptを含んだNuxtを稼働させるのに必要なようです。

### nuxt-property-decoratorとは？
VueのComponentとしてや、Nuxtのheader要素としてメソッドを割り付けるとき、デコレータを使って簡単にできるようになるというもの。

見た目もクラスらしくスッキリしますよ！

## 設定ファイルの追加

`nuxt.config.js`と`tsconfig.json`を作成します。
ページに書いてある内容コピペです！

```js:nuxt.config.js
export default {
  buildModules: ['@nuxt/typescript-build']
}
```

`tsconfig.json`は`nuxt-property-decorator`でデコレータを使うので`"experimentalDecorators": true`を追加します。これを追加することでTypeScriptのコンパイラがデコレータを理解してくれます。

```json:tsconfig.json
{
  "compilerOptions": {
    "experimentalDecorators": true,
    "target": "ES2018",
    "module": "esnext",
    "moduleResolution": "node",
    "lib": [
      "esnext",
      "esnext.asynciterable",
      "dom"
    ],
    "esModuleInterop": true,
    "allowJs": true,
    "sourceMap": true,
    "strict": true,
    "noEmit": true,
    "baseUrl": ".",
    "paths": {
      "~/*": [
        "./*"
      ],
      "@/*": [
        "./*"
      ]
    },
    "types": [
      "@types/node",
      "@nuxt/types"
    ]
  },
  "exclude": [
    "node_modules"
  ]
}
```

## package.jsonの書き換え
`nuxt`を`nuxt-ts`に書き換えます。

```json
{
  "name": "my-app",
  "scripts": {
    "dev": "nuxt-ts"
  }
}
```

## `pages/index.vue`にTypeScriptを書き加えてみる
`<script>`タグに`lang=ts`を追加して、TypeScriptを使って.vueファイルにスクリプトを仕込みます。
さっき`nuxt-property-decorator`をインストールしたので、デコレータを利用して書くことができます！

単一コンポーネントファイルを作成して、TypeScriptを使ってComponentを書きましょう！

```vue
<template>
    <div>{{helloWorld}}</div>
</template>
<script lang="ts">
    import {Component, Vue} from "nuxt-property-decorator";

    @Component // <- 1
    export default class Index extends Vue /* <- 2 */{
        get helloWorld(): string { // <- 3
            return 'Hello world!';
        }
    }
</script>
```

### 1. `@Component`デコレータ
`@Component`デコレータは以下のクラスがVueのスクリプトであることを表します。
デコレータの次に定義されるクラスは必ず`Vue`クラスを継承する必要があります。

### 2. `Vue`クラス
これを継承しないとめっちゃエラーになります。

### 3. get helloWorld():string
プロパティを定義しています。これをVueテンプレートから参照して`Hello world!`します。

## サーバー起動！
サーバーをまた起動してみましょう！

```zsh
npm run dev
```

[http://localhost:3000](http://localhost:3000)にアクセスして、`Hello world!`って出たらうまく行ってます。お疲れさまです。

### うまく行かないときは...
- npmコマンドで必要なものをインストールした？
- `tsconfig.json`をちゃんと作った？
- `package.json`のnuxtをnuxt-tsに書き換えた？

# Jestをセットアップしよう！

## Jestとは？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273517/6bb27921-44af-31a3-89d5-f067daa46e10.png)

Source : [Jest · 🃏快適なJavaScriptのテスト](https://jestjs.io/ja/)

JestはFacebook社が提供しているJavaScriptのテストを行うフレームワーク。
Node.js上で動作するのでブラウザを立ち上げる必要もないし、非同期のテストもできる！

## Jestをインストールしよう
Jestと、JestでTypeScriptを動かすために必要なものと、型定義をインストールします。

```zsh
npm install --save-dev jest ts-jest @types/jest
```

## 設定ファイルを作ろう
`jest.config.js`を作ります。

```js:jest.config.js
module.exports = {
    transform: {
        '.*\\.(ts)$': '<rootDir>/node_modules/ts-jest',    // TypeScriptファイルをテストする場合
    },
    moduleFileExtensions: ['ts', 'js'], // テスト対象の拡張子を列挙する
    moduleNameMapper: {
        "^~/(.+)": "<rootDir>/$1",
        "^@/(.+)": "<rootDir>/$1"
    }
};
```

[tsconfig.json](#設定ファイルを追加する)でTypeScriptでルートディレクトリへエイリアスを設定していたので、ここでも同じく設定してあげます。

### この設定ではJavaScriptのテストがしづらい
TypeScriptのみを使う前提の超怠惰設定なのでJavaScriptのテストが満足にできません。
具体的にいうとES2015で登場した`import / export`構文などが使えないのでクソクソ不便です。
これはNode.jsがES2015に対応していないことに起因しています。`babel`を使えばES2015構文も満足に使えます。設定頑張れ！

が、TypeScriptのほうが安心感があるのでJavaScriptが必要だと感じるシーンは少ないでしょう。なぁ、そうだろ？

## tsconfig.jsonに型定義を追記する
Jestのテストメソッドの型定義をTypeScriptの設定ファイルに追加してあげます。

```json:tsconfig.json
{
    //....
    "types": [
      "@types/node",
      "@nuxt/types",
      "@types/jest" // <- 追加
    ]
}
```

これで開発環境などでJestの入力補完が効き始めるようになると思います。

## `package.json`にJest起動コマンドを追加
`scripts`のところに`"test": "jest"`を追加します。

現時点での`package.json`はだいたいこんな感じになると思います。

```json:package.json
{
  "name": "how-to-setup-nuxt",
  "scripts": {
    "dev": "HOST=0.0.0.0 nuxt",
    "test": "jest"
  },
  "dependencies": {
    "@nuxt/typescript-runtime": "^0.2.10",
    "nuxt": "^2.10.2",
    "nuxt-property-decorator": "^2.5.0"
  },
  "devDependencies": {
    "@nuxt/typescript-build": "^0.3.10",
    "@types/jest": "^24.0.23",
    "jest": "^24.9.0",
    "ts-jest": "^24.2.0"
  }
}
```

## テストケースを作る
試しに`true`をアサーションするテストケースを作ってみよう！
Jestでは`****.test.ts`、`****.spec.ts`がテストファイルとして自動的に認識されるようになっています。
今回は`tests/`ディレクトリを作って、その中に`example.test.ts`を作ってみます。

```typescript:tests/example.test.ts
test('example test', ():void=>{
    expect(true).toBeTruthy();
});
```

## Jestを動かしてみる
Jestを動かしてみましょう！
`npm run test`をターミナルへターーーーイプッ！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273517/49562393-4025-1ae3-384e-13041c77c998.png)

うごいあ。
ぼくはDocker for Mac環境下なので実行にかなり時間がかかっていますが、ホストマシンで動かすとなかなか早いんじゃないでしょうか。

# 環境整備はおわった！


楽もう！みかんとお正月、そして`Nuxt.ts`！！