Webpackを1系から2系に移行する


## webpack2系の正式版がリリース

2017年1月にwebpack 2.xの正式版としてwebpack v2.2がリリースされた。

* [2017-01-24のJS: webpack 2正式リリース、JavaScriptの開発環境設定、2016 JS Stars - JSer.info](https://jser.info/2017/01/24/webpack-2-javascript-2016-js-star/)
* [🎉 webpack 2.2: The Final Release 🎉 – webpack – Medium](https://medium.com/webpack/webpack-2-2-the-final-release-76c3d43bf144#.tzdlg4cpd)	
* [Release v2.2.0 · webpack/webpack](https://github.com/webpack/webpack/releases/tag/v2.2.0)

webpack1系から2系に移行する際の手順を示す。
development環境はHMRで、production環境は`ExtractTextPlugin`でcssファイルを書き出す設定をしている人向け。
`postcss-import`を使っている人は注意。

## yarn upgrade webpack

まずは、webpackのバージョンのupgradeを行う。
同時に1系に依存しているパッケージもupgradeを行う。

```console:console
$ yarn upgrade webpack webpack-dev-server extract-text-webpack-plugin
```

```diff:package.json
-    "extract-text-webpack-plugin": "^1.0.1",
+    "extract-text-webpack-plugin": "^2.1.0",
-    "webpack": "^1.14.0",
-    "webpack-dev-server": "^1.16.2",
+    "webpack": "^2.2.1",
+    "webpack-dev-server": "^2.4.1",
```

## webpack.configの書き換え

下記に従って、webpack.configを書き換えていく。
`rules`と`use`を使うようにapiが修正された。

[Migrating from v1 to v2](https://webpack.js.org/guides/migrating/)

```diff:webpack.config.js
resolve: {
- extensions: ['', '.js', '.jsx'],
+ extensions: ['.js', '.jsx'],
  alias: {
    react: path.resolve('./node_modules/react'),
    'react-dom': path.resolve('./node_modules/react-dom'),
  },
},
module: {
- loaders: [
+ rules: [
    {
      test: /\.jsx?$/,
-     loader: 'babel-loader',
+     use: 'babel-loader',
      exclude: /node_modules/,
    },
    {
      test: /\.css$/,
-     loaders: [
+     use: [
        'css-loader/locals?modules&localIdentName=[name]--[local]--[hash:base64:5]',
        'postcss-loader',
      ],
    },
  ],
},
```

また、production向けに`ExtractTextPlugin`を使っている箇所は

```diff:webpack.config.js
- loader: ExtractTextPlugin.extract(
-   'style-loader',
-   ['css-loader?modules&localIdentName=[name]--[local]--[hash:base64:5]', 'postcss-loader']
- ),
+ use: ExtractTextPlugin.extract({
+   fallback: 'style-loader',
+   use: ['css-loader?modules&localIdentName=[name]--[local]--[hash:base64:5]', 'postcss-loader']
+ }),
```

このように書き換える

## PostCSS周り

`postcss.config.js`を作成する

```diff:webpack.config.js
-const postcssImport = require('postcss-import')
-const postcssCssnext = require('postcss-cssnext')
-const cssnano = require('cssnano')

...

-  postcss() {
-    return [postcssImport, postcssCssnext, cssnano]
-  },
```

```diff:postcss.config.js
+const postcssImport = require('postcss-smart-import')
+const postcssCssnext = require('postcss-cssnext')
+const cssnano = require('cssnano')
+
+module.exports = {
+  plugins: [
+    postcssImport, postcssCssnext, cssnano
+  ]
+}
```

postcss-importがwebpack2系でのHMRに対応していないようで、`webpack-dev-server --hot`している最中にcssを書き換えると、下記エラーが出る

```console:console
ERROR in ./~/css-loader?modules&localIdentName=[name]--[local]--[hash:base64:5]!./~/postcss-loader!./app/assets/styles/test.css
Module build failed: (SystemJS) ENOENT: no such file or directory, open '/Users/kikunantoka/repository/application/client/node_modules/css-loader/lib/loader'
```

[Doesn't compiles css · Issue #106 · postcss/postcss-loader](https://github.com/postcss/postcss-loader/issues/106)

`{ addDependencyTo: webpack }`を加える方法で対応していたようだが、postcss-loaderのexampleをみると、`postcss-smart-import`が推奨されているので、`postcss-import`から`postcss-smart-import`に乗り換えた

```console:console
$ yarn remove postcss-import
$ yarn add postcss-smart-import
```

```diff:package.json
-    "postcss-import": "^9.1.0",
     "postcss-loader": "^1.3.3",
+    "postcss-smart-import": "^0.6.9",
```

## 動作確認
development環境でのHMRもproduction環境向けの`ExtractTextPlugin`によるcssの吐き出しも成功しました🎉
webpack2系への移行を考えている方の参考になれば幸いです。