近年ただのモジュールバンドラであるはずのwebpackをgulpのように扱う傾向があるように感じます。
その流行に乗っかってgulpをwbpackに完全replaceしてみたのですが、htmlやimageを /dist
などにコピーするという単純な処理に手間取ったので、解決法をここに記しておこうと思います。
ディレクトリ構成
root
webpack.config.js
- dist
- src
index.html
- under
- index.html
- assets
- images
- test.png
目標
- これらのファイルを構造を維持しつつ、distへコピーする.
- webpack-dev-serverを使いながらでも、ファイルが更新されるようにする.
- watch中にファイルが新しく追加されてもコピーされるようにする.
ライブラリのインストール
$ yarn add -D webpack webpack-cli webpack-dev-server copy-webpack-plugin write-file-webpack-plugin
webpack
、 webpack-cli
、 webpack-dev-server
の説明は割愛します。
copy-webpack-plugin
が今回の主役です。名前の通り、webpackでの単純なファイルコピーを実現します.
また、 webpack-dev-server
を使うなら write-file-webpack-plugin
もあると楽ちんです。
通常 webpack-dev-server
の起動時、更新されたファイルはメモリ上でのみ展開されるのですが、 write-file-webpack-plugin
を使うことによって、実ファイルが更新されるようになるのです。
webpack.config.js
const CopyWebpackPlugin = require('copy-webpack-plugin')
const path = require('path');
const webpack = require('webpack');
const WriteFilePlugin = require('write-file-webpack-plugin');
module.exports = {
mode: process.env.NODE_ENV || "development",
watch: false,
watchOptions: {
ignored: /node_modules/
},
devtool: 'source-map',
output: {
path: path.join(__dirname, './dist/assets'),
publicPath: '/assets',
filename: 'js/[name].js'
},
plugins: [
new CopyWebpackPlugin(
[
{
from: '',
to: '../',
ignore: [
'!*.html'
]
},
],
{ context: 'src' }
),
new CopyWebpackPlugin(
[
{
from: '',
to: 'images/',
},
],
{ context: 'src/assets/images' }
),
new WriteFilePlugin(),
],
devServer: {
contentBase: path.resolve(__dirname, 'dist'),
port: 8080,
},
};
こうなります。
これだけの目的なら output
のpathはそうじゃなくてよくね?と思われそうですが、この webpack.config.js
はjsやcssをコンパイルする想定で書いています。
今回は見やすいようにjsやcssのloaderについての記述は省いています。
CopyWebpackPluginの設定
まずやりがちなのが、fromに src/**/*.html
とか書いちゃうことですが、そのように書くとコピーされた時 dist/src/index.html
のように from
のパスをすべて保ったまま吐き出されてしまいます。
最悪です。
さらに注意したいのが、 from
に **/*.html
のようにファイル形式を指定してしまうと、watc中に新規でファイルを追加した時にwebpackの監視対象から外れてしまいます。
その対策として、 from
は ''
とだけ書き、 context
と to
で何を対象とし、どこにコピーするかを記述する必要があります。
あと to
についての補足ですが、 to
は output
のpathの情報を引き継ぎます。
これらを踏まえた上で、画像とhtmlのコピーを例にとって設定方法を説明していきます。
例1: 画像のコピー
source: src/assets/images/**/*
dist: dist/assets/images/**/*
まず contextを設定しましょう。contextとは、fromの基準をどのパスとするかの設定です。
画像は dist/assets/images
に入る想定です。
そしてfromが ''
ということは、contextは src/assets/images
となりますね。
そして、toは output.pathの dist/assets
を基準パスとした時、 images/
になりますね。
つまり画像をコピーするための設定は
new CopyWebpackPlugin(
[
{
from: '',
to: 'images/',
},
],
{ context: 'src/assets/images' }
)
となります。
例2: htmlのコピー
source: src/**/*.html
dist: dist/**/*.html
まずconextを考えましょう. fromが ''
ということは、 contextは src
となります。
そして、to は output.pathの dist/assets
を基準パスとした時、 ../
になります。
ここまではいいのですが、このままだとどこにもファイル形式についての指定がないので、 src
の中身が そのまま dist
へ コピーされてしまいます。
そうではなく、htmlのみをコピーしたいので、 fromではないどこかにファイル形式の指定をする必要があります。
そこで、 ignore
の出番です。
ignore
は無視するファイルを glob形式で記述できるのですが、ここで html以外のような指定をすると、htmlだけがコピーされるようになります。
それらを合わせた結果、このような設定になります。
new CopyWebpackPlugin(
[
{
from: '',
to: '../',
ignore: [
'!*.html'
]
},
],
{ context: 'src' }
)
〆
このように、少し工夫した設定をすることで、無事gulp.distをCopyWebpackPluginで再現することができました。
果たしてこんなに頑張ってまでgulpから脱却する必要があるのかはいささか疑問ですが、それはそれとしましょう。