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

Rails: Webpacker→jsbundling-rails+webpackアップグレード手順(翻訳)

概要

MITライセンスに基づいて翻訳・公開いたします。

表記の大文字小文字は「Webpacker」「Shakapacker」「webpack」「jsbundling-rails」「cssbundling-rails」に統一しました。

  • 2022/02/03: 初版公開
  • 2022/09/06: 更新
  • 2024/01/22: 更新

Rails: Webpacker→jsbundling-rails+webpackアップグレード手順(翻訳)

本ガイドでは、Webpacker 5からjsbundling-rails + webpack 4への移行方法を手順を追って解説します。Webpacker/Shakapacker v6への移行方法については、Shakapackerのアップグレードガイドを参照してください。また、Webpackerとjsbundling-railsの比較についてはこちらをご覧ください。

なお、jsbundling-railsに移行すると、Webpackerの以下の機能は利用できなくなります。

上記の機能に依存している場合や、webpackのセットアップが複雑な場合は、以下のShakapackerへの移行を検討してください。

shakacode/shakapacker - GitHub

🔗 1. jsbundling-railsのセットアップ

最初にjsbundling-railsをインストールします。

# Gemfileに以下を追加する
+ gem 'jsbundling-rails'
# コマンドラインでバンドルを再ビルドする
./bin/bundle install

# コマンドラインで基本設定を作成する
./bin/rails javascript:install:webpack

このインストールスクリプトでは以下が行われます。

  • マニフェストにビルドを追加する
  • gitのビルドを無視する
  • マルチプロセス用にforemanをセットアップする
  • ./webpack.config.jsを作成する
  • package.jsonにビルドスクリプトを追加する

🔗 webpackの設定を移動する

Webpackerとjsbundling-railsの差分を最小限にとどめたい場合は、以下を実行します。

  • 1. ./webpack.config.js./config/webpack/以下に移動する
  • 2. package.jsonの設定パスを以下のように変更する
- "build": "webpack --config ./webpack.config.js"
+ "build": "webpack --config ./config/webpack/webpack.config.js"
  • 3. webpack.config.js出力パスを以下のように変更する
- path: path.resolve(__dirname, "app/assets/builds"),
+ path: path.resolve(__dirname, '..', '..', 'app/assets/builds')

🔗 2. Webpackerを削除する

🔗 1. 以下のファイルを削除し、これらのファイルで行ったカスタマイズがすべて移行されていることを確認する

  • ./bin/webpack
  • ./bin/webpack-dev-server
  • ./config/initializers/webpacker.rb
  • ./config/webpacker.yml
  • ./config/webpack/development.js
  • ./config/webpack/environment.js
  • ./config/webpack/production.js
  • ./config/webpack/test.js

🔗 2. Webpackerのコンフィグを削除する

# config/initializers/assets.rbで以下を削除
-# Add Yarn node_modules folder to the asset load path.
-Rails.application.config.assets.paths << Rails.root.join('node_modules')
# config/initializers/content_security_policy.rbで以下を削除
-#   # If you are using webpack-dev-server then specify webpack-dev-server host
-#   policy.connect_src :self, :https, "http://localhost:3035", "ws://localhost:3035" if Rails.env.development?

🔗 3. Webpacker gemを削除する

# Gemfileで以下を削除
- gem 'webpacker'

🔗 4. ./bin/bundle installを実行する

🔗 3. 依存関係をインストールする

Webpackerにはデフォルトで多数の依存関係がインストールされますが、jsbundling-railsの依存関係は開発者に任せられています。単にJavaScriptを変更せずに扱いたい場合、追加のパッケージをインストールする必要はありません。以後のセクションについては開発者の好みに応じて適用してください。

# CLIでWebpackerパッケージを削除する
yarn remove @rails/webpacker webpack-dev-server

🔗 オプション: Babel

Babelは、JavaScriptソースコードを古いバージョンのJavaScriptにトランスパイルするのに用いられます。

🔗 1. パッケージをインストールする
# Babelのプリセットをコマンドラインで追加する
yarn add @babel/core @babel/preset-env babel-loader
🔗 2. Babelを設定する
// package.jsonに以下を追加する
+ "babel": {
+   "presets": ["@babel/env"]
+   "presets": ["@babel/preset-env"]
+ }
🔗 3. webpackのローダーを利用する
// webpack.config.jsに以下を追加する
module.exports = {
  module: {
    rules: [
+       {
+         test: /\.(js)$/,
+         exclude: /node_modules/,
+         use: ['babel-loader'],
+       },
    ],
  },
};

🔗 例: Babel + React + TypeScript

フロントエンドのフレームワークやTypeScriptはBabelでトランスパイルできます。この例では、ReactとTypeScriptを利用するセットアップを使います。

🔗 1. パッケージをインストールする
# Babelのプリセットをコマンドラインで追加する
yarn add @babel/core @babel/preset-env @babel/preset-react @babel/preset-typescript
🔗 2. Babelを設定する
// package.jsonに以下を追加する
+ "babel": {
+   "presets": [
+     "@babel/env",
+     "@babel/react",
+     "@babel/preset-env",
+     "@babel/preset-react",
+     "@babel/preset-typescript"
+   ]
+ }
🔗 3. webpackを設定する
// webpack.config.jsに以下を追加する
module.exports = {
  module: {
    rules: [
+       {
+         test: /\.(js|jsx|ts|tsx|)$/,
+         exclude: /node_modules/,
+         use: ['babel-loader'],
+       },
    ],
  },
};

🔗 オプション: CSS + SASS

webpackでは、適切なローダーを使うことでCSSファイルを扱えるようになります。このセットアップでは、ファイルを扱うときにjsbundling-rails「のみ」を利用し、cssbundling-railsを利用していません。

🔗 1. パッケージをインストールする
# ローダー、プラグイン、node sassをコマンドラインでインストールする
yarn add css-loader sass sass-loader mini-css-extract-plugin webpack-remove-empty-scripts
🔗 2. webpackを設定する
// webpack.config.jsで以下を行う

// CSSを.cssファイルに切り出す
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// CSSのみを含むエントリーから、exportされたJavaScriptファイルを削除する
// この例では、entry.customは対応する空のcustom.jsファイルを作成する
const RemoveEmptyScriptsPlugin = require('webpack-remove-empty-scripts');

module.exports = {
  entry: {
    // 自分のcssやsassのエントリをここに追加する
    application: [
      './app/assets/javascripts/application.js',
      './app/assets/stylesheets/application.scss',
    ],
    custom: './app/assets/stylesheets/custom.scss',
  },
  module: {
    rules: [
      // ローダーを含むCSS/SASS/SCSSルールをここに追加する
      {
        test: /\.(?:sa|sc|c)ss$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],
      },
    ],
  },
  resolve: {
    // 追加のファイル種別をここに追加する
    extensions: ['.js', '.jsx', '.scss', '.css'],
  },
  plugins: [
    // プラグインをインクルードする
    new RemoveEmptyScriptsPlugin(),
    new MiniCssExtractPlugin(),
  ],
};

🔗 オプション: フォント、画像、SVG

webpackでは、適切なローダーを使うことでJavaScriptファイルやCSSファイル以外のファイルも扱えるようになります。このセットアップ手順は用途によって異なりますが、おおよそ以下のようになります。

🔗 1. パッケージをインストールする
yarn add file-loader
🔗 2. webpackを設定する
// webpack.config.jsに以下を追加する
module.exports = {
  module: {
    rules: [
+       {
+         test: /\.(png|jpe?g|gif|eot|woff2|woff|ttf|svg)$/i,
+         use: 'file-loader',
+       },
    ],
  },
};

🔗 オプション: webpackでアセットをチャンクしてSprocketsで動作するようにする

Sprocketsが更新されて、アセットがフィンガープリント設定済みであることを検出した場合はフィンガープリントを再実行しないようになりました。これによって、webpackのcode splitting機能が利用可能になるとともに、すべてのアセットでキャッシュ無効化フィンガープリント(cache-busting fingerprints)が置かれるようになってCDNに保存可能になります。この設定によって、Sprocketsがエントリポイントファイルへのフィンガープリント設定を実行可能になり、javascript_include_tagでそのアセット名を指定して読み込めるようになります。

// webpack.config.jsに以下を追加する:
module.exports = {
  output: {
    filename: "[name].js",
    chunkFilename: "[name]-[contenthash].digested.js",
    sourceMapFilename: "[file]-[fullhash].map",
    path: path.resolve(__dirname, '..', '..', 'app/assets/builds'),
    hashFunction: "sha256",
    hashDigestLength: 64,
  }
}

🔗 4. ビルドをテストする

webpackの設定が期待どおりに動作することを確認します。以下を実行することでバンドルを再ビルドできます。

yarn build --progress --color

エントリが複数ある場合は、個別のエントリごとに確認してから、最後にバンドル全体を確認することをおすすめします。

🔗 5. Webpackerのpackタグを置き換える

Webpackerのアセットタグを以下のように検索置換します。

# Webpackerのタグ       # Sprocketsのタグ
javascript_pack_tag = javascript_include_tag
stylesheet_pack_tag = stylesheet_link_tag

タグの置き換えが完了すれば、アプリケーションはこれまでと同じように動くはずです。

🔗 オプション: development環境向けのサポートを追加する

jsbundling-railsはproductionモードにのみ同梱されています。以下のようにmode: 'development'に切り替えることで、開発中のビルド時間を劇的に短縮できます。

// webpack.config.jsを以下のように変更する
+ const mode = process.env.NODE_ENV === 'development' ? 'development' : 'production';

module.exports = {
-  mode: "production",
+  mode,
-  devtool: "source-map",
  …
+  optimization: {
+    moduleIds: 'deterministic',
+  }
}

関連記事

Rails: Webpacker v5からShakapacker v6へのアップグレードガイド(翻訳)

Rails UJS・Turbolinks -> Turboアップグレードガイド(翻訳)


CONTACT

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