Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

Rails+Docker環境をbrowser-syncでオートリロードできるようにしてみた

例のEvil Martians流Rails + Docker環境でひとつ困っていたのが、ファイルを更新したときの自動ブラウザ再読み込みです。

今回は、Gulpなどの静的Webサイト開発などでよく使われるbrowser-syncをプロキシにしてオートリロードをやってみました。Chrome拡張をインストールせずにオートリロードできるのと、管理コンソールが使えるのが特徴です。


同リポジトリより

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をベースとします。

Rails 6のDocker開発環境構築をEvil Martians流にやってみた

自分は上に加えて以下のdipツールも併用していますのでdipコマンドで記述します。それ以外の環境では適宜docker-compose exec app bashdocker-compose upなどに置き換えてください。

docker-composeを便利にするツール「dip」を使ってみた

設定手順

下ごしらえ

  • 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上)での定番のオートリロード方法が早く確立されて欲しいです。

おたより発掘


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。