🐇

webpackをsimpackerで導入する

2021/07/24に公開

きっかけ

Railsでwebpackといえば、WebpackerRails ガイドもある。

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に戻したという話で、内容に共感できました。

https://dev.icare.jpn.com/dev_cat/bye_bye_webpacker/

上記記事内から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つを参考にしました。
https://github.com/hokaccha/simpacker/tree/master/example/multiple-entry-points
https://github.com/hokaccha/simpacker/tree/master/example/webpack-dev-server

できたのは以下のブランチです。

https://github.com/junara/webpack_simpack/tree/docker

解説

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は以下の感じ

https://github.com/hokaccha/simpacker/blob/master/example/multiple-entry-points/app/javascript/packs/posts.js

webpack-dev-serverを使う。

webpack-dev-serverをローカルで動かす場合と、dockerコンテナで動かす場合の2パターンを説明します。

webpack-dev-serverをローカルで動かす

webpack-dev-serverを入れて、webpack.config.jsを修正して、最後 webpack serveを実行します。

コードの修正点はこちらを参照して下さい。

https://github.com/junara/webpack_simpack/commit/43336806f5cc24ea65238ea3bcfd16b2417cd1c3

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コンテナで動かす

コンテナで動かす事もできます。
コードは以下の通り。

https://github.com/junara/webpack_simpack/commit/4b56f6ba008865f7ad0730720c9f64556076127e

まず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