【Vue3】Docker + Viteで Vue3 + TypeScriptの爆速開発環境を構築する【Mac】

# はじめに
「巷で話題になっている爆速ビルドツール"[Vite](https://ja.vitejs.dev/)"を使用して開発体験を向上させたい。」
「せっかく環境構築するなら、チームのみんなにも配れる方が嬉しい。」
という思いで、今回はDockerを使用してフロントエンドの開発環境を構築しました。

## 本記事を読む前に
本記事では、各ツールやライブラリの説明は行いません。
あくまで環境構築を目的とした記事となっております。
`dockerfile`や`docker-compose.yml`の記法・使用するコマンドは事前に学習しておくと、スムーズに進めることが出来ると思います。

# 目次
1. [事前準備/条件](#事前準備/条件)
1. [流れ](#流れ)
1. [導入](#導入)
    1. [dockerfileの作成](#dockerfileの作成)
    1. [docker-compose.ymlの作成](#docker-composeymlの作成)
    1. [dockerのイメージ作成](#dockerのイメージ作成)
    1. [create-vueでプロジェクトの作成](#create-vueでプロジェクトの作成)
    1. [yarn.lockの作成](#yarnlockの作成)
    1. [Viteの起動](#viteの起動)
1. [更新速度を見てみる](#更新速度を見てみる)
1. [まとめ](#まとめ)
1. [次回](#次回)

# 事前準備/条件
 - Macを使用していること
 - Dockerを導入していること

これだけです。
Dockerをインストールしていない方は[こちら](https://docs.docker.com/desktop/install/mac-install/)からインストールしてください。
Windowsだと一部のコマンドが動作しない場合がありますので、あくまで参考程度にご覧いただければと思います。

# 流れ
今回は[create-vue](https://github.com/vuejs/create-vue)を使用して、開発環境を構築していきます。
都度新しい開発環境を構築する度に`init`をするのは億劫なので、一度`create-vue`を使用した後は、作成されたフォルダをマウントするように設定していきます。

# 導入
### dockerfileの作成
 任意の作業ディレクトリを作成し、`Dockerfile`を作成します。

```Bash:zsh
$ mkdir docker_vue3
$ cd docker_vue3
$ touch Dockerfile
```

 ``` Dockerfile:Dockerfile
FROM node:16.13.2-alpine
WORKDIR /app
RUN apk update
 ```

これだけです。シンプルですね。

### docker-compose.ymlの作成
続いてdocker-compose.ymlファイルを作成します。

```docker-compose.yml
version: '3.9'
services:
  frontend:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: vite_fast
    working_dir: /app
    volumes:
      - .:/app
    ports:
      - "5173:5173"
```

### dockerのイメージ作成
`dockerfile`と`docker-compose.yml`の作成が出来たらdockerのイメージをビルドします。

``` Bash:zsh
$ docker compose build
[+] Building 2.3s (7/7) FINISHED
 => [internal] load build definition from dockerfile                                                                                                                                                               0.0s
 => => transferring dockerfile: 90B                                                                                                                                                                                0.0s
 => [internal] load .dockerignore                                                                                                                                                                                  0.0s
 => => transferring context: 2B                                                                                                                                                                                    0.0s
 => [internal] load metadata for docker.io/library/node:16.13.2-alpine                                                                                                                                             0.0s
 => [1/3] FROM docker.io/library/node:16.13.2-alpine                                                                                                                                                               0.0s
 => CACHED [2/3] WORKDIR /app                                                                                                                                                                                      0.0s
 => [3/3] RUN apk update                                                                                                                                                                                           2.2s
 => exporting to image                                                                                                                                                                                             0.0s
 => => exporting layers                                                                                                                                                                                            0.0s
 => => writing image sha256:efba8b2ffcc00fefaabd41237364fcd39846f774e47ab652e58e2d16b0dcbb52                                                                                                                       0.0s
 => => naming to docker.io/library/docker_vue3_frontend
```

### create-vueでプロジェクトの作成
`create-vue`を使用してプロジェクトを作成します。

```Bash:zsh
$ docker compose run frontend npm init vue@latest
[+] Running 1/0
 ⠿ Network docker_vue3_default  Created                                                                                                                                                                              0.0s
Need to install the following packages:
  create-vue@latest
Ok to proceed? (y) y

Vue.js - The Progressive JavaScript Framework
#プロジェクト名を入力します。
✔ Project name: … vite_fast
✔ Add TypeScript? … No / Yes
✔ Add JSX Support? … No / Yes
✔ Add Vue Router for Single Page Application development? … No / Yes
✔ Add Pinia for state management? … No / Yes
✔ Add Vitest for Unit Testing? … No / Yes
✔ Add Cypress for both Unit and End-to-End testing? … No / Yes
✔ Add ESLint for code quality? … No / Yes
✔ Add Prettier for code formatting? … No / Yes

Scaffolding project in /app/vite_fast...

Done. Now run:

  cd vite_fast
  npm install
  npm run lint
  npm run dev

npm notice
npm notice New minor version of npm available! 8.1.2 -> 8.18.0
npm notice Changelog: https://github.com/npm/cli/releases/tag/v8.18.0
npm notice Run npm install -g npm@8.18.0 to update!
npm notice
```

`frontend`は`docker-compose.yml`で指定したService名です。
`create-vue`を使用して、`npm init vue@latest`を実行すると、インタラクティブに導入するツールが選択できます。
今回は下記を選択しました。
  - `TypeScript`
  - `Vue Router`
  - `Pinia`
  - `ESLint`
  - `Prettier`

`Vitest`と`Cypress`のテストツールは作成した際のディレクトリ構成が煩雑になってしまうため（主に設定ファイル）今回は導入しませんでした。
JSXは使用する予定であれば導入してください。

### yarn.lockの作成
`npm`経由でプロジェクトを作成したので、`yarn.lock`ファイルがありません。
`npm`より速い`yarn`を使用したいので、`yarn.lock`ファイルを作成します。(yarnを使用したくない場合はこの先の`yarn`を`npm run`に置き換えればいいと思います。)

その前に一度`create-vue`でプロジェクトを作成したので、ビルド時にプロジェクトをコピーするように`dockerfile`を変更します。

```dockerfile:Dockerfile
FROM node:16.13.2-alpine

WORKDIR /app
# プロジェクトのコピー
COPY vite_fast/ ./
RUN apk update
```
また、ボリュームのマウント先も変更します。

```docker-compose.yml
version: '3.9'
services:
  frontend:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: vite_fast
    working_dir: /app
    volumes:
    # マウント先の変更
      - ./vite_fast:/app
    ports:
      - "5173:5173"
```

ビルドし直して、`yarn install`を実行します。

```Bash:zsh
 $ docker compose build
 $ docker compose run frontend yarn install
run frontend yarn install
yarn install v1.22.15
warning package.json: No license field
info No lockfile found.
warning vite_fast@0.0.0: No license field
[1/4] Resolving packages...
[2/4] Fetching packages...
~~~

~~~
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
warning Your current version of Yarn is out of date. The latest version is "1.22.19", while you're on "1.22.15".
info To upgrade, run the following command:
$ curl --compressed -o- -L https://yarnpkg.com/install.sh | bash
Done in 122.59s.
```

プロジェクト配下に`yarn.lock`ファイルが生成されれば完了です。

### 

### Viteの起動
これで`yarn`コマンドで`Vite`が起動出来るようになりましたので、`Vite`を起動します。

```dockerfile:Dockerfile
FROM node:16.13.2-alpine

WORKDIR /app
COPY vite_fast/ ./
RUN apk update
# "yarn dev"は package.json内にscriptｓに記載されています。
# Viteを実行
CMD ["yarn", "dev"]
```

```Bash:zsh
$ docker compose build
$ docker compose up
[+] Running 1/0
 ⠿ Container vite_fast  Created                                                                                                                                                                                    0.0s
Attaching to vite_fast
vite_fast  | yarn run v1.22.15
vite_fast  | warning package.json: No license field
vite_fast  | $ vite
vite_fast  |
vite_fast  |   VITE v3.0.9  ready in 1600 ms
vite_fast  |
vite_fast  |   ➜  Local:   http://localhost:5173/
vite_fast  |   ➜  Network: use --host to expose
```

`http://localhost:5173` でホスティングできたようです。アクセスしてみましょう。

![スクリーンショット 2022-08-22 0.45.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730384/d3a5b722-f280-69fb-b94d-43001d231da9.png)

「`このページは動作していません`」と表示されました。
実行時ログをよく見ると`Network: use --host to expose`と表示されています。

これはデフォルトのホスト(コンテナ側)は`127.0.0.1`をリッスンするので、コンテナ内のローカルホストのみが公開されるためです。
起動時に意図せず外部アドレス（ホスト側）に公開することはセキュリティ上の問題になるので、Viteの初期設定ではホスト側からアクセスが出来ないようになっています。

`use --host`とあるので、そのように変更してみます。

```dockerfile:Dockerfile
FROM node:16.13.2-alpine

WORKDIR /app
COPY vite_fast/ ./
RUN apk update
# --hostを追加
CMD ["yarn", "dev", "--host"]
```

```Bash:zsh
$ docker compose build
$ docker compose up
[+] Running 1/1
 ⠿ Container vite_fast  Recreated                                                                                                                                                                                  0.1s
Attaching to vite_fast
vite_fast  | yarn run v1.22.15
vite_fast  | warning package.json: No license field
vite_fast  | $ vite --host
vite_fast  |
vite_fast  |   VITE v3.0.9  ready in 2059 ms
vite_fast  |
vite_fast  |   ➜  Local:   http://localhost:5173/
vite_fast  |   ➜  Network: http://172.28.0.2:5173/
```

今度は、Networkが`http://172.28.0.2:5173/`になりました。
接続確認してみましょう。

![スクリーンショット 2022-08-22 0.56.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730384/80a25745-b844-d5a6-d8db-db05f9d74a2c.png)

接続確認ができました。
これは`vite.config.ts`でも変更することができます。
やってみます。

```typescript:vite_fast/vite.config.ts
import { fileURLToPath, URL } from 'node:url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  },
  // 追記
  server: {
    // --hostと同義
    host: true,
    // 立ち上げる際のポートを変更できます。
    port: 5173
  }
})
```

```dockerfile:Dockerfile
FROM node:16.13.2-alpine

WORKDIR /app
COPY vite_fast/ ./
RUN apk update
# --hostを削除
CMD ["yarn", "dev"]
```

```Bash:zsh
$ docker compose build
$ docker compose up
[+] Running 1/1
 ⠿ Container vite_fast  0.1s
Attaching to vite_fast
vite_fast  | yarn run v1.22.15
vite_fast  | warning package.json: No license field
vite_fast  | $ vite
vite_fast  |
vite_fast  |   VITE v3.0.9  ready in 1934 ms
vite_fast  |
vite_fast  |   ➜  Local:   http://localhost:5173/
vite_fast  |   ➜  Network: http://172.28.0.2:5173/
```

起動確認してみます。
![スクリーンショット 2022-08-22 0.56.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730384/80a25745-b844-d5a6-d8db-db05f9d74a2c.png)

こちらでも問題なく起動確認が出来ました。

# 更新速度を見てみる
それではファイルを変更して、更新反映速度を見てみましょう。
![rec.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730384/0f0dc648-d90b-4e86-9b78-7c2add4e5c72.gif)


ほぼタイムラグなしで、瞬時に反映されました。これは爆速。


# まとめ
今後新規でプロジェクトを作成する際は、今回の作業フォルダをコピーして、`docker compose build`→ `docker compose up`をするだけで環境構築が出来るようになりました。

再利用可能なDocker構成は便利ですね。チーム開発でも個人開発でも関係なくさっと環境を作れるのは嬉しいです。

また、ViteをVue CLIの代わりに採用することで、ストレスなくフロント開発が出来そうです。

# 次回
今回はフロントエンドの環境構築で終わりましたが、次回はRailsをバックエンドのAPIとしてDocker環境を作成します。
フロントエンドとバックエンドのAPI通信の確立までを初期設定とした環境構築をしていきたいと思います。