WebpackerからShakapackerへ移行したときの備忘録
RailsでWebpackerを使用していたのですが、こちらが開発終了となり、fork先にShakapackerが引き継いでいるので、そちらに移行したときの備忘録です。
Webpacker5.4 -> Shakapacker6.1 へ移行したため、途中のWebpacker5.4以上の対応も含まれてます
移行した手順
- Gemfileの
webpacker
をshakapacker
に書き換える(バージョンが5系の場合は6系にする) - npm packageから
@rails/webpacker
を削除する
yarn remove @rails/webpacker
shackapacker
をインストールする(shackepacekrの場合は@rails
の接頭詞は不要)
yarn add shackapacker
- 依存packegeのインストール
yarn add @babel/core @babel/plugin-transform-runtime @babel/preset-env @babel/runtime babel-loader compression-webpack-plugin terser-webpack-plugin webpack webpack-assets-manifest webpack-cli webpack-merge webpack-sources webpack-dev-server
- bin/webpack -> bin/webpacker に, bin/webpack-dev-server -> bin/webpacker-dev-serverに名前を変える
$ git mv bin/webpack bin/webpacker $ git mv bin/webpack-dev-server bin/webpacker-dev-server
- 設定ファイルが単一の
config/webpack/webpack.config.js
の場合は以下のように修正する
const { env, webpackConfig } = require('shakapacker') const { existsSync } = require('fs') const { resolve } = require('path') const envSpecificConfig = () => { const path = resolve(__dirname, `${env.nodeEnv}.js`) if (existsSync(path)) { console.log(`Loading ENV specific webpack configuration file ${path}`) return require(path) } else { console.log(`WARNING: Using default webpack configuration. Did not find a Env specific file at path ${path}`) return webpackConfig } } module.exports = envSpecificConfig()
webpacker.yml
を修正する
source_path: app/javascript source_entry_path: /
app/javascript/packs/*
以下にあるファイルをapp/javascript/
に移動する
$ git mv app/javascript/packs/* app/javascript/
webpacker:install
タスクを実行しwebpacker関連のファイルを上書きする(mオプションで必要に応じて既存の設定をmergeする)
$ bundle exec rails webpacker:install
javascript_packs_with_chunks_tag
をjavascript_packs_tag
に、stylesheet_packs_with_chunks_tag
をstylesheet_pack_tag
に変更するconfig/webpack/environment.js
をconfig/webpack/base.js
に変更し、以下の修正を加える
// config/webpack/base.js const { webpackConfig, merge } = require('@rails/webpacker'); const customConfig = { module: { rules: [ { test: require.resolve('jquery'), loader: 'expose-loader', options: { exposes: ['$', 'jQuery'] } } ] } }; module.exports = merge(webpackConfig, customConfig);
12 . package.jsonにbbrowserslist
の設定が存在する場合、.browserslistrc
ファイルを削除する
// package.json "browserslist": [ "defaults" ],
babel.config.js
を削除する。デフォルトでは以下の設定を読み込むようになる
"babel": { "presets": [ "./node_modules/shakapacker/package/babel/preset.js" ] },
- webpacker.ymlから
extensions
を削除する。config/webpack/base.js
にextensions
の内容をmergeする
// config/webpack/base.js const { webpackConfig: baseWebpackConfig, merge } = require('shakapacker') const options = { resolve: { extensions: ['.css', '.ts', '.tsx'] } } // Copy the object using merge b/c the baseClientWebpackConfig is a mutable global // If you want to use this object for client and server rendering configurations, // havaing a new object is essential. module.exports = merge({}, baseWebpackConfig, options)
webpacker.yml
にwatched_paths
がある場合、additional_paths
に書き換える以下のコミットで消されたパッケージがある場合、削除する
https://github.com/rails/webpacker/pull/3056/files
$ yarn remove babel-plugin-macros case-sensitive-paths-webpack-plugin core-js regenerator-runtime
bin/webpack
を実行しエラーが出ないことを確認する
./bin/webpack
- railsタスクからcompileが通ることを確認する
RAILS_ENV=production bin/rails assets:precompile bin/rails assets:clobber // assetsをclean
- webpack-dev-serverが動くことを確認する
yarn add webpack-dev-server
- 他のscriptで
/bin/webpack
,bin/webpack-dev-server
を記述している箇所があれば、bin/webpacker
,bin/webpacker-dev-server
に修正する
typescriptの場合
- tsconfig.jsonを以下のように修正
{ "compilerOptions": { "declaration": false, "emitDecoratorMetadata": true, "experimentalDecorators": true, "lib": ["es6", "dom"], "module": "es6", "moduleResolution": "node", "baseUrl": ".", "paths": { "*": ["node_modules/*", "app/packs/*"] }, "sourceMap": true, "target": "es5", "noEmit": true }, "exclude": ["**/*.spec.ts", "node_modules", "vendor", "public"], "compileOnSave": false }
- 依存パッケージのインストール
$ yarn add typescript @babel/preset-typescript
- webpack.config.js(環境別であればconfig/webpack/base.js)を修正する
const { webpackConfig, merge } = require("shakapacker"); const ForkTSCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin"); module.exports = merge(webpackConfig, { plugins: [new ForkTSCheckerWebpackPlugin()], });
- ${RAILE_ENV}.jsでtoWebpackConfigは不要
babel.config.jsをカスタマイズする
// babel.config.js module.exports = function (api) { const defaultConfigFunc = require('shakapacker/package/babel/preset.js') // defaultで使用される設定を読み込む const resultConfig = defaultConfigFunc(api) const isDevelopmentEnv = api.env('development') const isProductionEnv = api.env('production') const isTestEnv = api.env('test') const changesOnDefault = { presets: [ [ '@babel/preset-react', { development: isDevelopmentEnv || isTestEnv, useBuiltIns: true } ] ].filter(Boolean), plugins: [ isProductionEnv && ['babel-plugin-transform-react-remove-prop-types', { removeImport: true } ], process.env.WEBPACK_SERVE && 'react-refresh/babel' ].filter(Boolean), } // デフォルトの設定とカスタム設定をmergeする resultConfig.presets = [...resultConfig.presets, ...changesOnDefault.presets] resultConfig.plugins = [...resultConfig.plugins, ...changesOnDefault.plugins ] return resultConfig }
css
- 各種css loaderをインストールする
$ yarn add css-loader style-loader mini-css-extract-plugin css-minimizer-webpack-plugin
- resolve.extensionsを修正する
// config/webpack/webpack.config.js const { webpackConfig, merge } = require('shakapacker') const customConfig = { resolve: { extensions: ['.css'] } } module.exports = merge(webpackConfig, customConfig)
sass
$ yarn add sass sass-loader
移行時に躓いたポイント
static_assets_extensionsについて
削除されているため、設定しても無意味
- Webpack5 からAsset Modulesが採用されており、その設定が組み込まれているため基本的には修正不要
Error: Can't resolve './src'
- webpack5以降デフォルトでのentry pointは
src/index.js
- webpackの設定をoutputしてみるが、entryは正しく設定されていた
原因
環境別のconfig/webpack/${RAILE_ENV}.js
にてmodule.exports
をしてなかった...
- config/webpack/development.js
process.env.NODE_ENV = process.env.NODE_ENV || 'development' const base = require('./base') module.exports = base // これを忘れていた...
- config/webpack/base.js
const { webpackConfig, merge, environment } = require('shakapacker'); const ForkTSCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin"); const path = require("path") const customConfig = { resolve: { extensions: [ ".tsx", ".ts", ".mjs", ".js", ".jsx", ".sass", ".scss", ".css", ".module.sass", ".module.scss", ".module.css", ".png", ".svg", ".gif", ".jpeg", ".jpg" ] }, module: { rules: [ { test: require.resolve('jquery'), loader: 'expose-loader', options: { exposes: ['$', 'jQuery'] } } ] }, plugins: [new ForkTSCheckerWebpackPlugin({ typescript: { configFile: path.resolve(__dirname, "../../tsconfig.json"), }, async: false, })], }; module.exports = merge(webpackConfig, customConfig);
- config/webpack/webpack.config.js
const { env, webpackConfig } = require('shakapacker') const { existsSync } = require('fs') const { resolve } = require('path') const envSpecificConfig = () => { const path = resolve(__dirname, `${env.nodeEnv}.js`) if (existsSync(path)) { console.log(`Loading ENV specific webpack configuration file ${path}`) return require(path) } else { console.log(`WARNING: Using default webpack configuration. Did not find a Env specific file at path ${path}`) return webpackConfig } } module.exports = envSpecificConfig()
TypeError: Cannot read properties of undefined (reading 'get')
at WebpackAssetsManifest.handleProcessAssetsAnalyse (...node_modules/webpack-assets-manifest/src/WebpackAssetsManifest.js:467:37))
application.tsを一旦コメントアウトすると動作したため、 どこかのファイルの書き方の問題くさい(もう少しわかりやすいエラーでないのか...)
expose-loaderを入れてなかったのが原因
https://runebook.dev/ja/docs/webpack/loaders/expose-loader https://site-builder.wiki/posts/17882
webpackのProvidePluginを使ったほうが良さそう
// app/packs/entrypoints/application.js - import jQuery from 'jquery' - window.jQuery = jQuery
// config/webpack/webpack.config.js const webpack = require('webpack') const { webpackConfig, merge } = require('shakapacker') module.exports = merge(webpackConfig, { plugins: [ new webpack.ProvidePlugin({ $: 'jquery', jQuery: 'jquery', }) ], })
require.context('./images', true)
かつてimage_pack_tag
helperを使用するために使われていたもの
おそらく不要になった(webpackの設定から読み込むようになった) https://github.com/shakacode/shakapacker/blob/4d41b5a4ad3a7b7f4373c2ae0c8f2d0d697e389c/lib/webpacker/helper.rb#L169
Stimuls JS Class constructor Controller cannot be invoked without 'new'
browserlistに"not IE 11"を指定すると解決する
https://github.com/hotwired/stimulus/issues/433
imagesが読み込めない
https://github.com/rails/webpacker/issues/2956
TypeError: Cannot read properties of undefined (reading 'get')
at WebpackAssetsManifest.handleProcessAssetsAnalyse (/
以下のようにruleを追加する(フォルダは他に合わせてstaticにする)
rules: [ { test: [/\.mp3$/], exclude: /\.(js|mjs|jsx|ts|tsx)$/, type: 'asset/resource', generator: { filename: 'static/[name]-[hash][ext][query]' } } ]
asset_pack_path("static/images/image.png")
だと読み込めない
static/imagesディレクトリは作成されないから