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ディレクトリは作成されないから