2年前に作ったBabel6、Vue2.5.2のプロジェクトを動くようにする

# 2年前に作ったBabel6、Vue2.5.2のプロジェクトのビルドが通らない!!
昔作ったVueのプロジェクトをcloneしてきて動かそうとしてみたら、`npm install`も`npm run dev`も通らない！！！
本記事では、`npm run dev`の成功、つまり開発用サーバが正常に立ち上がるまでに、場当たり的に設定ファイルを祈りながら編集し、成功するまでを記録したものである。

diffの結果やコマンドの結果をベタッと貼ってしまっているため読みにくいとは思うが、ご容赦願いたい。

レポジトリは[これ](https://github.com/morimolymoly/dead-github.io)である。
関連するcommitは

* [commit1](https://github.com/morimolymoly/dead-github.io/commit/ba60287721e546cf3034d3c76807eea121a91fea)
* [commit2](https://github.com/morimolymoly/dead-github.io/commit/64c89385c0acb50d2f2ae355c970f0b7e5bc98a7)

である。

# 調査
package.jsonをみてみる。
依存パッケージが大変古いことがわかる。

```json
{
  "scripts": {
    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
  },
  "dependencies": {
    "vue": "^2.5.2",
    "vue-router": "^3.0.1"
  },
  "devDependencies": {
    "autoprefixer": "^7.1.2",
    "babel-core": "^6.22.1",
    "babel-eslint": "^8.2.1",
    "babel-helper-vue-jsx-merge-props": "^2.0.3",
    "babel-jest": "^21.0.2",
    "babel-loader": "^7.1.1",
    "babel-plugin-dynamic-import-node": "^1.2.0",
    "babel-plugin-syntax-jsx": "^6.18.0",
    "babel-plugin-transform-es2015-modules-commonjs": "^6.26.0",
    "babel-plugin-transform-runtime": "^6.22.0",
    "babel-plugin-transform-vue-jsx": "^3.5.0",
    "babel-preset-env": "^1.3.2",
    "babel-preset-stage-2": "^6.22.0",
    "babel-register": "^6.22.0",
    "chalk": "^2.0.1",
    "chromedriver": "^2.27.2",
    "copy-webpack-plugin": "^4.0.1",
    "cross-spawn": "^5.0.1",
    "css-loader": "^0.28.0",
    "eslint": "^4.15.0",
    "eslint-config-standard": "^10.2.1",
    "eslint-friendly-formatter": "^3.0.0",
    "eslint-loader": "^1.7.1",
    "eslint-plugin-import": "^2.7.0",
    "eslint-plugin-node": "^5.2.0",
    "eslint-plugin-promise": "^3.4.0",
    "eslint-plugin-standard": "^3.0.1",
    "eslint-plugin-vue": "^4.0.0",
    "extract-text-webpack-plugin": "^3.0.0",
    "file-loader": "^1.1.4",
    "friendly-errors-webpack-plugin": "^1.6.1",
    "html-webpack-plugin": "^2.30.1",
    "jest": "^22.0.4",
    "jest-serializer-vue": "^0.3.0",
    "nightwatch": "^0.9.12",
    "node-notifier": "^5.1.2",
    "node-sass": "^4.7.2",
    "optimize-css-assets-webpack-plugin": "^3.2.0",
    "ora": "^1.2.0",
    "portfinder": "^1.0.13",
    "postcss-import": "^11.0.0",
    "postcss-loader": "^2.0.8",
    "postcss-url": "^7.2.1",
    "rimraf": "^2.6.0",
    "sass-loader": "^6.0.6",
    "selenium-server": "^3.0.1",
    "semver": "^5.3.0",
    "shelljs": "^0.7.6",
    "uglifyjs-webpack-plugin": "^1.1.1",
    "url-loader": "^0.5.8",
    "vue-jest": "^1.0.2",
    "vue-loader": "^13.3.0",
    "vue-style-loader": "^3.0.1",
    "vue-template-compiler": "^2.5.2",
    "webpack": "^3.6.0",
    "webpack-bundle-analyzer": "^2.9.0",
    "webpack-dev-server": "^2.9.1",
    "webpack-merge": "^4.1.0"
  },
  "engines": {
    "node": ">= 6.0.0",
    "npm": ">= 3.0.0"
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 8"
  ]
}
```

# パッケージを一新する
`npm-check-updates`コマンドをグローバルインストールする。

```sh
npm install -g npm-check-updates
```

先程インストールした`npm-check-updates`コマンドで古いパッケージを一新する。
このコマンドは`package.json`に直接作用する。


```sh
☻  ncu -u
Upgrading /Users/mizuho/work/dead-github.io/package.json
[====================] 60/60 100%

 vue                                              ^2.5.2  →    ^2.6.11
 vue-router                                       ^3.0.1  →     ^3.1.6
 autoprefixer                                     ^7.1.2  →     ^9.7.6
 babel-core                                      ^6.22.1  →    ^6.26.3
 babel-eslint                                     ^8.2.1  →    ^10.1.0
 babel-jest                                      ^21.0.2  →    ^25.3.0
 babel-loader                                     ^7.1.1  →     ^8.1.0
 babel-plugin-dynamic-import-node                 ^1.2.0  →     ^2.3.0
 babel-plugin-transform-es2015-modules-commonjs  ^6.26.0  →    ^6.26.2
 babel-plugin-transform-runtime                  ^6.22.0  →    ^6.23.0
 babel-plugin-transform-vue-jsx                   ^3.5.0  →     ^3.7.0
 babel-preset-env                                 ^1.3.2  →     ^1.7.0
 babel-preset-stage-2                            ^6.22.0  →    ^6.24.1
 babel-register                                  ^6.22.0  →    ^6.26.0
 chalk                                            ^2.0.1  →     ^4.0.0
 chromedriver                                    ^2.27.2  →    ^81.0.0
 copy-webpack-plugin                              ^4.0.1  →     ^5.1.1
 cross-spawn                                      ^5.0.1  →     ^7.0.2
 css-loader                                      ^0.28.0  →     ^3.5.2
 eslint                                          ^4.15.0  →     ^6.8.0
 eslint-config-standard                          ^10.2.1  →    ^14.1.1
 eslint-friendly-formatter                        ^3.0.0  →     ^4.0.1
 eslint-loader                                    ^1.7.1  →     ^4.0.0
 eslint-plugin-import                             ^2.7.0  →    ^2.20.2
 eslint-plugin-node                               ^5.2.0  →    ^11.1.0
 eslint-plugin-promise                            ^3.4.0  →     ^4.2.1
 eslint-plugin-standard                           ^3.0.1  →     ^4.0.1
 eslint-plugin-vue                                ^4.0.0  →     ^6.2.2
 extract-text-webpack-plugin                      ^3.0.0  →     ^3.0.2
 file-loader                                      ^1.1.4  →     ^6.0.0
 friendly-errors-webpack-plugin                   ^1.6.1  →     ^1.7.0
 html-webpack-plugin                             ^2.30.1  →     ^4.2.0
 jest                                            ^22.0.4  →    ^25.3.0
 jest-serializer-vue                              ^0.3.0  →     ^2.0.2
 nightwatch                                      ^0.9.12  →     ^1.3.4
 node-notifier                                    ^5.1.2  →     ^7.0.0
 node-sass                                        ^4.7.2  →    ^4.13.1
 optimize-css-assets-webpack-plugin               ^3.2.0  →     ^5.0.3
 ora                                              ^1.2.0  →     ^4.0.3
 portfinder                                      ^1.0.13  →    ^1.0.25
 postcss-import                                  ^11.0.0  →    ^12.0.1
 postcss-loader                                   ^2.0.8  →     ^3.0.0
 postcss-url                                      ^7.2.1  →     ^8.0.0
 rimraf                                           ^2.6.0  →     ^3.0.2
 sass-loader                                      ^6.0.6  →     ^8.0.2
 selenium-server                                  ^3.0.1  →  ^3.141.59
 semver                                           ^5.3.0  →     ^7.2.2
 shelljs                                          ^0.7.6  →     ^0.8.3
 uglifyjs-webpack-plugin                          ^1.1.1  →     ^2.2.0
 url-loader                                       ^0.5.8  →     ^4.1.0
 vue-jest                                         ^1.0.2  →     ^3.0.5
 vue-loader                                      ^13.3.0  →    ^15.9.1
 vue-style-loader                                 ^3.0.1  →     ^4.1.2
 vue-template-compiler                            ^2.5.2  →    ^2.6.11
 webpack                                          ^3.6.0  →    ^4.42.1
 webpack-bundle-analyzer                          ^2.9.0  →     ^3.6.1
 webpack-dev-server                               ^2.9.1  →    ^3.10.3
 webpack-merge                                    ^4.1.0  →     ^4.2.2

Run npm install to install new versions.
```

# babelを7に一新する。
babel6からbabel7へのマイグレーションコマンド`babel-upgrade`を使う。
これを実行すると、`package.json`と`.babelrc`に直接作用し、babel7用にマイグレーションされる。

```sh
☻  npm i -g babel-upgrade
☻  babel-upgrade --write --install
```

# npm audit fix & npm install & 足りないパッケージをインストールする

`npm audit fix`で脆弱性のあるパッケージをアップデートし、`npm install`でパッケージをインストールする。

```sh
☻  npm audit fix
省略
☻  npm install
npm WARN ajv-keywords@3.4.1 requires a peer of ajv@^6.9.1 but none is installed. You must install peer dependencies yourself.
npm WARN extract-text-webpack-plugin@3.0.2 requires a peer of webpack@^3.1.0 but none is installed. You must install peer dependencies yourself.

audited 263641 packages in 9.355s

50 packages are looking for funding
  run `npm fund` for details

found 3 vulnerabilities (2 low, 1 moderate)
  run `npm audit fix` to fix them, or `npm audit` for details
```

`npm run dev`コマンドを実行してみる。


```sh

☻  npm run dev

> moly333@1.0.0 dev /Users/mizuho/work/dead-github.io
> webpack-dev-server --inline --progress --config build/webpack.dev.conf.js

The CLI moved into a separate package: webpack-cli
Please install 'webpack-cli' in addition to webpack itself to use the CLI
-> When using npm: npm i -D webpack-cli
-> When using yarn: yarn add -D webpack-cli
internal/modules/cjs/loader.js:969
```

`npm install`と`npm run dev`コマンドで足りないと指摘されたパッケージをインストールする。

```sh
☻  npm install ajv webpack-cli
```

# `scoped packages`の時代到来！！！！
`npm run dev`でローカルサーバを立ち上げるもまだエラーが出る。

```sh
☻  npm run dev

> moly333@1.0.0 dev /Users/mizuho/work/dead-github.io
> webpack-dev-server --inline --progress --config build/webpack.dev.conf.js

10% building 1/1 modules 0 activeℹ ｢wds｣: Project is running at http://localhost:8080/
ℹ ｢wds｣: webpack output is served from /
ℹ ｢wds｣: 404s will fallback to /index.html
94% after seal

 ERROR  Failed to compile with 1 errors                                                                            7:16:25 PM

 error  in ./src/main.js

Module build failed (from ./node_modules/babel-loader/lib/index.js):
Error: [BABEL] /Users/mizuho/work/dead-github.io/src/main.js: Cannot find module 'babel-plugin-syntax-jsx'
```

エラーメッセージいわく、`babel-plugin-syntax-jsx`なるパッケージが足りないようだ。
しかし、ここで**はっきり言っておく。**
babelやvueなどのパッケージ名は昔と違い、`vue-hogehoge`や`babel-hogehoge`から`@vue/hogehoge`や`@babel/hogehoge`に変わっているのだ。[参考](https://babeljs.io/docs/en/v7-migration)ページいわく、

```text:babel公式サイトから
The most important change is finally switching all packages to scoped packages (the folder names in the monorepo are not changed but the name in its package.json is).

This means there will be no more issues with accidental/intentional name squatting, a clear separation from community plugins, and a simpler naming convention.

Your dependencies will need to be modified like so:

babel-cli -> @babel/cli. For us, we basically started by replacing babel- with @babel/.
```

つまり時代は`scoped packages`の時代であり、古い名前のパッケージは`npm`にこそあるものの、使うべきではないようだ。

ここで、`.babelrc`も編集しておく。古いパッケージ名から`scoped packages`へと変換させておく。
npmのサイトで古いパッケージ名で検索すると新しい`scoped packages`なパッケージ名が得られるのでそれに置き換える。

```diff
diff --git a/.babelrc b/.babelrc
index d5d93a5..50660c7 100644
--- a/.babelrc
+++ b/.babelrc
@@ -15,7 +15,7 @@
     ]
   ],
   "plugins": [
-    "transform-vue-jsx",
+    "@vue/babel-plugin-transform-vue-jsx",
     [
       "@babel/plugin-transform-runtime",
       {
@@ -43,7 +43,7 @@
         "@babel/preset-env"
       ],
       "plugins": [
-        "transform-vue-jsx",
+        "@vue/babel-plugin-transform-vue-jsx",
         "@babel/plugin-transform-modules-commonjs",
         "dynamic-import-node",
         "@babel/plugin-syntax-dynamic-import",
```

`.babelrc`を編集したので、もう一度`npm run dev`を走らせる。

```sh
☻  npm run dev

> moly333@1.0.0 dev /Users/mizuho/work/dead-github.io
> webpack-dev-server --inline --progress --config build/webpack.dev.conf.js

10% building 1/1 modules 0 activeℹ ｢wds｣: Project is running at http://localhost:8080/
ℹ ｢wds｣: webpack output is served from /
ℹ ｢wds｣: 404s will fallback to /index.html
94% after seal

 ERROR  Failed to compile with 1 errors                                                                            7:37:44 PM

 error  in ./src/main.js

Module build failed (from ./node_modules/babel-loader/lib/index.js):
Error: Cannot find module '@vue/babel-plugin-transform-vue-jsx' from 
省略
```

先程`.babelrc`で指定したパッケージが足らないのでインストールする。

```sh
☻  npm install @vue/babel-plugin-transform-vue-jsx
npm WARN extract-text-webpack-plugin@3.0.2 requires a peer of webpack@^3.1.0 but none is installed. You must install peer dependencies yourself.

+ @vue/babel-plugin-transform-vue-jsx@1.1.2
added 5 packages from 6 contributors and audited 264720 packages in 10.828s

50 packages are looking for funding
  run `npm fund` for details

found 3 vulnerabilities (2 low, 1 moderate)
  run `npm audit fix` to fix them, or `npm audit` for details

```

# npm run devのエラーが大きく変わる


```sh
☻  npm run dev

> moly333@1.0.0 dev /Users/mizuho/work/dead-github.io
> webpack-dev-server --inline --progress --config build/webpack.dev.conf.js

10% building 1/1 modules 0 activeℹ ｢wds｣: Project is running at http://localhost:8080/
ℹ ｢wds｣: webpack output is served from /
ℹ ｢wds｣: 404s will fallback to /index.html
94% after seal

 ERROR  Failed to compile with 12 errors                                                                           7:40:12 PM

Module Error (from ./node_modules/vue-loader/lib/index.js):
vue-loader was used without the corresponding plugin. Make sure to include VueLoaderPlugin in your webpack config.

You may use special comments to disable some warnings.
Use // eslint-disable-next-line to ignore the next line.
Use /* eslint-disable */ to ignore all warnings in a file.
 error  in ./src/components/PageFooter.vue?vue&type=style&index=0&lang=css&

Module parse failed: Unexpected character '#' (14:0)
File was processed with these loaders:
 * ./node_modules/vue-loader/lib/index.js
 * ./node_modules/eslint-loader/dist/cjs.js
You may need an additional loader to handle the result of these loaders.
```

今までのパッケージが足らないだのとつまらないエラーから、`vue-loader`のエラーに変わった。
[参考](https://qiita.com/7110/items/0721525ed6ccc263768b)をたよりに、webpackのconfigを変更する。プラグインに`vue-loader`のインスタンスを追加する。

```diff
diff --git a/build/webpack.dev.conf.js b/build/webpack.dev.conf.js
index 070ae22..c3cb9b0 100755
--- a/build/webpack.dev.conf.js
+++ b/build/webpack.dev.conf.js
@@ -9,6 +9,7 @@ const CopyWebpackPlugin = require('copy-webpack-plugin')
 const HtmlWebpackPlugin = require('html-webpack-plugin')
 const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
 const portfinder = require('portfinder')
+const { VueLoaderPlugin } = require("vue-loader")

 const HOST = process.env.HOST
 const PORT = process.env.PORT && Number(process.env.PORT)
@@ -64,7 +65,8 @@ const devWebpackConfig = merge(baseWebpackConfig, {
         to: config.dev.assetsSubDirectory,
         ignore: ['.*']
       }
-    ])
+    ]),
+    new VueLoaderPlugin()
   ]
 })

diff --git a/build/webpack.prod.conf.js b/build/webpack.prod.conf.js
index 2f17259..2852d33 100644
--- a/build/webpack.prod.conf.js
+++ b/build/webpack.prod.conf.js
@@ -10,6 +10,7 @@ const HtmlWebpackPlugin = require('html-webpack-plugin')
 const ExtractTextPlugin = require('extract-text-webpack-plugin')
 const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
 const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
+const { VueLoaderPlugin } = require("vue-loader")

 const env = process.env.NODE_ENV === 'testing'
   ? require('../config/test.env')
@@ -48,7 +49,7 @@ const webpackConfig = merge(baseWebpackConfig, {
       filename: utils.assetsPath('css/[name].[contenthash].css'),
       // Setting the following option to `false` will not extract CSS from codesplit chunks.
       // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
-      // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`,
+      // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`,
       // increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
       allChunks: true,
     }),
@@ -119,7 +120,8 @@ const webpackConfig = merge(baseWebpackConfig, {
         to: config.build.assetsSubDirectory,
         ignore: ['.*']
       }
-    ])
+    ]),
+    new VueLoaderPlugin()
   ]
 })
```

さて、すべての変更を終え、`npm run dev`すると、開発用サーバーが立ち上がった。

```sh
☻  npm run dev

> moly333@1.0.0 dev /Users/mizuho/work/dead-github.io
> webpack-dev-server --inline --progress --config build/webpack.dev.conf.js

10% building 1/1 modules 0 activeℹ ｢wds｣: Project is running at http://localhost:8080/
ℹ ｢wds｣: webpack output is served from /
ℹ ｢wds｣: 404s will fallback to /index.html
98% after emitting CopyPlugin

 DONE  Compiled successfully in 3445ms                                                                               7:45:41 PM

 I  Your application is running here: http://localhost:8080
```

# 編集したもの

* `.babelrc`
* `package.json`
* `build/webpack.dev.conf.js`
* `build/webpack.prod.conf.js`

# おわりに
2年前に作ったVueのプログラムだが、たった2年で環境が大きく変わり、`npm install`すらできなくなってしまう。
とはいえ、問題のあった部分は、`.babelrc`や`webpack.*.conf.js`や`package.json`であり、Vue本体の仕様が変わってビルドができなくなったわけではなく、周辺ライブラリの命名規則やバージョンアップによりできなくなってしまったのだ。
筆者はフロントエンドエンジニアではなく、趣味でたまにフロントをいじる人間であるが、これをメンテナンスするためには、webpack、babel、Vueなどの依存パッケージの変更に追随していく必要があり、とても面倒くさそうだなあと思う。

# おまけ
実はまだこのプロジェクトは最新になりきれていない。
Webpack3をWebpack4にアップデートしたことでe2eテストが動かなくなってしまった。
[issue](https://github.com/morimolymoly/dead-github.io/issues/1)をつくったが、やる気が起きない。