Docker + Vue CLIで簡単にVue.jsの環境構築

##概要
　dockerで簡単にVue CLIをインストールして、vueの開発環境を構築
　（※私はVagrant上にDocker環境を作ってそこで作業していますが、今回は割愛してます）

##ファイル構成
```
vue
 ├ src
 │  ├ app 　→ ここにvueのソースコード
 │  └ scripts
 │     └ startup.sh  → コンテナ起動時に実行したいスクリプト
 ├ Dockerfile
 └ docker-compose.yml
```

##Dockerfileの用意
まずはDockerfileを用意します。

```Dockerfile
FROM node:lts-alpine

WORKDIR /src                                                                                                                                                                                                

#イメージ作成時に実行 Vue CLIをインストール
RUN npm install -g @vue/cli

#shファイルをコンテナにコピー
#今回はコンテナ起動時に実行したいものをstartup.shにまとめて記述（後述）
COPY ./src/scripts/startup.sh /scripts/startup.sh

#shファイルの権限変更
RUN chmod +x /scripts/*

#コンテナ起動のタイミングで実行 これは最初コメントアウトしておきます
#ENTRYPOINT ["/scripts/startup.sh"]

WORKDIR /src/app
```

### `FORM`
ベースのイメージ名を指定
今回は軽量のalpineを使用


### `WORKDIR`
コンテナ内の作業ディレクトリを指定。

### `RUN`
イメージをビルドするときに実行するコマンドを指定。
ここでは、Vue CLIをインストールしています。

### `COPY`
イメージにファイルを追加。
今回は、コンテナの起動時に実行したいスクリプトを1つのファイルにまとめておきたいので、
このファイルをコンテナにコピーしておきます。（スクリプトの中身については後述）

### `ENTRYPOINT`
コンテナの起動時（docker startやdocker runなど）に実行。
ここでは、上でコピーしたstartup.shを実行するように指定しています。


##コンテナ起動時に実行したいスクリプトの用意
先ほどDockerfileで指定したstartup.shを用意します。
コンテナ起動と同時にアプリも起動させたいので、コンテナ内でnpm installとnpm run serveが実行されるようにしています。

```src/scripts/startup.sh
#!/bin/sh
                                                                                                                                                                                                            
#package.jsonに記載されたパッケージをインストール
echo "npm install..."
npm install

#アプリ起動
echo "npm run serve"
npm run serve
```

##docker-compose.ymlの用意

```:docker-compose.yml
version: '3' 
services:                                                                                                                                                                                                   
  app:
   build: .
   ports:
    - 8080:80
   volumes:
    - ./src:/src
    - vue-cli-node-modules-volume:/src/app/node_modules
volumes:
  vue-cli-node-modules-volume:
```

### `version` 
　docker-composeの書式のバージョン。
   
### `services`
 サービス（コンテナのことと考えて良い）の定義を記述。
上の例では、appというサービス名で各種の設定をしています。

   * build

    Dockerfileのパスを指定。以下の様な指定方法もあります。

```
build:
 context:　Dockerfileのパス
 dockerfile: ファイル名
 ```

* ports
  ポートの指定。上の例では、Dockerホストの8080番をコンテナの80番に指定してます。

* volumes
  ``./src:/src``
　ホストのsrcディレクトリ以下をコンテナ内のsrcと同期。

　  ``vue-cli-node-modules-volume:/src/app/node_modules``
　　　ホスト側にコピーしたくないものを指定。node_modulesを入れるボリュームvue-cli-node-modules-volumeを指定し、node_modulesを同期から外しています。ボリュームについては、下で説明します。

### `volumes`
　コンテナが利用するボリュームを指定。今回はvue-cli-node-modules-volumeという名前にしています。ボリュームが存在しない場合は作成されるので、先に作成しておく必要はないです。

これで、準備は終わりです！！


##イメージの構築
最初に作ったDockerfileを元に、以下のコマンドでイメージを構築していきます。

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

念のため、imageが出来ているか確認しておきます。

```:ターミナル 
 $ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
vue_app             latest              784a3fd0ee9a        1 hours ago         433MB
```

##プロジェクト作成
以下のコマンドで、プロジェクトを作成します。サービス名appを指定。

```:ターミナル 
$ docker-compose run app vue create .
```

カレントディレクトリにプロジェクトを作成します。
Dockerfileの最後で`WORKDIR /src/app`と記述していたため、appディレクトリの中で作成されます。
（※色々聞かれますが、適宜選択してプロジェクトを作成してください）
無事に完了したら、ホストのvue/src/app内にアプリケーションが作成されているはずです。


##Dockerfile修正
コンテナを起動する前に、先ほどコメントアウトしていた箇所を外します。

```:Dockerfile
#コンテナ起動のタイミングで実行 これは最初コメントアウトしておきます
ENTRYPOINT ["/scripts/startup.sh"]
```

なぜ最初にコメントアウトしておくかというと、上でイメージを構築したときにはプロジェクトファイルが存在しないので、npm run serveなど実行しても意味がないためです。


##イメージの再構築
Dockerfileを修正したので、再構築しておきます。

```:ターミナル 
$ docker-composer build
```
これで、コンテナを起動した際にnpm installとnpm run serveが実行されるようになります。


##コンテナ起動
いよいよコンテナを起動します。-dオプションを付けることで、バックグラウンドで起動することができます。
オプションを外した場合、startup.shでechoしておいた`npm install...`や`npm run serve`が出力されてスクリプトが実行されているのを確認することができます。

```:ターミナル 
$ docker-compose up -d
```
ちなみに、以下のコマンドでコンテナ内に入ってみると、src以下のプロジェクトとstartup.shが同期されていることを確認することができます。

```:ターミナル 
$ docker-compose exec app 
```


### ブラウザで確認
docker-composer.ymlで指定したホスト側のポート（今回は8080）を入力してブラウザで確認すると、無事に以下のページが表示されるはずです。

![FireShot Capture 133 - app - 192.168.33.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/953754/8c0107d2-00d7-feae-9c72-e24a09aa9919.png)