webpack3から4にアップデートしてみた

2020-01-04

年末に業務でwebpack3で動いてたものを4系にアップデートしたので時代遅れな話題かもだけどやったことを書いてみる。

何故アップデートしたの?

StorybookやJestなどを導入してみようと思ったときに、今の資産だと4系ではないからキツかったのが原因だ。あと、ローカル環境でのビルドも平均5秒程度掛かっており少し減らせないかなと考えやってみた。

webpack5の動向も気になる時期なのに何をやっているんだろう感もあるが。。

構成

CLIではないVue.jsを使用している。webpack自体はbaseのwebpackの他にSTG環境用、Prod環境用(本番)と存在している。

├── build/
│ ├── build.js # 本番環境で動かす
│ ├── check-versions.js # バージョンをチェックする
│ ├── staging.js # 結合環境で動かす
│ ├── vue-loader.conf.js # ヘッダーの通知のタイマー処理
│ ├── utils.js # cssのローディング周りの設定など
│ ├── webpack.base.conf.js # どの環境でもベースとなるwebpack
│ ├── webpack.dev.conf.js # npm scriptで最初に呼ばれるwebpack
│ ├── webpack.stg.conf.js # 結合環境でのwebpack
│ ├── webpack.prod.conf.js # 本番環境でのwebpack

STG環境と本番環境の違いはenvの部分が違うだけで後はほぼ一緒。

進め方

基本的には

  • webpackを4にバージョンアップする
  • babelのバージョンアップをする
  • その時出たエラーを解消していく

という手順になる。

先人の知恵があるので基本的には問題なく進められると思う。

お世話になった参照記事

次のリリースであるwebpack4の主な変更点まとめ

vue init webpackで作成したプロジェクトをwebpack4に移行する

基本この2つでエラーに対しては、Stack Overflowで検索すれば基本出てくる。

  1. webpack4からcliと機能が分離されているのでインストール
npm install webpack-cli --save-dev
  1. package.jsonのwebpackのバージョンを変更してupdate
"webpack": "^4.26.0"

この時vue-routerなどもupdateする。

  1. modeオプションを追加する。

webpack4からmodeオプションが追加されている。これで今までNODE_ENVで設定していたものが使わなくなる。また開発時はdevelopment、公開時はproductionにしてnpm scriptの記述も変える

npm script

"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"build": "node build/build.js webpack --mode=production",

webpack.prod.conf.js

mode: 'production',
  1. mini-css-extract-pluginの追加

webpack3まで使っていたextract-text-webpack-pluginは非推奨なためmini-css-extract-pluginをインストールして記述を変更する。

build/webpack.prod.conf.js

new MiniCssExtractPlugin({
  filename: utils.assetsPath('css/[name].[contenthash].css'),
  allChunks: true,
  ignoreOrder: true
}),

build/utils.js

const MiniCssExtractPlugin = require('mini-css-extract-plugin')
if (options.extract) {
  return ['vue-style-loader', MiniCssExtractPlugin.loader].concat(loaders)
} else {
  return ['vue-style-loader'].concat(loaders)
}
  1. optimization系の設定 mode指定している場合はminifyされるが、UglifyJsPluginを使用している場合はoptimization.minimizerの中に処理を移す必要がある。OptimizeCSSPluginも処理を移動する。

CommonsChunkPluginはv4だと削除となりSplitChunksPluginになっている

さらに、optimization.runtimeChunkを記述してmanifest.jsとして出力するように設定する。

optimization: {
    runtimeChunk: {
      name: 'manifest'
    },
    minimizer: [
      new UglifyJsPlugin({
        uglifyOptions: {
          compress: {
            warnings: false
          }
        },
        sourceMap: config.build.productionSourceMap,
        parallel: true
      }),
      new OptimizeCSSPlugin({
        cssProcessorOptions: config.build.productionSourceMap
          ? { safe: true, map: { inline: false } }
          : { safe: true }
      })
    ],
    splitChunks: {
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: "vendor",
          chunks: "all"
        }
      }
    }
  }
  1. VueLoaderPluginの追加 build/webpack.base.conf.jsに以下を追加する。
const VueLoaderPlugin = require('vue-loader/lib/plugin')
plugins: [
  new VueLoaderPlugin()
],

babelのバージョンアップ

babel6だったので7にアップデートしていく。参照記事は以下 https://babeljs.io/docs/en/v7-migration

上記を読んで何となく全体感を把握したがbabel7から懐疑的な変更が入っているため色々修正していく。

  1. 以下が必要だったのでインストールしていく。
npm install --save-dev @babel/core @babel/preset-env babel-loader
  1. webpackの記述を以下に修正する。
{
  test: /\.js$/,
  exclude: /node_modules/,
  use: [
    {
      loader: 'babel-loader',
    }
  ]
},
  1. .babelrcからbabel.config.jsに変更 babel.config.jsで以下を記述していく。.babelrcは削除する。
module.exports = function (api) {
  api.cache(true);

  const presets = [
    ["@babel/preset-env", {
      corejs: 3,
      modules: false,
      useBuiltIns: "usage"
    }]
  ];

  return {
    presets,
  };
}
  1. エントリーポイントのmain.jsにbabelをimportする。
import 'core-js/stable'
import 'regenerator-runtime/runtime'

IE11対応

これだけだと、IE11環境でエラーとなってしまい、表示できなかったのでbabel.config.jsのuseBuiltInsをentryに変更、targetsにie11を指定。

※entryを指定すると、全polyfillをimportしてしまうのでファイルサイズが肥大化してしまう。polyfill.ioなどに移行も検討する必要がある。

module.exports = function (api) {
  api.cache(true);

  const presets = [
    ["@babel/preset-env", {
      corejs: 3,
      modules: false,
      useBuiltIns: "entry",
      targets: {
        ie: 11
      }
    }]
  ];

  return {
    presets,
  };
}

これで完了だと思いきや今回のpackageの中のnode_modules内に.vueファイルがあり、その中の処理でアロー関数が使用されていたためIE11環境でSCRIPTエラーとなっていた。対象のpackageはvue-quill-editor

import {quillEditor as QuillEditor} from 'vue-quill-editor'

上記のimport先をnode_modules内のdist内にあるコンパイル済みのファイルに指定してあげることで解決。cssについてはコンパイルされていないので別でimportする必要があった。

import { quillEditor as QuillEditor } from 'vue-quill-editor/dist/vue-quill-editor'

import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'

vue-routerのバージョンアップで起きたエラー

3.1.1にアップデートしたところ以下のissueのエラーに出くわした。

https://github.com/vuejs/vue-router/issues/2872

router.pushする箇所で以前まではコールバックがない状態だとグローバルなrouterにエラーを送信していたが、3.1.1から個別のrouterにエラーが送られるようになったっぽい。実際にコンソールエラーが表示されていた。

これを解消するには、issueの通り以下を追加していく。

.catch(err => {})

これで解決した。検索とかするUIで何度も同じrouter.pushする箇所があると発生する。

感想

IE11対応すると途端につらくなる。ファイルサイズも大きくなるし。残対応としては次は、ファイルサイズを減らしていくチューニングする作業をしていく。


ソースコードはこちらのリポジトリにあります。

Google Analyticsを使っています。