【Webpack4 備忘録】オススメ設定詰め合わせ

この記事はQiitaの記事をエクスポートしたものです。内容が古くなっている可能性があります。

備忘録で作成したもの以外に入れた方がいいもののまとめ。

以前、備忘録で作成した こちら に設定を追加する。

目次

ソースマップにオリジナルのソースコードを表示する

build時にhtmlファイルも生成する

スタイルシートを要素として出力する

大きい画像ファイルを別ファイルとして出力する

ビルドのたびにbuildディレクトリをクリーンアップする

プロダクション環境へのデプロイモジュールを小さくする

ESLintとPrettierを導入する

ソースマップにオリジナルのソースコードを表示する

デフォルト設定のソースマップは以下の通り。

このままだと、デバッグが捗らない。

webpack-c-0

開発環境で、ソースマップにオリジナルのソースコードを表示する設定を追加するには、webpackにdevtoolの設定を追加する必要がある。

実装

webpack.conf.jsに以下の設定を追加する。

// 中略 ...

module.exports = {
  // 中略 ...
  // ソースマップの設定(オリジナルのソースコードを出力、コメントも出力される)
  devtool: 'eval-source-map',
  // 中略 ...
};

変更後は、以下の通りオリジナルのソースコードが表示されるようになる。

webpack-c-1

これで多少はデバッグがしやすくなるはず。

参考

本家のドキュメントのdevtoolのところ

build時にhtmlファイルも生成する

以前作成したボイラープレートのままだと、buildディレクトリにHTMLファイルは生成されない。

html-webpack-pluginを使用することで、ビルドコマンドを実行するたびにbuildディレクトリにHTMLファイルを生成できるようになる。

html-webpack-plugin とは

webpackで生成したJavaScriptCSSを埋め込んだHTMLを生成できるプラグイン

ディレクトリごとデプロイしたい場合などに使える。

実装

プラグインをインストールする。

$ npm install -D html-webpack-plugin

webpack.config.jshtml-webpack-pluginを読み込む。

const htmlWebpackPlugin = require('html-webpack-plugin');

// 中略 ...
module.exports = {
  // 中略 ...
  
  plugins: [
    // filenameで指定したJSを読み込むHTMLファイルをbuildディレクトリに生成
    new htmlWebpackPlugin()
  ],

// 中略 ...
}

// 中略 ...

ビルドコマンドを実行して確認する。

$ npm run build

> react-ts-webpack@1.0.0 build /Users/kento/Programing/VScodeProjects/ts-react-sass-simple-boiler-v4
> webpack

Hash: f56cebd02a6bb3a59a34
Version: webpack 4.38.0
Time: 2598ms
Built at: 2019-12-02 18:44:16
     Asset       Size  Chunks             Chunk Names
 bundle.js    967 KiB    main  [emitted]  main
index.html  182 bytes          [emitted]  
Entrypoint main = bundle.js
[./node_modules/css-loader/dist/cjs.js?!./node_modules/postcss-loader/src/index.js!./node_modules/sass-loader/lib/loader.js!./src/scss-style.scss] ./node_modules/css-loader/dist/cjs.js??ref--5-1!./node_modules/postcss-loade
r/src!./node_modules/sass-loader/lib/loader.js!./src/scss-style.scss 506 bytes {main} [built]
[./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 472 bytes {main} [built]
[./src/assets/img/react.png] 31.3 KiB {main} [built]
[./src/assets/img/vue.png] 5.48 KiB {main} [built]
[./src/index.tsx] 810 bytes {main} [built]
[./src/scss-style.scss] 1.35 KiB {main} [built]
    + 15 hidden modules
Child html-webpack-plugin for "index.html":
     1 asset
    Entrypoint undefined = index.html
    [./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 472 bytes {0} [built]
    [./node_modules/webpack/buildin/module.js] (webpack)/buildin/module.js 497 bytes {0} [built]
        + 2 hidden modules

buildディレクトリにHTMLファイルが生成される。

$ tree ./build
./build
├── bundle.js
└── index.html

0 directories, 2 files

中身は、同階層のbundle.jsを読み込む設定で自動生成される。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Webpack App</title>
  </head>
  <body>
  <script type="text/javascript" src="bundle.js"></script></body>
</html>

スタイルシートを要素として出力する

style-loadercss-loaderを使用することで、<style>という要素を埋め込むことができるが、スタイルシートは別ファイルとして<link>要素で埋め込むのが一般的である。

別ファイルとして読み込むためには、style-loader ではなく extract-text-webpack-pluginを使用する。

extract-text-webpack-pluginとは

バンドルしたリソースをファイルとして切り出すためのプラグイン

実装

webpack用のプラグインをインストールする。

# latestバージョンでは、対応していないので @next をインストールする
$ npm install -D extract-text-webpack-plugin@next

webpack.config.jsプラグインを追加する。

const extTextPlugin = require('extract-text-webpack-plugin');

// 中略 ...

const rules = [
  /* Sass用設定 */
  {
    // 対象とする拡張子を指定
    test: /\.scss$/,
    // extract-text-webpack-plugin に use で指定しているloaderを加える
    use: extTextPlugin.extract([
      // linkタグへの出力用 
      // 'style-loader',  extract-text-webpack-plugin を使うので不要
      // CSSのバンドル設定
      {
        loader: 'css-loader',
        options: {
          // css内のurl()メソッドを取り込む設定
          url: true,
          // // ソースマップの有効化 development と production で勝手に切り替わるのでコメントアウト
          // sourceMap: true,

          // sass-loader と postcss-loader を使用するので 2 を設定
          // ここを参考に設定 https://github.com/webpack-contrib/css-loader#importloaders
          importLoaders: 2,
        },
      },
      'postcss-loader',
      {
        loader: 'sass-loader',
        // options: {
        // // ソースマップの有効化 development と production で勝手に切り替わるのでコメントアウト
        //   sourceMap: true,
        // }
      },
    ]),
  },
  
  // 中略 ...
  
];

module.exports = {
  // 中略 ...
  
  plugins: [
    // 出力ファイル名を指定
    new extTextPlugin('[name].css'),
  ],

// 中略 ...
}

// 中略 ...

ビルドコマンドを実行して確認する。

$ npm run build

> react-ts-webpack@1.0.0 build /Users/kento/Programing/VScodeProjects/ts-react-sass-simple-boiler-v5
> webpack

Hash: f7c0f22ec54908cad1c7
Version: webpack 4.38.0
Time: 2071ms
Built at: 2019-12-02 19:12:25
     Asset       Size  Chunks             Chunk Names
 bundle.js   2.29 MiB    main  [emitted]  main
index.html  221 bytes          [emitted]  
  main.css   5.68 KiB    main  [emitted]  main
Entrypoint main = bundle.js main.css
[./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 472 bytes {main} [built]
[./src/assets/img/react.png] 31.3 KiB {main} [built]
[./src/assets/img/vue.png] 5.48 KiB [built]
[./src/index.tsx] 1.22 KiB {main} [built]
[./src/scss-style.scss] 41 bytes [built]
[./src/style1.scss] 41 bytes [built]
[./src/style2.scss] 41 bytes [built]
    + 14 hidden modules
Child extract-text-webpack-plugin node_modules/extract-text-webpack-plugin/dist node_modules/css-loader/dist/cjs.js??ref--5-1!node_modules/postcss-loader/src/index.js!node_modules/sass-loader/lib/loader.js!src/scss-style.scss:
    Entrypoint undefined = extract-text-webpack-plugin-output-filename
    [./node_modules/css-loader/dist/cjs.js?!./node_modules/postcss-loader/src/index.js!./node_modules/sass-loader/lib/loader.js!./src/scss-style.scss] ./node_modules/css-loader/dist/cjs.js??ref--5-1!./node_modules/postcss-loader/src!./node_modules/sass-loader/lib/loader.js!./src/scss-style.scss 506 bytes {0} [built]
    [./src/assets/img/vue.png] 5.48 KiB {0} [built]
        + 2 hidden modules
Child extract-text-webpack-plugin node_modules/extract-text-webpack-plugin/dist node_modules/css-loader/dist/cjs.js??ref--5-1!node_modules/postcss-loader/src/index.js!node_modules/sass-loader/lib/loader.js!src/style1.scss:
    Entrypoint undefined = extract-text-webpack-plugin-output-filename
    [./node_modules/css-loader/dist/cjs.js?!./node_modules/postcss-loader/src/index.js!./node_modules/sass-loader/lib/loader.js!./src/style1.scss] ./node_modules/css-loader/dist/cjs.js??ref--5-1!./node_modules/postcss-loader/src!./node_modules/sass-loader/lib/loader.js!./src/style1.scss 169 bytes {0} [built]
        + 1 hidden module
Child extract-text-webpack-plugin node_modules/extract-text-webpack-plugin/dist node_modules/css-loader/dist/cjs.js??ref--5-1!node_modules/postcss-loader/src/index.js!node_modules/sass-loader/lib/loader.js!src/style2.scss:
    Entrypoint undefined = extract-text-webpack-plugin-output-filename
    [./node_modules/css-loader/dist/cjs.js?!./node_modules/postcss-loader/src/index.js!./node_modules/sass-loader/lib/loader.js!./src/style2.scss] ./node_modules/css-loader/dist/cjs.js??ref--5-1!./node_modules/postcss-loader/src!./node_modules/sass-loader/lib/loader.js!./src/style2.scss 169 bytes {0} [built]
        + 1 hidden module
Child html-webpack-plugin for "index.html":
     1 asset
    Entrypoint undefined = index.html
    [./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 472 bytes {0} [built]
    [./node_modules/webpack/buildin/module.js] (webpack)/buildin/module.js 497 bytes {0} [built]
        + 2 hidden modules

CSSファイルが別ファイルとして切り出されていることがわかる。

$ tree ./build
./build
├── bundle.js
├── index.html
└── main.css

0 directories, 3 files

./build/index.htmlにもLinkタグが追加されている。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Webpack App</title>
  <link href="main.css" rel="stylesheet"></head>
  <body>
  <script type="text/javascript" src="bundle.js"></script></body>
</html>

CSSとJSを別ファイルとすることで、並行してのダウンロードができるので、パフォーマンス改善も期待できる。

大きい画像ファイルを別ファイルとして出力する

ファビコンなどの小さい画像イメージならJSにバンドルしてもパフォーマンスに影響しないが、数百KBの画像ファイルをJSにバンドルすると、パフォーマンスが悪くなる。

file-loaderを使う

file-loaderを使うことで、一定以上の大きさの画像ファイルはそのまま画像ファイルとして保持できる。

実装

file-loaderをインストールする。

$ npm install -D file-loader

web pack.config.jsに設定を追加する。

// 中略 ...

const rules = [
  // 中略 ...

  /* 画像ファイル用設定 */
  {
    // 対象となるファイルの拡張子を設定
    test: /\.(gif|png|jpg|jpeg|svg|ttf|eot|wof|woff|woff2)$/,
    // 画像をBase64で取り込み
    loader: 'url-loader',

    //// ↓ 追加 
    // 画像ファイルに関するオプション
    options: {
      // 20KB以上を対象とする(バイナリ換算)
      // https://www.gbmb.org/kb-to-bytes で正確な値を調べる
      limit: 20480,
      // ファイルのアウトプット場所 名前は保持
      name: "./images/[name].[ext]"
    }
  },
];

// 中略 ...

ビルドコマンドを実行して確認する。

$ npm run build

> react-ts-webpack@1.0.0 build /Users/kento/Programing/VScodeProjects/ts-react-sass-simple-boiler-v5
> webpack

Hash: c6425b45d4a5dcfdf726
Version: webpack 4.38.0
Time: 2676ms
Built at: 2019-12-02 19:36:26
             Asset       Size  Chunks             Chunk Names
./images/react.png   23.5 KiB          [emitted]  
         bundle.js   2.22 MiB    main  [emitted]  main
        index.html  221 bytes          [emitted]  
          main.css   5.68 KiB    main  [emitted]  main
Entrypoint main = bundle.js main.css
[./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 472 bytes {main} [built]
[./src/assets/img/react.png] 62 bytes {main} [built]
[./src/assets/img/vue.png] 5.48 KiB [built]
[./src/index.tsx] 1.22 KiB {main} [built]
[./src/scss-style.scss] 41 bytes [built]
[./src/style1.scss] 41 bytes [built]
[./src/style2.scss] 41 bytes [built]
    + 14 hidden modules
Child extract-text-webpack-plugin node_modules/extract-text-webpack-plugin/dist node_modules/css-loader/dist/cjs.js??ref--5-1!node_modules/postcss-loader/src/index.js!node_modules/sass-loader/lib/loader.js!src/scss-style.scss:
    Entrypoint undefined = extract-text-webpack-plugin-output-filename
    [./node_modules/css-loader/dist/cjs.js?!./node_modules/postcss-loader/src/index.js!./node_modules/sass-loader/lib/loader.js!./src/scss-style.scss] ./node_modules/css-loader/dist/cjs.js??ref--5-1!./node_modules/postcss-loader/src!./node_modules/sass-loader/lib/loader.js!./src/scss-style.scss 506 bytes {0} [built]
    [./src/assets/img/vue.png] 5.48 KiB {0} [built]
        + 2 hidden modules
Child extract-text-webpack-plugin node_modules/extract-text-webpack-plugin/dist node_modules/css-loader/dist/cjs.js??ref--5-1!node_modules/postcss-loader/src/index.js!node_modules/sass-loader/lib/loader.js!src/style1.scss:
    Entrypoint undefined = extract-text-webpack-plugin-output-filename
    [./node_modules/css-loader/dist/cjs.js?!./node_modules/postcss-loader/src/index.js!./node_modules/sass-loader/lib/loader.js!./src/style1.scss] ./node_modules/css-loader/dist/cjs.js??ref--5-1!./node_modules/postcss-loader/src!./node_modules/sass-loader/lib/loader.js!./src/style1.scss 169 bytes {0} [built]
        + 1 hidden module
Child extract-text-webpack-plugin node_modules/extract-text-webpack-plugin/dist node_modules/css-loader/dist/cjs.js??ref--5-1!node_modules/postcss-loader/src/index.js!node_modules/sass-loader/lib/loader.js!src/style2.scss:
    Entrypoint undefined = extract-text-webpack-plugin-output-filename
    [./node_modules/css-loader/dist/cjs.js?!./node_modules/postcss-loader/src/index.js!./node_modules/sass-loader/lib/loader.js!./src/style2.scss] ./node_modules/css-loader/dist/cjs.js??ref--5-1!./node_modules/postcss-loader/src!./node_modules/sass-loader/lib/loader.js!./src/style2.scss 169 bytes {0} [built]
        + 1 hidden module
Child html-webpack-plugin for "index.html":
     1 asset
    Entrypoint undefined = index.html
    [./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 472 bytes {0} [built]
    [./node_modules/webpack/buildin/module.js] (webpack)/buildin/module.js 497 bytes {0} [built]
        + 2 hidden modules

vue.pngはないが20KB以上のreact.pngは存在する。 (react.pngは約25KBの画像ファイル)

$ tree ./build
./build
├── bundle.js
├── images
│   └── react.png
├── index.html
└── main.css

1 directory, 4 files

ビルドのたびにbuildディレクトリをクリーンアップする

clean-webpack-pluginを追加することで、ビルド先のディレクトリをビルド前にクリーンアップできる。(versionは3系を使用)

実装

clean-webpack-pluginをインストールする。

$ npm install -D clean-webpack-plugin

webpack.config.jsに設定を追加する。

outputオプションで指定したディレクトリがクリーンアップ対象となる。

// 中略 ...
const {CleanWebpackPlugin} = require('clean-webpack-plugin');

// 中略 ...

module.exports = {
  // 中略 ...

  // 各種プラグイン
  plugins: [
    // ここでは、buildディレクトリをビルド前にクリーンアップ
    new CleanWebpackPlugin(),
  ],

  // 中略 ...
};

確認用にtext.txtを配置

$ $ tree ./build
./build
├── bundle.js
├── images
│   └── react.png
├── index.html
├── main.css
└── test.txt  ← ここ

1 directory, 5 files

ビルドコマンドを実行して確認する。

$ npm run build

> react-ts-webpack@1.0.0 build /Users/kento/Programing/VScodeProjects/ts-react-sass-simple-boiler-v5
> webpack

Hash: c6425b45d4a5dcfdf726
Version: webpack 4.38.0
Time: 2772ms
Built at: 2019-12-03 09:38:26
             Asset       Size  Chunks             Chunk Names
./images/react.png   23.5 KiB          [emitted]  
         bundle.js   2.22 MiB    main  [emitted]  main
        index.html  221 bytes          [emitted]  
          main.css   5.68 KiB    main  [emitted]  main
Entrypoint main = bundle.js main.css
[./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 472 bytes {main} [built]
[./src/assets/img/react.png] 62 bytes {main} [built]
[./src/assets/img/vue.png] 5.48 KiB [built]
[./src/index.tsx] 1.22 KiB {main} [built]
[./src/scss-style.scss] 41 bytes [built]
[./src/style1.scss] 41 bytes [built]
[./src/style2.scss] 41 bytes [built]
    + 14 hidden modules
Child extract-text-webpack-plugin node_modules/extract-text-webpack-plugin/dist node_modules/css-loader/dist/cjs.js??ref--5-1!node_modules/postcss-loader/src/index.js!node_modules/sass-loader/lib/loader.js!src/scss-style.scss:
    Entrypoint undefined = extract-text-webpack-plugin-output-filename
    [./node_modules/css-loader/dist/cjs.js?!./node_modules/postcss-loader/src/index.js!./node_modules/sass-loader/lib/loader.js!./src/scss-style.scss] ./node_modules/css-loader/dist/cjs.js??ref--5-1!./node_modules/postcss-loader/src!./node_modules/sass-loader/lib/loader.js!./src/scss-style.scss 506 bytes {0} [built]
    [./src/assets/img/vue.png] 5.48 KiB {0} [built]
        + 2 hidden modules
Child extract-text-webpack-plugin node_modules/extract-text-webpack-plugin/dist node_modules/css-loader/dist/cjs.js??ref--5-1!node_modules/postcss-loader/src/index.js!node_modules/sass-loader/lib/loader.js!src/style1.scss:
    Entrypoint undefined = extract-text-webpack-plugin-output-filename
    [./node_modules/css-loader/dist/cjs.js?!./node_modules/postcss-loader/src/index.js!./node_modules/sass-loader/lib/loader.js!./src/style1.scss] ./node_modules/css-loader/dist/cjs.js??ref--5-1!./node_modules/postcss-loader/src!./node_modules/sass-loader/lib/loader.js!./src/style1.scss 169 bytes {0} [built]
        + 1 hidden module
Child extract-text-webpack-plugin node_modules/extract-text-webpack-plugin/dist node_modules/css-loader/dist/cjs.js??ref--5-1!node_modules/postcss-loader/src/index.js!node_modules/sass-loader/lib/loader.js!src/style2.scss:
    Entrypoint undefined = extract-text-webpack-plugin-output-filename
    [./node_modules/css-loader/dist/cjs.js?!./node_modules/postcss-loader/src/index.js!./node_modules/sass-loader/lib/loader.js!./src/style2.scss] ./node_modules/css-loader/dist/cjs.js??ref--5-1!./node_modules/postcss-loader/src!./node_modules/sass-loader/lib/loader.js!./src/style2.scss 169 bytes {0} [built]
        + 1 hidden module
Child html-webpack-plugin for "index.html":
     1 asset
    Entrypoint undefined = index.html
    [./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 472 bytes {0} [built]
    [./node_modules/webpack/buildin/module.js] (webpack)/buildin/module.js 497 bytes {0} [built]
        + 2 hidden modules

buildディレクトリを削除して、再作成するためtest.txtは存在しない。

$ tree ./build
./build
├── bundle.js
├── images
│   └── react.png
├── index.html
└── main.css

1 directory, 4 files

プロダクション環境へのデプロイモジュールを小さくする

ビルドコマンドでproductionを指定している場合、ソースコードは最適化されるが、一部不要なコードやCSSの最適化までは行われない。

uglifyjs-webpack-pluginoptimize-css-assets-webpack-pluginで最適化できる。

uglifyjs-webpack-pluginとは

プロダクション環境で関数を除去できるプラグイン

例えば、本番環境では、console.log()は必要ないから削除したいなど。

実装

uglifyjs-webpack-pluginをインストールする。

$ npm install -D uglifyjs-webpack-plugin

webpack.config.jsに設定を追加する。

// 中略 ...
const uglifyJsPlugin = require('uglifyjs-webpack-plugin');

// 中略 ...

module.exports = {
  // 中略 ...

  // プロダクション環境での設定(minimizer)
  optimization: {
    minimizer: [
      new uglifyJsPlugin({
        uglifyOptions: {
          compress: {
            // console.log() console.table()等除去
            drop_console: true
          }
        }
      })
    ]
  },
  
  // 中略 ...
};

optimize-css-assets-webpack-pluginとは

XXX.min.cssのように改行などを削除したCSSを出力できるプラグイン

実装

optimize-css-assets-webpack-pluginをインストールする。

$ npm install -D optimize-css-assets-webpack-plugin

web pack.config.jsに設定を追加する。

// 中略 ...

// uglifyjs-webpack-pluginは必須
const uglifyJsPlugin = require('uglifyjs-webpack-plugin');
const optimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');

// 中略 ...

module.exports = {
  // 中略 ...

  // プロダクション環境での設定(minimizer)
  optimization: {
    minimizer: [
      // 必須
      new uglifyJsPlugin({
        // 省略 ...
      }),
      // スタイルシートの圧縮設定
      new optimizeCssAssetsPlugin({}),
    ]
  },
  
  // 中略 ...
};

変更前

$ npm run build-prod

> react-ts-webpack@1.0.0 build-prod /Users/kento/Programing/VScodeProjects/ts-react-sass-simple-boiler-v5
> webpack --mode=production

Hash: f2a87911c7157885324e
Version: webpack 4.38.0
Time: 2916ms
Built at: 2019-12-03 10:22:04
             Asset       Size  Chunks                    Chunk Names
./images/react.png   23.5 KiB          [emitted]         
         bundle.js    336 KiB       0  [emitted]  [big]  main
        index.html  221 bytes          [emitted]         
          main.css   5.68 KiB       0  [emitted]         main  ← ここ


中略 ...

変更後

$ npm run build-prod

> react-ts-webpack@1.0.0 build-prod /Users/kento/Programing/VScodeProjects/ts-react-sass-sim
ple-boiler-v5
> webpack --mode=production

Hash: f2a87911c7157885324e
Version: webpack 4.38.0
Time: 2357ms
Built at: 2019-12-03 10:20:39
             Asset       Size  Chunks                    Chunk Names
./images/react.png   23.5 KiB          [emitted]         
         bundle.js    336 KiB       0  [emitted]  [big]  main
        index.html  221 bytes          [emitted]         
          main.css   5.63 KiB       0  [emitted]         main  ← ここ

中略 ...

変更後の方がCSSファイルのサイズが小さくなる。

ESLintとPrettierを導入する

構文解析を実装するため、ESLintとPrettierを使用する。

実装

exlintprettierとその他必要なプラグインをインストールする。

$ npm install -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin prettier eslint-plugin-prettier eslint-config-prettier

プロジェクトルートに.eslintrcを作成する。

{
  "parser": "@typescript-eslint/parser",
  "extends": [
    "plugin:@typescript-eslint/recommended",
    "plugin:prettier/recommended",
    "prettier/@typescript-eslint"
  ],
  "rules": {
    "prettier/prettier": [
      "error",
      {
        "singleQuote": true,
        "semi": true,
        "no-var-requires": true
      }
    ]
  }
}

package.jsonスクリプトを追加する。

{
  // 中略 ...

  "scripts": {
    // 中略 ...

    "lint": "eslint --fix --ext .tsx,.ts ./src",
    "type-check": "tsc"

  },

  // 中略 ...
}


今回作成したものは こちら