heyushuo / Blob

日常博客总结
19 stars 5 forks source link

记录vue-cli项目升级到webpack4以及升级到Babel7一步一步踩坑以及解决 #35

Open heyushuo opened 4 years ago

heyushuo commented 4 years ago

1. 优先升级webpack3至webpack4,因为webpack需要和webpack-cli配合使用所以两个需要同时升级

cnpm i -D webpack@latest webpack-cli@latest

然后运行 npm run dev 运行之后报错

Error: Cannot find module 'webpack/bin/config-yargs'
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:636:15)
    at Function.Module._load (internal/modules/cjs/loader.js:562:25)
    at Module.require (internal/modules/cjs/loader.js:692:17)
    at require (internal/modules/cjs/helpers.js:25:18)
    at Object.<anonymous> (E:\project\heyushuo-cli\node_modules\_webpack-dev-server@2.11.5@webpack-dev-server\bin\webpack-dev-server.js:54:1)

通过报错大概知道是webpack-dev-server版本不匹配所以升级版本

cnpm i -D webpack-dev-server@latest

2. 继续npm run dev 运行之后报错

:\project\heyushuo-cli\node_modules\_html-webpack-plugin@2.30.1@html-webpack-plugin\lib\compiler.js:81
        var outputName = compilation.mainTemplate.applyPluginsWaterfall('asset-path', outputOptions.filename, {
                                                  ^

TypeError: compilation.mainTemplate.applyPluginsWaterfall is not a function
    at E:\project\heyushuo-cli\node_modules\_html-webpack-plugin@2.30.1@html-webpack-plugin\lib\compiler.js:81:51
    at compile (E:\project\heyushuo-cli\node_modules\_webpack@4.43.0@webpack\lib\Compiler.js:343:11)
    at hooks.afterCompile.callAsync.err (E:\project\heyushuo-cli\node_modules\_webpack@4.43.0@webpack\lib\Compiler.js:681:15)

从报错中可以看出是html-webpack-plugin插件中的某些函数报错了,接着升级到最新版本

cnpm i -D html-webpack-plugin@latest

3. 继续npm run dev 运行之后报错如下

Module build failed (from ./node_modules/_eslint-loader@1.9.0@eslint-loader/index.js):
TypeError: Cannot read property 'eslint' of undefined
    at Object.module.exports (E:\project\heyushuo-cli\node_modules\_eslint-loader@1.9.0@eslint-loader\index.js:148:18)

可以看出是eslint报错的原因,接着升级,把package.json中所有和eslint相关的都升级一下

cnpm i D eslint@latest eslint-config-standard@latest eslint-friendly-formatter@latest eslint-loader@latest eslint-plugin-import@latest eslint-plugin-node@latest eslint-plugin-promise@latest eslint-plugin-standard@latest eslint-plugin-vue@latest eslint-plugin-html@latest

4. 继续npm run dev 运行之后报错如下

Module build failed (from ./node_modules/_vue-loader@13.7.3@vue-loader/index.js):
TypeError: Cannot read property 'vue' of undefined
    at Object.module.exports (E:\project\heyushuo-cli\node_modules\_vue-loader@13.7.3@vue-loader\lib\loader.js:61:18)

可以看出是vue-loader报错的原因(顺便把和vue相关的都进行升级),接着升级到最新版本

cnpm i D vue-loader@latest vue-style-loader@latest vue-template-compiler@latest

5. 继续npm run dev 运行之后报错如下

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

报错可以看出Make sure to include VueLoaderPlugin in your webpack config需要修改webpack配置如下

//分别在webpack.base.conf.js中添加VueLoaderPlugin

const { VueLoaderPlugin } = require('vue-loader')
plugins:[
  new VueLoaderPlugin()
]

6. 继续npm run dev 成功启动应用了,接下来打包试试npm run build 报错如下

Error: webpack.optimize.CommonsChunkPlugin has been removed, please use config.optimization.splitChunks instead.
    at Object.get [as CommonsChunkPlugin] (E:\project\heyushuo-cli\node_modules\_webpack@4.43.0@webpack\lib\webpack.js:189:10)

由于webpack4 移除了 CommonsChunkPlugin,所以需要在配置上做一些修改。去除webpack.prod.conf.js中与 CommonsChunkPlugin,webpack4中使用optimization替换掉了CommonsChunkPlugin

 // split vendor js into its own file
    // new webpack.optimize.CommonsChunkPlugin({
    //   name: 'vendor',
    //   minChunks(module) {
    //     // any required modules inside node_modules are extracted to vendor
    //     return (
    //       module.resource &&
    //       /\.js$/.test(module.resource) &&
    //       module.resource.indexOf(
    //         path.join(__dirname, '../node_modules')
    //       ) === 0
    //     )
    //   }
    // }),
    // // extract webpack runtime and module manifest to its own file in order to
    // // prevent vendor hash from being updated whenever app bundle is updated
    // new webpack.optimize.CommonsChunkPlugin({
    //   name: 'manifest',
    //   minChunks: Infinity
    // }),
    // // This instance extracts shared chunks from code splitted chunks and bundles them
    // // in a separate chunk, similar to the vendor chunk
    // // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
    // new webpack.optimize.CommonsChunkPlugin({
    //   name: 'app',
    //   async: 'vendor-async',
    //   children: true,
    //   minChunks: 3
    // }),

optimization默认使用''压缩代码性能要比UglifyJsPlugin好,所以直接把vue-cli中使用`UglifyJsPlugin'地方去掉就可以了

7. 继续npm run build,报错如下

Error: Chunk.entrypoints: Use Chunks.groupsIterable and filter by instanceof Entrypoint instead
    at Chunk.get (E:\project\heyushuo-cli\node_modules\_webpack@4.43.0@webpack\lib\Chunk.js:866:9)
    at E:\project\heyushuo-cli\node_modules\_extract-text-webpack-plugin@3.0.2@extract-text-webpack-plugin\dist\index.js:176:48
    at Array.forEach (<anonymous>)
    at E:\project\heyushuo-cli\node_modules\_extract-text-webpack-plugin@3.0.2@extract-text-webpack-plugin\dist\index.js:171:18

由报错可以看出是ExtractTextWebpackPlugin 插件的问题,通过查看官网有这样一句话

:warning: Since webpack v4 the extract-text-webpack-plugin should not be used for css. Use mini-css-extract-plugin instead. webpack4中不能使用extract-text-webpack-plugin来提取css,需要使用mini-css-extract-plugin插件

cnpm i D mini-css-extract-plugin

修改webpack.prod.conf中的内容如下

// webpack4不支持extrack-text-webpack-plugin 用在css上
// const ExtractTextPlugin = require('extract-text-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
new MiniCssExtractPlugin({
filename: utils.assetsPath('css/[name].[contenthash:8].css'),
chunkFilename: utils.assetsPath('css/[name].[contenthash:8].css')
})

修改build/utils.js中的内用如下

// const ExtractTextPlugin = require('extract-text-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
if (options.extract) {
//webpack4已经不支持了
// return ExtractTextPlugin.extract({
//   use: loaders,
//   fallback: 'vue-style-loader'
// })
return [MiniCssExtractPlugin.loader].concat(loaders)
} else {
return ['vue-style-loader'].concat(loaders)
}

8. 继续npm run build 报错如下

building for production...Unhandled rejection Error: "dependency" is not a valid chunk sort mode
at HtmlWebpackPlugin.sortEntryChunks (E:\project\heyushuo-cli\node_modules\_html-webpack-plugin@4.3.0@html-webpack-plugin\index.js:472:11)

通过全局搜索"dependency" 在``

new HtmlWebpackPlugin({
filename: process.env.NODE_ENV === 'testing' ?
'index.html' : config.build.index,
template: 'index.html',
inject: true,
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
// more options:
// https://github.com/kangax/html-minifier#options-quick-reference
},
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
chunksSortMode: 'dependency'
}),

通过官网查看 chunksSortMode可使用的值如下,控制插入html的js的顺序的,manual手动排序,将chunks按引入的顺序排序['vender','main'] chunksSortMode:

Allows to control how chunks should be sorted before they are included to the HTML. Allowed values are 'none' | 'auto' | 'manual' | {Function}

9. 继续 npm run build 终于打包成功了.

webpack4新增了mode字段,在开发环境加上mode:'development' 生产环境添加mode: 'production',默认会添加很多默认配置和优化(包括代码分割),具体默认配置可以查看链接,分别在webpack.dev.conf.jswebpack.prod.conf.js文件做修改

const devWebpackConfig = merge(baseWebpackConfig, {
  mode: 'development'
}

在开发环境加上mode:'development'

会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 development。启用 NamedChunksPlugin 和 NamedModulesPlugin。可以把vue-cli中的这两个插件注释掉

// new webpack.DefinePlugin({
//   'process.env': require('../config/dev.env')
// }),
// new webpack.NamedModulesPlugin(),

开启mode: 'development'相当于开启如下默认配置和优化

module.exports = {
+ mode: 'development'
- devtool: 'eval',
- cache: true,
- performance: {
-   hints: false
- },
- output: {
-   pathinfo: true
- },
- optimization: {
-   namedModules: true,
-   namedChunks: true,
-   nodeEnv: 'development',
-   flagIncludedChunks: false,
-   occurrenceOrder: false,
-   sideEffects: false,
-   usedExports: false,
-   concatenateModules: false,
-   splitChunks: {
-     hidePathInfo: false,
-     minSize: 10000,
-     maxAsyncRequests: Infinity,
-     maxInitialRequests: Infinity,
-   },
-   noEmitOnErrors: false,
-   checkWasmTypes: false,
-   minimize: false,
- },
- plugins: [
-   new webpack.NamedModulesPlugin(),
-   new webpack.NamedChunksPlugin(),
-   new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("development") }),
- ]
}

开启mode: 'production '相当于开启如下默认配置和优化,可以把vue-cli中相应的地方注释掉

// webpack.production.config.js
module.exports = {
+  mode: 'production',
- performance: {
-   hints: 'warning'
- },
- output: {
-   pathinfo: false
- },
- optimization: {
-   namedModules: false,
-   namedChunks: false,
-   nodeEnv: 'production',
-   flagIncludedChunks: true,
-   occurrenceOrder: true,
-   sideEffects: true,
-   usedExports: true,
-   concatenateModules: true,
-   splitChunks: {
-     hidePathInfo: true,
-     minSize: 30000,
-     maxAsyncRequests: 5,
-     maxInitialRequests: 3,
-   },
-   noEmitOnErrors: true,
-   checkWasmTypes: true,
-   minimize: true,
- },
- plugins: [
-   new TerserPlugin(/* ... */),
-   new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") }),
-   new webpack.optimize.ModuleConcatenationPlugin(),
-   new webpack.NoEmitOnErrorsPlugin()
- ]
}

10. 这个时候在npm run dev的时候还有一个警告如下

- building for production...(node:7012) DeprecationWarning: Tapable.plugin is deprecated. Use new API on `.hooks` instead
Hash: a38a1834a1cb2ff61367
Version: webpack 4.43.0

犹豫新版本的webpack的hook做了修改,替换了新的api,所以尽量把所有得loader或者plugin都做一个升级 如下是我的项目中的一些loader

cnpm i D css-loader@latest url-loader@latest postcss-loader@latest file-loader@latest vue-style-loader@latest vue-template-compiler@latest

如下是一些项目中用的plugin

cnpm i D optimize-css-assets-webpack-plugin@latest copy-webpack-plugin@latest friendly-errors-webpack-plugin@latest 

都升级一遍后继续 npm run dev ,擦直接报错了如下

plugins: [new VueLoaderPlugin()],

TypeError: VueLoaderPlugin is not a constructor

在Vueloader的官网查到了,点击查看具体

// webpack.config.js
const VueLoaderPlugin = require('vue-loader/lib/plugin')
 plugins: [
    // 请确保引入这个插件!
    new VueLoaderPlugin()
  ]

到此终于完成升级了

其实在跟新的时候还会遇到各种问题,需要自己来判断解决

2020/5/11 发现 babel 有 7 版本了,尝试升级一下

"babel-core": "^6.22.1",
"babel-eslint": "^8.2.1",
"babel-helper-vue-jsx-merge-props": "^2.0.3",
"babel-loader": "^7.1.5",
"babel-plugin-syntax-jsx": "^6.18.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.26.0",

官方升级指南升级指南

babel-loader要8版本以上

babel 的核心

"@babel/core"

可以将 es5 转 es6,但是一些新的 api 例如 promise,arr.includes 等不支持

"@babel/preset-env"

需要 polyfill 垫片来解决这个问题

"@babel/polyfill"

我们需要按需引入 polyfill 而不是全部引入

cnpm install --save core-js@3

babel6使用如下几个插件支持 jsx

"babel-plugin-syntax-jsx": "^6.18.0",
"babel-plugin-transform-vue-jsx": "^3.5.0",
"babel-helper-vue-jsx-merge-props": "^2.0.3",    

babel7替换成了如下插件

@vue/babel-plugin-transform-vue-jsx   

因为使用了@babel/preset-env设置polyfill按需引用了,就不用如下方式了,下边的方式有自己优势,也有自己的缺点

cnpm install --save-dev @babel/plugin-transform-runtime
cnpm install --save @babel/runtime

babel7去掉了stage-x这个功能,如果需要使用在提案中的功能需要自己单独引入.例如如下插件(使用import(),跟好的使用Es6的class)

 @babel/plugin-syntax-dynamic-import
 @babel/plugin-proposal-class-properties
mytart commented 3 years ago

看你发的记录,吐槽下这些东西就不能智能化一点么。。。感觉把时间和精力都花在这个上面了。

heyushuo commented 3 years ago

看你发的记录,吐槽下这些东西就不能智能化一点么。。。感觉把时间和精力都花在这个上面了。

没办法,老项目打包速度太慢了,升级只能这样一步一步升级