webpack3到4的迁移

webpack4大幅度减少配置成本。为了优化打包流程和打包效率,决定升级新版本,拥抱新技术

计划步骤:

  1. 从现有的一个项目,找到每个配置的作用是什么,以及新旧版本的区别,然后制定修改方案,同时埋好日志输出,便于排查错误
  2. 打包测试,修正问题

找到每个配置的作用是什么,以及新旧版本的区别,然后制定修改方案,同时埋好日志输出,便于排查错误

为防止不同npm包版本兼容有问题,我们把所有涉及到的包都升级到最新

先把"webpack": "3.6.0",升级到4.39.3

打开项目根目录下package.jsonscripts下的dev开始分析

webpack-dev-server --config build/webpack.dev.conf.js // 通过webpack-dev-server启动的本地服务。看到最新版本webpack-dev-server,需要webpack4,索性把webpack-dev-server升级到最新版,把原来的 "webpack-dev-server": "2.9.1", 改成 "3.8.0" 

分析build/webpack.dev.conf.js文件

引入的插件

const merge = require('webpack-merge') // "webpack-merge": "4.1.0" 升级到 "4.2.2"
const HtmlWebpackPlugin = require('html-webpack-plugin') // "html-webpack-plugin": "2.30.1" 升级到 "3.2.0"
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') // 最新版不用动
const portfinder = require('portfinder') // "portfinder": "1.0.13" 升级 "1.0.23"

引入其他文件const utils = require('./utils')

webpack4,ExtractTextPlugin废弃了,需要换成MiniCssExtractPlugin

const ExtractTextPlugin = require('extract-text-webpack-plugin') // 用于提取css文件 webpack4 不需要用这个插件, 换成 mini-css-extract-plugin
// 在工程里搜索 extract-text-webpack-plugin 发现可能有用到的文件或者包有:
1. /build/utils.js
// const ExtractTextPlugin = require('extract-text-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
if (options.extract) {
      // return ExtractTextPlugin.extract({
      //   use: loaders,
      //   fallback: 'vue-style-loader'
      // })
      return [
        {
          loader: MiniCssExtractPlugin.loader
        },
        'css-loader'
      ] 
 } 
2. /build/webpack.prod.conf.js
// new ExtractTextPlugin({
new MiniCssExtractPlugin({
3. 包 avg // 未在package.json中出现,不做处理
4. 包 async // 未在package.json中出现,不做处理
5. 包 css-loader // "css-loader": "0.28.0", 升级到 "3.2.0"
6. 包 element-ui // "element-ui": "2.3.2", 升级到2.11.1
7. 包 html-webpack-plugin // 已经升级过
8. 包 loader-utils // 未在package.json中出现,不做处理
9. 包 optimize-css-assets-webpack-plugin // "3.2.0",升级到5.0.3
10. 包 postcss-loader // "postcss-loader": "2.0.8", 升级到3.0.0
11. 包 sass-loader // 6.0.6,升级到7.3.1
12. 包 schema-utils // 未在package.json中出现,不做处理
13. 包 svg-sprite-loader // 3.7.3 升级到4.1.6
14. 包 tabel // 未在package.json中出现,不做处理 
15. 包 ajv // 未在package.json中出现,不做处理 
16. 包 ve-calendar // 没有新版本暂时不处理
17. 包 vue-loader // 13.3.0 升级到15.7.1
18. 包 vue-resize-directive // 未在package.json中出现,不做处理 
19. 包 webpack-sources // 未在package.json中出现,不做处理 

引入其他文件const config = require('../config')

根据不同环境:develop或者production等采取不同的配置,可能一些配置和webpack4不一致,暂定不需修改。

引入其他文件const baseWebpackConfig = require('./webpack.base.conf')

引入文件 vue-loader.conf,用于vue-loader需要的配置,暂定不需修改。

分析build/webpack.dev.conf.js文件配置的参数

暂定不需修改

打包测试,修正问题

安装npm包

删掉node_modules目录

执行npm i

npm WARN [email protected] requires a peer of vue@^2.5.17 but none is installed. You must install peer dependencies yourself.

提示element-ui需要[email protected],将vue升级到2.6.10。重新npm i

npm WARN [email protected] requires a peer of webpack@2 || 3 but none is installed. You must install peer dependencies yourself.
npm WARN [email protected] requires a peer of webpack@^2.0.0 || ^3.0.0 but none is installed. You must install peer dependencies yourself.
npm WARN [email protected] requires a peer of webpack@^2.0.0 || ^3.0.0 but none is installed. You must install peer dependencies yourself.

升级babel-loader到8.0.6,升级file-loader到4.2.0,webpack4.0已经不用uglifyjs-webpack-plugin,直接删掉。重新npm i

npm WARN [email protected] requires a peer of @babel/core@^7.0.0 but none is installed. You must install peer dependencies yourself.

升级babel-core@babel/core] 7.5.5重新npm i

测试

npm run dev

The CLI moved into a separate package: webpack-cli
Please install 'webpack-cli' in addition to webpack itself to use the CLI
# 安装webpack-cli 
npm install webpack-cli --save-dev

重新npm run dev

ERROR  Failed to compile with 1 errors                             
Module build failed (from ./node_modules/eslint-loader/index.js):
TypeError: Cannot read property 'eslint' of undefined at Object.module.exports (/Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/eslint-loader/index.js:155:18)

eslint-loader 1.7.1升级到3.0.0, 重新npm i

npm WARN [email protected] requires a peer of eslint@^5.0.0 || ^6.0.0 but none is installed. You must install peer dependencies yourself.

eslint 3.19.0升级到6.2.2, 重新npm i

npm WARN [email protected] requires a peer of [email protected] - 4.x but none is installed. You must install peer dependencies yourself.
npm WARN [email protected] requires a peer of acorn@^6.0.0 || ^7.0.0 but none is installed. You must install peer dependencies yourself.

eslint-plugin-import 2.7.0升级到2.18.2。

通过命令npm ls查看整个包依赖树,

webpack-bundle-analyzer 引用了[email protected],所以把webpack-bundle-analyzer2.9.0升级到3.4.1

另外一个引用[email protected] -> jest-cli -> jest-environment-jsdom -> jsdom -> [email protected] 所有把[email protected]升级到24.9.0

重新npm i

还是有警告

npm WARN [email protected] requires a peer of acorn@^6.0.0 || ^7.0.0 but none is installed. You must install peer dependencies yourself.

依赖树中看到

│ │ ├── UNMET PEER DEPENDENCY [email protected]
│ │ ├── [email protected]

只好手动安装acorn最新版本

npm install acorn --save-dev

重新npm i

没有警告

npm run dev

Module build failed (from ./node_modules/eslint-loader/dist/cjs.js):
TypeError: Cannot read property 'forEach' of undefined
    at Linter.parseResults (/Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/eslint-loader/dist/Linter.js:121:13)
    at Linter.printOutput (/Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/eslint-loader/dist/Linter.js:85:26)
    at Object.loader (/Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/eslint-loader/dist/index.js:26:10)

表面上看不出这个错误导致是怎么导致的。在/node_modules/eslint-loader/dist/Linter.js的lint(content)函数中输出捕获的错误.

Failed to load plugin 'html' declared in '.eslintrc.js': eslint-plugin-html error: It seems that eslint is not loaded. If you think it is a bug, please file a report at https://github.com/BenoitZugmeyer/eslint-plugin-html/issues
    at iterateESLintModules (/Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/eslint-plugin-html/src/index.js:79:11)
    at Object. (/Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/eslint-plugin-html/src/index.js:21:1)
    at Module._compile (internal/modules/cjs/loader.js:738:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:749:10)
    at Module.load (internal/modules/cjs/loader.js:630:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:570:12)
    at Function.Module._load (internal/modules/cjs/loader.js:562:3)
    at Module.require (internal/modules/cjs/loader.js:667:17)
    at require (internal/modules/cjs/helpers.js:20:18)
    at ConfigArrayFactory._loadPlugin (/Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/eslint/lib/cli-engine/config-array-factory.js:861:49)

eslint-plugin-html从3.0.0升级到6.0.0

npm i

成功升级eslint-plugin-html

npm run dev

 Cannot find module 'escope'
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:613:15)
    at monkeypatch (/Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/babel-eslint/index.js:53:26)
    at Object.exports.parse (/Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/babel-eslint/index.js:358:5)
    at parse (/Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/eslint/lib/linter/linter.js:625:29)
    at Linter._verifyWithoutProcessors (/Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/eslint/lib/linter/linter.js:1067:33)
    at Linter.(anonymous function) (/Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/eslint-plugin-html/src/index.js:151:21)
    at Linter._verifyWithConfigArray (/Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/eslint/lib/linter/linter.js:1210:21)
    at Linter.verify (/Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/eslint/lib/linter/linter.js:1165:25)
    at Linter.verifyAndFix (/Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/eslint/lib/linter/linter.js:1355:29)
    at verifyText (/Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/eslint/lib/cli-engine/cli-engine.js:231:48)

babel-eslint版本也比较老,7.1.1换成 10.0.3

npm i

成功升级babel-eslint

npm run dev

Module build failed (from ./node_modules/babel-loader/lib/index.js):
Error: .plugins[1][1] must be an object, false, or undefined
    at assertPluginItem (/Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/@babel/core/lib/config/validation/option-assertions.js:244:15)
    at arr.forEach (/Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/@babel/core/lib/config/validation/option-assertions.js:222:30)
    at Array.forEach ()
    at assertPluginList (/Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/@babel/core/lib/config/validation/option-assertions.js:222:9)
    at Object.keys.forEach.key (/Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/@babel/core/lib/config/validation/options.js:107:5)
    at Array.forEach ()
    at validateNested (/Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/@babel/core/lib/config/validation/options.js:83:21)
    at validate (/Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/@babel/core/lib/config/validation/options.js:74:10)
    at file (/Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/@babel/core/lib/config/config-chain.js:174:34)
    at cachedFunction (/Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/@babel/core/lib/config/caching.js:33:19)

/node_modules/@babel/core/lib/config/validation/options.js添加日志输出

console.log('optLoc--------', optLoc)
console.log('opts--------', opts)
console.log('key-----', key)
    validator(optLoc, opts[key]);
// 报错的前的输出是
optLoc-------- { type: 'option',
  name: 'plugins',
  parent: { type: 'root', source: 'babelrcfile' } }
opts-------- { presets: [ [ 'env', [Object] ], 'stage-2' ],
  plugins: [ 'transform-runtime', [ 'component', [Array] ] ],
  env: { test: { presets: [Array], plugins: [Array] } } }
key----- plugins
// 是babelr配置文件出问题了,这里应该是babel修改配置规则了,plugins里的元素不能是数组了

修改.babelrc文件

"plugins": ["transform-runtime", ["component", [
  {
    "libraryName": "element-ui"
  }
]]]
改为    
"plugins": ["transform-runtime", "component": [
  {
    "libraryName": "element-ui"
  }
]]

npm run dev

Module build failed (from ./node_modules/babel-loader/lib/index.js):
Error: Plugin/Preset files are not allowed to export objects, only functions. In /Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/babel-preset-stage-2/lib/index.js
    at createDescriptor (/Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/@babel/core/lib/config/config-descriptors.js:178:11)
    at items.map (/Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/@babel/core/lib/config/config-descriptors.js:109:50)
    at Array.map ()
    at createDescriptors (/Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/@babel/core/lib/config/config-descriptors.js:109:29)
    at createPresetDescriptors (/Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/@babel/core/lib/config/config-descriptors.js:101:10)
    at presets (/Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/@babel/core/lib/config/config-descriptors.js:47:19)
    at mergeChainOpts (/Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/@babel/core/lib/config/config-chain.js:320:26)
    at /Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/@babel/core/lib/config/config-chain.js:283:7
    at buildRootChain (/Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/@babel/core/lib/config/config-chain.js:120:22)
    at loadPrivatePartialConfig (/Users/treePro/develop/X/good_things/common-manage-platform-vue/node_modules/@babel/core/lib/config/partial.js:85:55)

先将babel-preset-stage-2从6.22.0升级到6.24.1

npm i

成功升级babel-preset-stage-2

npm run dev

一样的错误

/@babel/core/lib/config/config-chain.js283行添加打印日志

console.log('chain--',  chain)
console.log('op--',  op)
      mergeChainOpts(chain, op);
// 报错前输出
chain-- { options: [], presets: [], plugins: [] }
op-- { options:
   { presets: [ [Array], 'stage-2' ],
     plugins: [ 'transform-runtime', [Object] ],
     env: { test: [Object] } },
  plugins: [Function: plugins],
  presets: [Function: presets] }

[email protected]更新为@babel/[email protected]

.babelrc文件中

"plugins": ["transform-runtime", {
 改为
"plugins": ["@babel/plugin-transform-runtime", {

npm i

这里一直报babel的错,把babel的相关包都做下升级

"babel-plugin-dynamic-import-node": "1.2.0", => 2.3.0
"babel-plugin-transform-es2015-modules-commonjs": "6.26.0", => 6.26.2
"babel-preset-env": "1.3.2", => 1.7.0
"babel-register": "6.22.0", => 6.26.0
"babel-plugin-component": "0.10.1", => 1.1.1

npm i

npm run dev 一样的错,在网上找到有将babel-preset-env换成 @babel/preset-env,试下

"babel-preset-env": "1.7.0", => "@babel/preset-env" : "7.5.5",
"babel-register": "6.26.0",  => "@babel/register" : "7.5.5", // 一起改掉
"babel-polyfill": "6.26.0", => "@babel/polyfill" : "7.4.4", // 一起改掉

npm i

npm run dev 依然报错

临时把.babelrc文件简化

{
   "presets": ["@babel/preset-env"]
}

npm run dev

报其他错误。

先做下相关npm包升级

"vue-template-compiler": "2.5.2", => "2.6.10",
"vue-style-loader": "3.0.1",  => "@babel/register" : "4.1.2", 

依然报错

有个老兄说 webpack4 不兼容vue-loader 15.x.x版本https://www.cnblogs.com/tugenhua0707/p/9695179.html

我也把vue-loader 降低成^14.2.2

之前错误没了,只有eslint的错误

暂时将/config/index.js中的useEslint设置成false,

npm run dev

终于跑起来了

/config/index.js中的useEslint设置成true

eslint相关的包升级为最新

"eslint-config-standard": "10.2.1", => "14.1.0",
"eslint-friendly-formatter": "3.0.0",  => "4.0.1", 
"eslint-plugin-node": "5.2.0", => "10.0.0",
"eslint-plugin-promise": "3.5.0",  => "4.2.1", 
"eslint-plugin-standard": "3.0.1",  => "4.0.1", 

npm i

npm run dev 依然报错,猜测可能和简化.babelrc有关系

把babelrc中的配置一点点加回来

{
   "presets": [["@babel/preset-env", {"modules": false}], "stage-2"]
}

npm run dev 依然报错

查到babel7 stage-2的文章 https://babeljs.io/docs/en/babel-preset-stage-2 发现babel-preset-stage-2插件需要更换

"babel-preset-stage-2": "6.24.1",  => "@babel/preset-stage-2": "7.0.0", 

npm i

babelrc中的配置修改

{
   "presets": [["@babel/preset-env", {"modules": false}], "@babel/preset-stage-2"]
}

npm run dev , 提示As of v7.0.0-beta.55, we've removed Babel's Stage presets.发现babel7已经移除了stage preset https://babeljs.io/blog/2018/07/27/removing-babels-stage-presets

babelrc中去掉@babel/preset-stage-2 并添加pluginx component的结构做了点调整

{
  "presets": [["@babel/preset-env", {"modules": false}]],
  "plugins": [
    "@babel/plugin-transform-runtime", 
    [ 
      "component",
      {
        "libraryName": "element-ui"
      }
    ]
  ]
}

npm run dev

# 提示错误信息
These dependencies were not found:
* @babel/runtime/helpers/defineProperty in ./src/router/index.js
...

添加@babel/runtime

"@babel/runtime": "^7.6.0"

npm i

npm run dev

# 提示错误信息
These dependencies were not found:
* element-ui/lib/alert/style.css in ./src/element-ui/index.js
* element-ui/lib/aside/style.css in ./src/element-ui/index.js
...

element包导入有问题,babelrc需要添加styleLibraryName用来加载样式文件

{
  "presets": [["@babel/preset-env", {"modules": false}]],
  "plugins": [
    "@babel/plugin-transform-runtime",
    [
      "component",
      {
        "libraryName": "element-ui",
        "styleLibraryName": "theme-chalk"
      }
    ]
  ]
}

npm run lint(lint配置在package中)

还是报错

http://eslint.org/docs/rules/dot-notation  ["children"] is better written in dot notation  
  src/utils/index.js:36:31
...
    1 |