Edited at

gulp.distをCopyWebpackPluginで再現する

More than 1 year has passed since last update.

近年ただのモジュールバンドラであるはずの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

webpackwebpack-cliwebpack-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'' とだけ書き、 contextto で何を対象とし、どこにコピーするかを記述する必要があります。

あと to についての補足ですが、 tooutputの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から脱却する必要があるのかはいささか疑問ですが、それはそれとしましょう。