Docker環境でvite+Nginxを動作させた時に詰まったポイント


TL;DR

vite + Nginxの構成をDokcer上で作成したいと思ったんですが、
一部詰まったポイントがあったので備忘録的に残しておきます。

なおライブラリのソースを直接弄ってごまかしているので、
基本的には公式のアップデートを待つのが吉かと思います。

viteについて

公式リポジトリ
viteはVue.jsの作者のEvan You氏が作成したビルドツールです。

Vue-cliでは諸々のバンドルツールをいれてましたがviteは不要なため、
devサーバーが高速に動作するのが一番の特徴かと思います。
マジで早い。

ちなみにビルドにはRollupを利用しているようです。

Docker環境で動かす

さて今回の本題に入りたいと思います。
Dokcer環境上にNginx+viteの環境を構築するために準備をします。
HOST(8080) => Nginx(80) => vite(3000)で通信をする想定です。

※Docker環境の構築そのものの説明は割愛します。

最終的なディレクトリ構成は以下のような形になります。

.
├── config
│   └── nginx
│       └── dev.conf
├── docker-compose.yml
├── index.html
├── logs
│   └── nginx
│       └── error.log
├── package.json
├── public
│   └── favicon.ico
├── src
│   ├── App.vue
│   ├── assets
│   │   └── logo.png
│   ├── components
│   │   └── HelloWorld.vue
│   ├── index.css
│   └── main.js
└── yarn.lock

現時点でのdocker-compose.ymlとNginxの設定ファイルは以下のような状態。

docker-compose.yml
version: "3"
services:
  vite:
    image: node:12.6.0
    container_name: vite
    working_dir: /var/local/app
    volumes:
      - .:/var/local/app:cached
    environment:
      - HOST=0.0.0.0
    command: /bin/sh -c "yarn cache clean && yarn install && yarn dev"

  proxy_nginx_vite:
    image: nginx:1.19.1
    volumes:
      - ./config/nginx/dev.conf:/etc/nginx/nginx.conf:cached
      - ./logs/nginx:/var/log/nginx:cached
    container_name: proxy_nginx_vite
    ports:
      - 8080:80
    depends_on:
      - vite
dev.conf
error_log       /var/log/nginx/error.log;

events{
}

http {
    server {
        listen 80;
        server_name localhost;

        location / {
            proxy_pass http://vite:3000/;
            proxy_intercept_errors on;
        }
    }
}

Docker環境の立ち上げ(1回目)

環境の準備をしたら以下のコマンドで立ち上げます。

docker-compose -f docker-compose.yml up --build

この時点では以下のエラーが出て表示されません。

NginxでWebSocketを使うには設定が必要だったので早々にNginxのconfファイルを修正します。

NginxでWebsocket通信を使うための修正

以下のあたりを参考に修正します。

NginxのリバースプロキシでWebソケットを通す際の設定

以下をconfファイルに追加します。

dev.conf
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

~~中略~~

proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade; 
proxy_set_header Connection $connection_upgrade;

この時点のNginxのconfファイル

dev.conf
error_log       /var/log/nginx/error.log;

events{
}

http {
    map $http_upgrade $connection_upgrade {
        default upgrade;
        ''      close;
    }

    server {
        listen 80;
        server_name localhost;

        location / {
            proxy_pass http://vite:3000/;
            proxy_intercept_errors on;
            proxy_http_version 1.1;
            proxy_set_header Host $host;
            proxy_set_header Upgrade $http_upgrade; 
            proxy_set_header Connection $connection_upgrade;
        }
    }
}

Docker環境の立ち上げ(2回目)

ここでdokcerを立ち上げ直します。

docker-compose -f docker-compose.yml up --build

先程のエラーは解消されて表示自体はされますが、繰り返しページのリフレッシュが走ります。
consoleを見ると以下のエラーが出ています。

先程のエラーとは異なっているようですがこれもWebSocket関連のようです。

viteのWebSocket通信のPORTの向き先を変更する

hostからはポート8080でDockerコンテナに接続しているんですが、
vite自体はポート3000で起動しているもんだから、
WebSocket通信でlocalhost:3000を見に行こうとしてつながらない=>繰り返しリフレッシュされている模様。

↓此処から先は自己責任↓

ライブラリ内のファイルを直接弄って編集

node_modules/vite/dist/client/client.ts内のファイルの33行目でWebsocket通信に使うURLを生成しているんですが、ここで引いてきているPORTが3000のままのためおきているようです。

viteのリポジトリにもISSUEが立っていたので参考に無理やりつながるようにしてみます。

WebSocket connection can not work inside Docker container
公式リポジトリのコードの該当箇所

// dockerコンテナ内でコマンドを実行
docker exec -it vite bash

// vimがなければインストール
apt-get update
apt-get install vim

// 以下のファイルを編集
vi node_modules/vite/dist/client/client.js

// before
const socketUrl = `${socketProtocol}://${location.hostname}:${__PORT__}`;
↓↓↓以下に変更↓↓↓
// after
// HOSTから見に行く先のPORT番号を具体的に指定
const socketUrl = `${socketProtocol}://${location.hostname}:8080`;

Docker環境の立ち上げ(3回目)

もっかい再起動

docker-compose -f docker-compose.yml up --build

リフレッシュもせずに無事動きました。

今後どうなっていきそうか

正直この状態で動かすのは好ましくありません。

ただ先程のISSUEにぶら下がっているPR見てみると
WebSocket用のconfigが追加されそうな気配を感じます。

feat(dev): add config for websocket connection

どう反映されるかわかりませんが、以下はこんな感じになりそうかな?という想像です。

vite.config.js
module.exports = {
  socketPort: 8080
}

結論

とりあえず動作するとこまでは行きましたが、
さすがにこのままつかっていくのは厳しいなとは思っています。
今回のような構成にしなければこういう問題は発生しないんですけどね、、、。

まだ絶賛開発中なところもあるので、色々と手間をかける部分は必要そうです。

趣味や個人で使う分にはローカルでのサーバー起動も早くすごく快適ですので、
Vue使っている人は是非試してみてください!

参考