例のEvil Martians流Rails + Docker環境でひとつ困っていたのが、ファイルを更新したときの自動ブラウザ再読み込みです。
今回は、Gulpなどの静的Webサイト開発などでよく使われるbrowser-syncをプロキシにしてオートリロードをやってみました。Chrome拡張をインストールせずにオートリロードできるのと、管理コンソールが使えるのが特徴です。
- リポジトリ: BrowserSync/browser-sync: Keep multiple browsers & devices in sync when building websites. http://browsersync.io
- ドキュメント: Browsersync Documentation
Dockerの外でbrowser-syncを動かす
主に以下の記事を参考にしました。
参考: Rails + BrowserSync でViewをシームレスに開発する - Qiita
環境
- macOS Catalina
- Docker for Desktop 2.2.0.5(43834)
- Docker 19.03.8
- Docker Compose 1.25.4
- yarn 1.22.4(Dockerの外、つまりmacOSのシェル環境にインストールしておくこと)
前提
以下のEvil Martians流Rails + Docker + docker-composeをベースとします。
自分は上に加えて以下のdipツールも併用していますのでdip
コマンドで記述します。それ以外の環境では適宜docker-compose exec app bash
やdocker-compose up
などに置き換えてください。
設定手順
下ごしらえ
- macOSのシェルで
yarn global add browser-sync
を実行し、browser-syncをインストールする - プロジェクトのルートに移動する
dip browser-sync init
を実行して初期化する(bs-config.jsが作成される)
コンフィグ1
- 作成されたbs-config.jsを以下のように変更する
// 変更前
// (略)
module.exports = {
"ui": {
"port": 3001
},
"files": false,
"watchEvents": [
"change"
],
// (略)
"server": false,
"proxy": false,
// (略)
// 変更後
// (略)
module.exports = {
"ui": {
"port": 3001
},
"files": ["app/**/*.css", "app/**/*.sass", "app/**/*.html", "app/**/*.erb", "app/**/*.js", "app/**/*.rb"] // ここを変更
"watchEvents": [
"change"
],
// (略)
"server": false,
"proxy": "localhost:3000",
// (略)
コンフィグ2
- package.jsonに以下を追加する
browser-sync start --config bs-config.js
を直接実行するなら不要
"scripts": {
"start": "browser-sync start --config bs-config.js"
}
自動リロードを動かす
- ターミナルウィンドウを2つ開く
- 1つ目のターミナルでプロジェクトに移動し、エディタを開いてからDockerを起動する
自分はdipを使っているのでdip rails s
で起動しています
- 2つ目のターミナルで
npm start
を実行してbrowser-syncを起動する
これでブラウザでhttp://localhost:3001
が自動的に開き、エディタでファイルを更新するとオートリロードされるようになります。
自分の場合、webpack-dev-serverによるWebpackerのリコンパイルはEvil Martians流docker-compose側でやってくれるので、元々手動でリロードすればWebpackerのコンパイルが走るようになっています。なのでbrowser-sync側でwebpack-dev-serverの設定は不要です。
ブラウザでhttp://localhost:3002
にアクセスすると以下のコンソールが開きます。
BASIC認証を使う場合
自分のRailsアプリでは管理用画面にBASIC認証(実際はダイジェスト認証)をかけているのですが、そのままではBASIC認証がプロキシを通りません。
この場合はbs-authというプラグインを用いてBASIC認証が通るようにします。
設定
- macOSシェルでbs-authを追加する
yarn global add bs-auth
- bs-config.jsを以下のように変更する
process.env
で環境変数からユーザー名とパスワードを読める- digestの場合もdigestなしのパスワードを環境変数から渡す
// 変更前
// (略)
"plugins": [],
// (略)
// 変更後
// (略)
"plugins": [
{
module: "bs-auth",
options: {
user: process.env.DIGEST_USERNAME,
pass: process.env.BASIC_PASSWORD
}
}
],
// (略)
改良したい点
- ターミナルを2つ開いて起動するのが面倒、しかもRailsが完全に起動してからbrowser-syncを起動する必要がある
- bs-authの認証時にパスワードがコンソールに表示されないようにしたい
- できればDockerの外でbrowser-syncを動かすのではなく、docker-composeのサービスのひとつとしてbrowser-syncを動かしたい
docker-composeのサービスでやれないか以下のように試してみましたが、まだうまくいかないので今後の課題とします。
- ファイル更新は検出されるがブラウザに更新が届かない
- サービスを
ctrl-c
で止められず、ターミナルを閉じないと終了しない😢
# Dockerfile
FROM node:12-slim
RUN npm -g install browser-sync bs-auth
WORKDIR /app
# docker-compose.yml(抜粋)
browsersync:
build:
context: .
dockerfile: ./.dockerdev/Dockerfile_bs
command: browser-sync start --config ./bs-config.js --tunnel
env_file: .env
volumes:
- .:/app:cached
ports:
- "3000:3000"
- "3001:3001"
最後に
browser-syncを使う場合、ブラウザに拡張をインストールせずにやれる点はありがたいです。今のところ管理コンソールでは特別な設定はしていません。
READMEによると、初回リクエスト時に<script async>...</script>
という非同期スクリプトタグを<body>
タグの直後に挿入することで実現しているとのことです。そのためHTMLに<body>
タグがないと動作しません。自分のアプリでHTMLソースを見ると、たしかに以下が挿入されています。
<body><script id="__bs_script__">//<![CDATA[
document.write("<script async src='/browser-sync/browser-sync-client.js?v=2.26.7'><\/script>".replace("HOST", location.hostname));
//]]></script>
とにかく、Docker上の開発環境(特にMac上)での定番のオートリロード方法が早く確立されて欲しいです。
おたより発掘
Docker上の開発環境(特にMac上)での定番のオートリロード方法が早く確立されて欲しい
この最後の一文が共感できるRails+Docker環境をbrowser-syncでオートリロードできるようにしてみた https://t.co/ULX3XW1S3a
— たなだい@エンジニアときどきバレエダンサー (@DaigoTanaka0714) April 17, 2020