よんどころなき事情により Webpack で clean-webpack-plugin
を使おうとしたのですが、過去の記事を見ていたら嵌まったのでメモしておきます。
経緯
処理中のフラグによって .js
ファイルを複数出力(数はフラグにより増減)しようとしたのですが、減らすときは当然 output 先 (ここでは dist/js
)は前の出力結果が残ってしまっているので、余計なゴミとして残ってしまうことに気付きました。
そこで Webpack のビルド直前に output 先をクリーニングしようと考え、検索すると clean-webpack-plugin
がヒットしたので、これを試そうとしました。
なお、パッケージの指定は以下の通りです。
"devDependencies": {
"webpack": "^5.15.0",
"webpack-stream": "^6.1.1",
"terser-webpack-plugin": "^5.1.1",
"clean-webpack-plugin": "^3.0.0"
},
"resolutions": {
"webpack": "^5.15.0"
},
Gulp から webpack-stream
経由で Webpack を使用、という状況です。
現象
clean-webpack-plugin
の使い方の記事を見ると、 webpack.config.js
に以下のように書くケースが散見されました。
const webpackTerser = require('terser-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin'); // require
const path = require('path');
const glob = require('glob');
const entry = () => {
const entries = glob
.sync(
'**/*.js',
{
cwd: 'src/js',
ignore: [
'**/_*.js'
]
}
)
.map(function (key) {
return [key, path.resolve('src/js', key)];
});
return Object.fromEntries(entries);
};
const configs = {
mode: 'development',
entry: entry(),
output: {
filename: '[name]',
},
devtool: 'inline-source-map',
plugins: [
// plugin
new CleanWebpackPlugin([
'dist/js' // cleanup path
]),
],
optimization: {
minimizer: [
new webpackTerser({
extractComments: 'some',
terserOptions: {
compress: {
drop_console: false,
},
},
}),
],
},
};
module.exports = configs;
今回引っかかったのは CleanWebpackPlugin
インスタンスへの引数で「クリーニングしたいディレクトリのパスの配列」を指定する部分。
Error: clean-webpack-plugin only accepts an options object. See:
https://github.com/johnagan/clean-webpack-plugin#options-and-defaults-optiona
clean-webpack-plugin
の引数はオブジェクトの形式ですって?
散見される記事は配列でした。
上記エラー文の通り、 Github を参照すると……確かにオブジェクトの形式で指定されています。
これ以上は突っ込んでいませんが、どうやらどこかのバージョン (今回インストールした clean-webpack-plugin
は 3.0.0
だったので、2系と3系で乖離があるのかもしれません) で仕様が変わったのかもしれません。
これを受けて以下のように修正。
const webpackTerser = require('terser-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin'); // require
const path = require('path');
const glob = require('glob');
const entry = () => {
const entries = glob
.sync(
'**/*.js',
{
cwd: 'src/js',
ignore: [
'**/_*.js'
]
}
)
.map(function (key) {
return [key, path.resolve('src/js', key)];
});
return Object.fromEntries(entries);
};
const configs = {
mode: 'development',
entry: entry(),
output: {
filename: '[name]',
},
devtool: 'inline-source-map',
plugins: [
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns: [
'dist/js/**/*.js' // cleanOnceBeforeBuildPatterns キーの中に配列指定。また、ディレクトリパスの指定ではなく、 glob での指定
],
}),
],
optimization: {
minimizer: [
new webpackTerser({
extractComments: 'some',
terserOptions: {
compress: {
drop_console: false,
},
},
}),
],
},
};
module.exports = configs;
変更点は以下の2つ。
- 指定そのものを
cleanOnceBeforeBuildPatterns
キーに対する値として配列を記述するようにしたこと - ディレクトリパスではなく glob 指定ということ (拡張子指定が不要な場合は
dist/js/**/*
というような形)
これで意図した挙動になりました。
余談
最初とりあえず試すだけ試そうとして
plugins: [
new CleanWebpackPlugin(),
],
途中試験のため cwd
も抜いていたせいで、引数なしで CleanWebpackPlugin
インスタンスを起こしたところ、プロジェクトルートからファイルを削除しようとして焦りました (デフォルトが dry: false
(テストなし), verbose: false
(削除するファイルをコンソールに出力しない), cleanOnceBeforeBuildPatterns: ['**/*']
(ルートからの全てのファイル) という指定だったため)。
うっかり走らせないこと。
参考
- johnagan/clean-webpack-plugin: A webpack plugin to remove your build folder(s) before building
- Webpack Babel + Pug + Stylus で ホットリロードできるSPA開発環境作った。 – かもメモ
- CleanWebpackPlugin does not clean in Webpack 5 – Stack Overflow