30
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

updated at

gulp.distをCopyWebpackPluginで再現する

近年ただのモジュールバンドラであるはずの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から脱却する必要があるのかはいささか疑問ですが、それはそれとしましょう。

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
30
Help us understand the problem. What are the problem?