🛠
Rail6からWebpackerを剥がしてみた
補足
- やったことを思い出すための自分用のログという位置付けです 📝
- Webpacker と直接関係ないことも作業ログとして書いてます
- 理解が浅いところがあります 🙇♂️
- とりあえずできたって感じなのでベストな方法ではないと思います 💡
ゴール
- Webpacker -> Webpack に置き換えること
- Heroku にデプロイして動作に問題がないこと
環境など
- Rails 6.1.4
- webpack 5.73.0
- tailwind 3.1.6
- React 18.2.0
- Rails の view に埋め込んで使っている
- Heroku にデプロイしているアプリケーション
なぜ剥がすのか
- Jest を導入したくなったことがきっかけ
- Webpacker だとレールから外れたカスタマイズが難しく、Jest 導入前に脱却しておこうと考えたから
-
Webpacker を導入してから外すまでをふりかえる - 弥生開発者ブログ
-
Webpacker の場合は、独自でラップされたクラスを経由してカスタマイズする必要があります
-
Webpacker が提供していない範囲で webpack のカスタマイズが必要になってくると、結局は webpack.config.js 相当のものを引き剥がして書き変える必要が出てきます
-
Webpacker 側のパッケージが更新されるまでは、独自で入れたいパッケージが更新できない・あるいは追加できない
-
-
Webpacker を導入してから外すまでをふりかえる - 弥生開発者ブログ
- 今まで脳死で Webpacker を使っていて JS のビルドに関する知識が乏しく、勉強になりそうだから
やったこと
やったことを時系列順に書きます。
Switch from Webpacker 5 to jsbundling-rails with webpackの手順通りにやってみる
1.-
jsbundling-rails
のセットアップ -
Webpacker
に関するファイルの削除
起動はできたが React を使っている部分が表示されない
- gem
React-Rails
を使用していて、これがjsbundling-rails
に対応していなさそう? - gem
react_on_rails
への移行が選択肢としてあるが、大変そう
2. ということで gem を使わない方法に切り替えてみる
-
webpack を使った Rails 上での React 開発 - クックパッド開発者ブログ
-
Reactに関わるモジュールバンドリング(複数ファイルの結合)、ソースコードの変換、ビルドしたコードの配置まではwebpackで行い、ファイルへのフィンガープリント付与などはこれまで通りSprocketsに任せます。
-
- この対応に伴い
app/javascript/packs/
のファイルをclient/~
に移動させた - React 部分表示された!
tailwindcss-rails
の gem も剥がす
3. ついでに -
yarn install tailwindcss
し、tailwind の設定をwebpack.config.js
に追記
CSS が反映されない・・・なぜだ
-
tailwind.config.js
でcontent
を設定していなかった-
content
で指定したファイルがビルドされるようになっている - 余計なビルドを避ける仕組み
-
tailwind.config.js
の extend に定義したスタイルが適用されない
- tailwind の extend で定義してるものは
application.html.erb
で使っていたのでビルドの対象になってなかった-
application.html.erb
内でスタイル付けするのをやめて、jsx のコンポーネントに移した
-
4. Heroku に node.js のビルドパックを追加してデプロイする
デプロイを試みるも謎エラー発生
-
[ERR_MODULE_NOT_FOUND]: Cannot find package 'babel-plugin-macros'
- webpacker 時代から残っていた webpack の設定ファイル
babel.config.js
を参照してしまっていた?- ここに
babel-plugin-macros
が記述されている - ファイル削除して再 push
- ここに
- webpacker 時代から残っていた webpack の設定ファイル
別のエラーになった
18:18:17 webpack.1 | ERROR in ./client/src/app.css (./node_modules/css-loader/dist/cjs.js!./node_modules/postcss-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./client/src/app.css)
18:18:17 webpack.1 | Module build failed (from ./node_modules/postcss-loader/dist/cjs.js):
18:18:17 webpack.1 | TypeError: Cannot read property 'config' of undefined
-
この対応に伴いapp/javascript/packs/ のファイルを client/~ に移動させた
をしたとき、tailwind.config.js
とposts.config.js
を移動させていなかった- 移動させた
- デプロイ成功!
- しかし画像が表示されていない
5. 画像が Heroku 上で表示されない問題を解消する
- ローカルでは表示されている
- 画像読み込みには
file-loader
を使用している- 出力先を public 配下にしたら表示された
- 出力先が assets 配下だとフィンガープリントが付くから表示されない?
-
file-loader
のかわりにurl-loader
を使ったら表示された-
url-loader
は dataUrl として画像がバンドルされる -
file-loader
は画像ファイルそのものが出力される
-
- webpack5 から
AssetModules
という、file-loader
やurl-loader
の代替となる機能が使えるようになったらしいので採用した- ファイルサイズの閾値を設定しておくと、
file-loader
とurl-loader
を使い分けてくれる
- ファイルサイズの閾値を設定しておくと、
最終的な設定ファイルはこちら
webpack.config.js
const path = require('path');
module.exports = {
entry: {
page1: './client/src/entrypoints/page1.js',
page2: './client/src/entrypoints/page2.js',
// ...
},
output: {
path: path.resolve(__dirname, './app/assets/javascripts/webpack'),
filename: '[name].js',
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: {
loader: 'babel-loader',
},
exclude: /node_modules/,
},
{
test: /\.(png|jpg|gif|svg)$/,
type: 'asset',
// 8kb以下の画像はバンドルし、8kb以上の画像は public/images に出力する
parser: {
dataUrlCondition: {
maxSize: 8 * 1024, // 8kb
},
},
generator: {
filename: '[hash][ext][query]',
outputPath: '../../../../public/images/',
publicPath: 'images/',
},
},
{
test: /\.(css|scss)$/,
use: ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader'],
},
],
},
};
post.css.config
module.exports = {
plugins: ['tailwindcss'],
};
tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ['./client/src/**/*.{html,js}'],
theme: {
extend: {
backgroundColor: {
primary: '#e40b20',
},
backgroundImage: {
base: "url('../images/email-pattern.png')",
},
animation: {
bg: 'bg 40s infinite linear',
},
keyframes: {
bg: {
'0%': { backgroundPosition: '0 0' },
'100%': { backgroundPosition: '360px -360px' },
},
},
},
minHeight: {
// フッターを除いた高さ
main: 'calc(100vh - 148px)',
},
},
plugins: [],
};
Discussion