Help us understand the problem. What is going on with this article?

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

pepoipod
エリア: S+2 / ヤグラ: S+0 / ホコ: S+0 / アサリ: S+0
http://pepoipod.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away