webpackerからwebpackへ。
背景
Railsプロジェクトで、webpackerの引退に合わせて、webpackへの移行を行います。
移行の際に身につけたフロントの知識や、ポイントをまとめています。
基本の手順
基本は、webpackerのgem公式ページを参考にします。
上記のサイトでは、switching Guideが紹介されているので、それに従います。
ガイドに従えばできると思っていたのですが、いくつかポイントがありました。
そもそもwebpackerでは何を管理していたのか?
そもそも、RailsにはwebpackerとSprocketsという2つのフロントエンド関連のGemが入っていました。
上記のツールは、javascript, css, imageといった静的アセットを処理して、いい感じに配信してくれるためのモジュールハンドラーと呼ばれるものです。
ここで問題なのが、自分の使っているwebpackerではjs, css, imageのどれを管理対象にしていたのか?ということです。
基本webpackerはjavascriptを処理する前提で導入されているはずですが、設定によってはcss, imageも処理できてしまいます。
そして、それによって移行の手順も変わってきます。
フロントはビルドが必要
そもそもですが、webpackはフロンドの技術であり、ビルドが必要です。
Railsのようなフレームワークはrails sしてあげればよしなに処理してくれますが、webpackは都度ビルドが必要です。
私の場合は `blog/package.json` に以下のようなスクリプトを設置し、npm run buildを実行することでwebpackでビルをしています。
"scripts": {
"build": "webpack --config ./config/webpack/webpack.config.js"
}
実際の移行手順
javascrip,css,imageの全てをwebpackerで管理していたという前提で作業を進めていきます。
01. Javascriptをwebpackerへ移行
これは、手順通りにやればできます。
ただ、手順の中でディレクトリ階層が変化するので、application.jsでimportするパスを修正する必要があります。
npm run build
> blog@0.1.0 build
> webpack --config ./config/webpack/webpack.config.js
asset application.js 67.7 KiB [compared for emit] [minimized] (name: application) 1 related asset
runtime modules 718 bytes 3 modules
cacheable modules 99 KiB
modules by path ./node_modules/ 98 KiB
./node_modules/@rails/ujs/lib/assets/compiled/rails-ujs.js 27.7 KiB [built] [code generated]
./node_modules/turbolinks/dist/turbolinks.js 37.6 KiB [built] [code generated]
./node_modules/@rails/activestorage/app/assets/javascripts/activestorage.js 32.6 KiB [built] [code generated]
modules by path ./app/javascript/ 1.02 KiB
./app/javascript/packs/application.js 751 bytes [built] [code generated]
./app/javascript/channels/index.js 292 bytes [built] [code generated]
./app/javascript/channels/ sync _channel\.js$ 160 bytes [built] [code generated]
webpack 5.90.3 compiled successfully in 1981 ms
02. cssをwebpackへ移行。
一旦cssのimport業はコメントアウトしていましたが、ここで有効化してビルドするとエラーが発生します。
npm run build
ERROR in ./app/javascript/packs/application.js 11:0-28
Module not found: Error: Can't resolve 'packs/css/pack.css' in '/home/ubuntu/blog/app/javascript/packs'
resolve 'packs/css/pack.css' in '/home/ubuntu/blog/app/javascript/packs'
Optional: CSS + SASSの手順に沿って、css,scssをビルドする設定を記述します。
が、ここで不可解な単語が幾つが出てきます。
webpack.config.jsのmodule内にあるruleとは?
module: {
rules: [
// Add CSS/SASS/SCSS rule with loaders
{
test: /\.(?:sa|sc|c)ss$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],
},
],
},
ruleはアセットの変換ルールのことのようです。
testは変換対象のファイルを正規表現で書いています。
useは変換するためのローダを指定しています。配列で複数指定する場合はuseというものを使用するようです。
こちらの記事で解説されています。
この時点でのwebpack.config.json
const path = require("path")
const webpack = require("webpack")
// Extracts CSS into .css file
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// Removes exported JavaScript files from CSS-only entries
// in this example, entry.custom will create a corresponding empty custom.js file
const RemoveEmptyScriptsPlugin = require('webpack-remove-empty-scripts');
module.exports = {
mode: "production",
devtool: "source-map",
entry: {
application: [
"./app/javascript/packs/application.js",
],
custom: '/app/javascript/packs/css/pack.css',
},
output: {
filename: "[name].js",
sourceMapFilename: "[file].map",
chunkFormat: "module",
path: path.resolve(__dirname, '..', '..', 'app/assets/builds')
},
module: {
rules: [
// Add CSS/SASS/SCSS rule with loaders
{
test: /\.(?:sa|sc|c)ss$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],
},
],
},
resolve: {
// Add additional file types
extensions: ['.js', '.jsx', '.scss', '.css'],
},
plugins: [
new webpack.optimize.LimitChunkCountPlugin({
maxChunks: 1
}),
// Include plugins
new RemoveEmptyScriptsPlugin(),
new MiniCssExtractPlugin(),
]
}
ビルドに成功
ビルドには成功してbuildディレクトリにファイルが出力されました!
出力したcss類は、assets/stylesheets/application.cssでassets/buildsディレクトリごと読み込みました。
手順書には、ビルドまでした記述がないため、それ移行の出力はこちらで考える必要があります。
03. imageをwebpackへ移行。
こちらも基本的に手順書のOptional: Fonts, Images, SVGに従ってやります。
普通にやると、js,css同様`blog/app/assets/builds/`以下に画像が生成されるので、img_tagで出力できない。
img_tagの入力先を変えるっていう手もあるだろうけど、webpackのためにrailsの設定を変えたくないので、画像だけ出力先をimagesの中に変えたい!
が、いろいろ試してけれど、画像だけ出力先ディレクトリを変更することができなかった。。
そのうちまた試してみよう。(今後の課題)
現段階のwebpack.config.js
const path = require("path")
const webpack = require("webpack")
// Extracts CSS into .css file
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// Removes exported JavaScript files from CSS-only entries
// in this example, entry.custom will create a corresponding empty custom.js file
const RemoveEmptyScriptsPlugin = require('webpack-remove-empty-scripts');
module.exports = {
mode: "production",
devtool: "source-map",
entry: {
application: [
"./app/javascript/packs/application.js",
// "/app/assets/stylesheets/application.scss",
],
pack: '/app/javascript/packs/css/pack.css',
},
output: {
filename: "[name].js",
sourceMapFilename: "[file].map",
chunkFormat: "module",
path: path.resolve(__dirname, '..', '..', 'app/assets/builds')
},
module: {
rules: [
// Add CSS/SASS/SCSS rule with loaders
{
test: /\.(?:sa|sc|c)ss$/i,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
}
},
{
loader: 'css-loader'
},
{
loader: 'sass-loader'
},
],
},
{
test: /\.(png|jpe?g|gif|eot|woff2|woff|ttf|svg)$/i,
loader: 'file-loader',
options: {
// outputPath: path.resolve(__dirname, '..', '..', 'app/assets/aaa'),
outputPath: (__dirname, '..', '..', 'images'),
},
},
],
},
resolve: {
// Add additional file types
extensions: ['.js', '.jsx', '.scss', '.css'],
},
plugins: [
new webpack.optimize.LimitChunkCountPlugin({
maxChunks: 1
}),
// Include plugins
new RemoveEmptyScriptsPlugin(),
new MiniCssExtractPlugin(),
]
}
残された課題
- webpackで管理する画像をimg_tagで利用できない
- npm run buildすると、`app/assets/builds`の中にjs,css,imageの全てがビルドされる。
- railsのimg_tagは`app/assets/images`の中の画像を出力するので、これでは利用できない。
- npm run build実行時に画像だけ`app/assets/images`の中に入れば解決するが、その指定方法がいろいろ試してダメだった。
- img_tagのinputを`app/assets/images`から変えることは避けたいので現状手詰まり。