dockerでnuxt.jsの環境を作ってみる

## 概要
nuxt.jsの学習用にdockerコンテナを作ってみる。

## 前提条件

- macOS
- Docker Toolbox ( Docker for mac )

## ファイル構成
作成するファイルは、下記となります。

```:ファイル構成
nuxtjs-sample
　├ docker
　│　└ nuxt.js
　│　   ├ src
　│　   │  └ app       <- アプリケーション(nuxt.js)
　│　   └ Dockerfile   <- nuxt.jsのdockerイメージ
　├ .gitignore
　└ docker-compose.yml
```

## ソースコードのフォルダ作成
アプリケーションのコードが生成されるフォルダを用意します。

```bash:コンソール
$ mkdir -p docker/nuxt.js/src/app
```

## .gitignore作成
今回は必要最低限でとりあえず作成します。

```:.gitignore
.DS_Store
.idea

# direnv config file.
.envrc
```

## Dockerfile作成
下記の内容で作成します。

```dockerfile:docker/nuxt.js/Dockerfile
FROM node:11.1

# locale & timezone (Asia/Tokyo)
# https://github.com/moby/moby/issues/12084
ENV LANG C.UTF-8
ENV TZ Asia/Tokyo

# system update
RUN apt-get update && \
    apt-get install -y vim less

WORKDIR /root

# install yarn command.
# - https://yarnpkg.com/lang/ja/docs/install/#alternatives-stable
# - https://github.com/yarnpkg/yarn/releases
ARG CMD_YARN_VERSION=1.13.0
RUN npm install --global yarn@$CMD_YARN_VERSION && \
    chmod +x /usr/local/bin/yarn

# install direnv command.
# - https://github.com/direnv/direnv
# - https://github.com/direnv/direnv/releases
ARG DEV_DIRENV_VERSION=v2.19.0
RUN wget -O direnv https://github.com/direnv/direnv/releases/download/$DEV_DIRENV_VERSION/direnv.linux-amd64 && \
    mv direnv /usr/local/bin/ && \
    chmod +x /usr/local/bin/direnv && \
    echo 'eval "$(direnv hook bash)"' >> ~/.bashrc

# install vue-cli
RUN npm install --global @vue/cli @vue/cli-init

# copy application code from host.
ADD src /src
WORKDIR /src/app

# ↓ここから下は後で、コメントアウトを解除します
## install packages.
#RUN yarn install

#EXPOSE 3000
#CMD ["yarn", "run", "dev"]
```

## docker-compose.yml作成
下記の内容で作成します。

```yaml:docker-compose.yml
version: '3'
services:
  nuxt.js:
    container_name: nuxt.js
    build:
      context: ./docker/nuxt.js
      dockerfile: Dockerfile
    ports:
      - 3000:3000
    volumes:
      - ./docker/nuxt.js/src:/src:cached
      # exclude volumes
      - /src/app/node_modules
    tty: true
    stdin_open: true
    # Hot Module Replacement (HMR) is enable for virtual box.
    environment:
      - CHOKIDAR_USEPOLLING=true
```

## dockerイメージ構築
下記コマンドにて、dockerイメージを構築します。

```bash:ターミナル
$ docker-compose build
```

## アプリケーション作成 （vue-cli)
下記コマンドにてnuxt.jsのアプリケーションを構築する。

```bash:ターミナル
$ docker-compose run nuxt.js vue init nuxt-community/starter-template .
```
※「`docker/nuxt.js/src/app`」フォルダにアプリケーションが生成される。

## パッケージのインストール
下記コマンドにて、package.jsonに記載されているパッケージをインストールする。

```bash:ターミナル
$ docker-compose run nuxt.js yarn install
```
※「`docker/nuxt.js/src/app/node_modules`」フォルダにパッケージがインストールされる。

## package.json修正
下記のように「`HOST=0.0.0.0 PORT=3000 nuxt`」と修正する

```json:docker/nuxt.js/src/app/package.json
{
  ~ 省略 ~
  "scripts": {
    "dev": "HOST=0.0.0.0 PORT=3000 nuxt",                      <- ここを修正する
    "build": "nuxt build",
    "start": "nuxt start",
    "generate": "nuxt generate",
    "lint": "eslint --ext .js,.vue --ignore-path .gitignore .",
    "precommit": "npm run lint"
  },
  ~ 省略 ~
}
```

## Dockefile修正
コメントアウトしてある部分を解除する。

```dockerfile:docker/nuxt.js/Dockerfile
~省略~

# install packages.  <- ここから下の処理
RUN yarn install

EXPOSE 3000
CMD ["yarn", "run", "dev"]
```

## dockerイメージ再構築
Dockerfileを変更したので、dockerイメージを再構築します。

```bash:ターミナル
$ docker-compose build
```

## サーバ起動
下記コマンドにてdockerコンテナを起動する

```bash:コンソール
# コンテナ起動
$ docker-compose up -d

# サーバの状態確認
$ docker-compose ps

# サーバのログ確認
$ docker-compose logs -f --tail 10 nuxt.js

nuxt.js    | ��� Waiting for file changes                                            19:06:02
nuxt.js    | 
nuxt.js    |    ��������������������������������������������������
nuxt.js    |    ���                                             ���
nuxt.js    |    ���   Nuxt.js v2.3.4                            ���
nuxt.js    |    ���   Running in development mode (universal)   ���
nuxt.js    |    ���   Memory usage: 136 MB (RSS: 217 MB)        ���
nuxt.js    |    ���                                             ���
nuxt.js    |    ���   Listening on: http://192.168.16.2:3000    ���
nuxt.js    |    ���                                             ���
nuxt.js    |    ��������������������������������������������������

# ログ確認を終わりたい場合は、「 crl + c 」で終了する
```

## 動作確認
下記コマンドにてブラウザを起動し、閲覧できるか確認する

```bash:ターミナル
$ open http://192.168.99.100:3000/
```
![test.png](https://qiita-image-store.s3.amazonaws.com/0/142279/c5261118-1cc8-34fd-8307-ffc9c348b3a5.png)

※ `192.168.99.100` の部分は、dockerの環境によって異なります
※ サーバが起動するまでに少し時間がかかる場合がある。

## 開発時の利用について (ローカル環境)
gihubからクローンして開発で使う場合は、`yarn install`の手動実行が必要です。
※ ホストのフォルダをマウントしなければインストールは不要

```bash:ターミナル
# ワークス−ペース作成 (任意フォルダ)
$ mkdir -p ~/workspace/nuxt.js-sample/
$ cd ~/workspace/nuxt.js-sample/

# コード配置
$ git clone git@github.com:reflet/nuxt.js-sample.git .

# dockerイメージを構築する
$ docker-compose build

# パッケージをインストールする (ホストのフォルダをマウントする場合、初回必要)
$ docker-compose run nuxt.js yarn install

# コンテナを起動する
$ docker-compose up -d

# サーバのログ確認
$ docker-compose logs -f --tail 10 nuxt.js
```

## パッケージ導入 (axios-module)
`node_modules`にコードが追加され、パッケージ管理(`package.json`)にも追加される。

```bash:ターミナル
$ docker-compose exec nuxt.js yarn add @nuxtjs/axios
```
インストール後、`nuxt.config.js`に下記を追加。

```js:docker/nuxt.js/src/app/nuxt.config.js
{
  // ~省略~
  /*
   ** Customize the progress bar color
   */
  loading: { color: '#3B8070' },

+ /*
+ ** modules
+ */
+ modules: [
+   '@nuxtjs/axios'
+ ],
+ axios: {
+  
+ },

  /*
  ** Build configuration
  */
  build: {
    // ~省略~
  }
}
```

qiita APIを使ってデータを取得してみるため、下記ページを追加する。

```vue:docker/nuxt.js/src/app/pages/qiita/index.vue
<template>
  <section class="container">
    <div>
      <h1 class="title">
        Qiita APIへアクセス
      </h1>
      <p>Qiita APIから、Nuxt.jsのタグが付けられた投稿を取得してみる</p>
    </div>
  </section>
</template>

<script>
  export default {
    name: "qiita-index",
    async mounted() {
      console.log(JSON.stringify(await
        this.$axios.$get('https://qiita.com/api/v2/items?query=tag:nuxt.js'), true, '   ')
      )
    }
  }
</script>
```
chromeの開発ツールのコンソールで取得結果を確認してみる。

```bash:ターミナル
$ open http://192.168.99.100:3000/qiita/
```
![qiita-api.png](https://qiita-image-store.s3.amazonaws.com/0/142279/a28feb2a-9107-74c6-877e-f70137b98b21.png)

以上

## まとめ
とりあえず、サーバを起動できるようになったので、学習を進める環境ができました。
しかし、やはりホスト側のフォルダをdocker-composeでマウントするとディスクI/Oがネックでパフォーマンスが悪い。

私のPC（MacBook Air）だと、DockerToolboxよりDocker for macの方が修正箇所の反映が不思議と早いのが気になりますが、どちらにしてもパフォーマンスが悪く感じます。

マウントを解除して、シェルでファイルを修正してみたりするとスムーズなので、ディスクI/Oが足を引っ張っているのは間違いないようです・・・。

このマウントすると遅くなる件、継続しての課題です。

少しはましになる方法はあるでしょうが、設置がややこしくなるとせっかくお手軽に構築できるdockerのメリットがなくなるので、悩ましいところです。

## 参考サイト
- [[書籍] Nuxt.js ビギナーズガイド](https://nuxt-beginners-guide.elevenback.jp/)
- [Nuxt.js - Universal Vue.js Applications](https://nuxtjs.org/)
- [laradock と nuxt で開発環境構築](https://qiita.com/aoarashi/items/535feeca48d15516d450)
- [babelのwatch機能がdockerコンテナ上で動かない](https://qiita.com/nishiurahiroki/items/52ff8cf144049b7834b0)
- [Troubleshooting - Create React App](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-start-doesn-t-detect-changes)
- [yarnをインストールする](https://qiita.com/suisui654/items/1b89446e03991c7c2c3d)
- [Watch and WatchOptions](https://webpack.js.org/configuration/watch/)
- [docker-composeを爆速にする](https://qiita.com/shotat/items/57d049793605ffc20135)
- [DockerでVolumeをマウントするとき一部を除外する方法](https://qiita.com/suin/items/e53eee56da23d476addc)
- [host and port - Nuxt.js](https://nuxtjs.org/faq/host-port/)