webpack3からwebpack4へ移行した時の手順

まだ大したことやってないのでそれほどでもなかった。





コマンドラインツールwebpack-cliをインストールする



webpackの実行にwebpack-cliが必要になった。正確にいうと分離した。

webpackコマンド実行時に表示されるので詰まることはないはず。
npm install --save-dev webpack webpack-cli



開発用、本番用の取扱いが変更された



以前は本番用などに値を渡してconfigファイルで切り替えていた。
NODE_ENV=development $(npm bin)/webpack

ただのwebpackコマンドでは下記エラーが発生するようになっている。
WARNING in configuration
The 'mode' option has not been set. Set 'mode' option to 'development' or 'production' to enable defaults for this environment.

--mode オプションを使用して開発用、本番用を分ける。
$(npm bin)/webpack --mode development
$(npm bin)/webpack --mode production

developmentが開発用
productionが本番用



Module build failed: TypeError: Cannot read property 'xxxx' of undefined




ERROR in ./public/javascripts/index.ts
Module build failed: TypeError: Cannot read property 'tslint' of undefined
at resolveOptions (/Users/[username]/Project/i/SearchI/node_modules/tslint-loader/index.js:24:47)
at Object.module.exports (/Users/[username]/Project/i/SearchI/node_modules/tslint-loader/index.js:139:17)

ERROR in ./public/javascripts/f_index.ts
Module build failed: TypeError: Cannot read property 'ts' of undefined
at getLoaderOptions (/Users/shinichiyamada/Project/i/SearchI/node_modules/ts-loader/dist/index.js:70:43)
at Object.loader (/Users/shinichiyamada/Project/i/SearchI/node_modules/ts-loader/dist/index.js:23:19)

ローダが削除されたオプションにアクセスしようとしているらしい。
ググってみると結構いろいろ見る。おそらくまだ対応しきれていないということだろう。
tslint-loaderは最新にすればいける
肝心のts-loaderがまだ未対応?
→ メジャーバージョンが上がっただけだった。
3から4に変更。

ローダー周りでそこそこ出ているようなので対応していない場合はオプションを空で指定すればいける?
https://github.com/webpack/webpack/issues/6556

module.exports.plugins = (module.exports.plugins || []).concat([
    new webpack.LoaderOptionsPlugin({
      options: {}
    }),
  ])



プラグインが使用できなくなっている



hard-source-webpack-plugin が使用できなくなっている
Plugin could not be registered at 'hard-source-cache-factory'. Hook was not found.

記事を書いて公開するまでの間に対応されていた。

もし利用しているプラグインが動かなくなったら対応するまで待つか自分で対応するか別のものを使用するか。



TypeError: webpack.optimize.UglifyJsPlugin is not a constructor



modeオプションで開発用と本番用を指定するようになったので最適化を指定する必要は無くなったということらしい。



設定ファイル例



一例
VueとTypeScript以外は特に使用していない比較的シンプル?な構成。
Vue自体は別途外部から別途読み込む。
thread-loaderを使用している(使い方がこれ出会ってるかちょっと自信がない)
SPAにあまり興味が無いので機能単位(index,second)で画面を分けるようにしている。
output.filenameの[name]が置き換えられて、
'./public/javascripts/dist/index.built.js'と'./public/javascripts/dist/second.built.js'ができる。

var path = require('path')
var webpack = require('webpack')
var HardSourceWebpackPlugin = require('hard-source-webpack-plugin')

module.exports = {
  entry: {
    index: './public/javascripts/index.ts',
    second: './public/javascripts/second.ts',
  },
  output: {
    path: path.resolve(__dirname, './public/javascripts/dist'),
    publicPath: '/dist/',
    filename: '[name].built.js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        include: path.resolve("src"),
        use: [
          {
            loader: "thread-loader",
            options: {
              workers: require('os').cpus().length - 1,
            }
          }
          // your expensive loader (e.g babel-loader)
        ]
      },
      {
        enforce: 'pre',
        test: /\.ts$/,
        loader: 'tslint-loader',
        exclude: /(node_modules)/,
        options: {
          configFile: 'tslint.json'
        }
      },
      {
        test: /\.ts$/,
        exclude: /node_modules|vue\/src/,
        loader: 'ts-loader',
        options: {
          appendTsSuffixTo: [/\.vue$/],
          transpileOnly: true
        }
      },
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: {
          loaders: {
            // Since sass-loader (weirdly) has SCSS as its default parse mode, we map
            // the "scss" and "sass" values for the lang attribute to the right configs here.
            // other preprocessors should work out of the box, no loader config like this necessary.
            // 'scss': 'vue-style-loader!css-loader!sass-loader',
            // 'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax',
            'ts': 'ts-loader!tslint-loader',
          }
          // other vue-loader options go here
        }
      }
      // {
      //   test: /\.tsx?$/,
      //   loader: 'ts-loader',
      //   exclude: /node_modules/,
      //   options: {
      //     appendTsSuffixTo: [/\.vue$/],
      //   }
      // },
      // {
      //   test: /\.(png|jpg|gif|svg)$/,
      //   loader: 'file-loader',
      //   options: {
      //     name: '[name].[ext]?[hash]'
      //   }
      // }
    ]
  },
  resolve: {
    extensions: ['.ts', '.js', '.vue', '.json'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js'
    }
  },
  devServer: {
    historyApiFallback: true,
    noInfo: true
  },
  externals: {
    "vue": "Vue"
  },
  cache: true,
  performance: {
    hints: false
  },
  devtool: '#eval-source-map'
}

module.exports.plugins = (module.exports.plugins || []).concat([
  new HardSourceWebpackPlugin(),
])




後は設定ファイルが不要になったとか (ざっと調べた感じwebpackコマンドのオプションがやたら長くなるので微妙)
移行する場合は既存のものがあると思うのでそれを流用した方が楽かと。
この手の依存先(webpack)に大きな更新があった場合、(loaderの)メジャーバージョンを変更するのが正しいやり方だろうか?(ts-loaderしかやってない気がするけど)


2018年3月9日金曜日