webpackをsimpackerで導入する
きっかけ
Railsでwebpackといえば、Webpacker。Rails ガイドもある。
webpackerで一番うれしいのって、ファイル名などのエントリポイントを指定して、読み込むバンドルを指定するためのhelper。これがあるからwepacker使ってました。
<%= javascript_pack_tag 'application' %>
<%= stylesheet_pack_tag 'application' %>
参考 https://github.com/rails/webpacker#usage
一方、webpackerを使って、こまるのが、webpacker独自のDSL。ailsのenvironmentsと近いような感じで書けそう・・・なんだけど、そういうことはない。
webpackと近いDSL。
ただ、微妙に異なる。
この違いにより、webpackならすぐ解決できそうなことでも、webpackerでは情報がすくなくて解決まで時間がかかることが多い。
webpackを使いつつ、読み込むバンドルを指定できるヘルパーがあればと思っていたところ、素晴らしいgemがありました。
Simpacker です。
エントリポイントとバンドルの対応のmanifest.jsonを元に、webpackのバンドルを読み込むことができます。
{
"application.js": "/packs/application.js",
}
manifest.jsonの出力は、
WebpackAssetsManifestがやってくれます。
Simpackerを知ったのは、下記のblogです。webpackerから素のwebpackに戻したという話で、内容に共感できました。
上記記事内からcookpadのブログ Simpacker: Rails と webpack をもっとシンプルにインテグレーションしたいのですを読んだとき、Simpackerの話が出て、まさしく欲しいやつと思って早速ためしました。
manifest.json という、ハッシュ値が付与されたファイル名ともとのファイル名のマッピング情報を持つファイルをもとに、JS や CSS を読み込むタグを生成するヘルパーを提供します。
Simpacker は webpack 側の設定を一切管理せず、出力する manifest.json のパスしか知らないというところです。
うむ、とても疎な感じ。
早速Simpackerを試そう
SimpackerをRailsに導入するところから、webpack-dev-serverによるライブリローディングの開発環境をつくってみました。
なお、webpack-dev-serverはDockerコンテナで動かす場合と、localで動かす場合2つ試しました。
開発環境をコードに落とすためには、Dockerコンテナで書くのがいいのですが、javascriptが大きくなるとコンテナとローカル間のファイル同期が激遅となることもあるので、localで動かす場合も試しました。
参考にしたのは以下のブランチのコードです。
exampleから下記の2つを参考にしました。
できたのは以下のブランチです。
解説
webpackの導入
適当なRailsのレポジトリがあるとして以下の手順でwebpackを導入します
package.jsonを作成
yarn init
webpackをインストールします。 webpackの Installationを参照。
上記documentはnpmで説明されているけど、yarnで入れます。(ただの好みです。)
yarn add --dev webpack webpack-cli
複数エンドポイントを使うためにglob入れます。
yarn add --dev glob
webpack.config.jsを書きます。と、いってもSimpackerのwebpack.config.jsと同じです。
重要なのは、下記。
Simpackerのための 設定です
Simpackerは、下記の通り、manifest.jsonを使っています。
Simpacker provides only minimal features that lookup the manifest.json output by webpack and a create script tag through javascript_pack_tag.
helperからwebpackのエントリーポイントとなるjavascriptを参照できるようなmanifest.jsonを出力するための設定です。
plugins: [
new WebpackAssetsManifest({
publicPath: true,
output: "manifest.json",
}),
],
Simpacker gemの導入
これは、Gemfileに以下の記述を追加して bundle install
するだけです。
gem 'simpacker'
Rails側からwebpackでバンドルされたエントリーポイントを参照する。
あとは、 app/javascript/packs
にentryポイントのjavascriptを配置し、 npx webpack
を実行して、以下のヘルパーで呼び出せばOKです。(htmlでなく、slimで書いていますが、もちろんhtml.erbでもOKです。)
= javascript_pack_tag 'vendor'
= javascript_pack_tag 'posts'
div#app
javascriptは以下の感じ
webpack-dev-serverを使う。
webpack-dev-serverをローカルで動かす場合と、dockerコンテナで動かす場合の2パターンを説明します。
webpack-dev-serverをローカルで動かす
webpack-dev-serverを入れて、webpack.config.jsを修正して、最後 webpack serveを実行します。
コードの修正点はこちらを参照して下さい。
webpack-dev-server入れる
yarnで開発環境だけに入れる。それだけ。
yarn add --dev webpack-dev-server
webpack.config.jsを修正する
publicPath
を修正します。開発の場合は //localhost:8081/packs/
(dev-serverが動いているhost)を指定します。
output: {
path: path.resolve(__dirname, "public/packs"),
publicPath: isProd ? "/packs/" : "//localhost:8081/packs/",
filename: isProd ? "[name]-[hash].js" : "[name].js",
},
次に、devServerの設定です。 https://github.com/hokaccha/simpacker/blob/9743aa83a5d5bc25b09a93abafd94e041a9722a8/example/webpack-dev-server/webpack.config.js#L21-L29 こちらと同じです。
dev-serverを動かす
以下のコマンドで実行します。。
npx webpack serve
これで完了です。コードが変更されると同時にjavascriptが更新されることを確認してください。
webpack-dev-serverをdockerコンテナで動かす
コンテナで動かす事もできます。
コードは以下の通り。
まずdev-serverが動くコンテナを作ります。
FROM node:16-slim
RUN mkdir /myapp
WORKDIR /myapp
COPY package.json yarn.lock /myapp/
RUN yarn
COPY webpack.config.js /myapp/
COPY app/javascript /myapp/app/javascript
RUN mkdir /public
RUN mkdir /public/packs
Dockerfileで重要なのは、下記の4ファイルです。
RUN mkdir /public/packs
-
COPY package.json yarn.lock /myapp/
*COPY webpack.config.js /myapp/
RUN mkdir /public/packs
使用する最低限のファイルをコピー or 同期しています。
次に webpack.config.js を修正します。
host: "0.0.0.0"
が大きな違いです。
https://webpack.js.org/configuration/dev-server/#devserverhost こちらにあるように 外部からのアクセスを許可するための記述です。
devServer: {
contentBase: path.resolve(__dirname, "public"),
publicPath: "/packs/",
host: "0.0.0.0",
port: 8081,
違いはこれだけ。あとは、 docker-compose の commandに起動コマンドを追加します。
コンテナ起動設定が書かれているdocker-compose.yamlは以下のとおり。
webpack-dev-server:
build:
context: .
dockerfile: ./docker/webpack-dev-server.docker
command: npm run serve
volumes:
- ./public/packs:/myapp/public/packs
- ./app/javascript:/myapp/app/javascript
ports:
- "8081:8081"
depends_on:
- web
あとは以下のコマンドを実行して、 localhost:3000
にアクセスしてください。
アクセス後、 app/javascript/
配下のファイルを変更したときに上記 localhost:3000 の記述が自動的に再度読み込みされることを確認してください。
docker-compose build
docker-compose up
Discussion