依赖调整
| 包名 | 处理方式 | 版本 | 
|---|---|---|
| webpack | 升级 | 5.51.0 | 
| webpack-cli | 新增 | 4.10.0 | 
| webpack-dev-server | 升级 | 4.7.4 | 
| webpack-merge | 升级 | 5.8.0 | 
| babel-loader | 升级 | 8.2.5 | 
| autoprefixer | 升级 | 10.4.7 | 
| babel-core | 升级 | 7.0.0-bridge.0 | 
| babel-eslint | 升级 | 9.0.0 | 
| babel-jest | 升级 | 23.4.2 | 
| compression-webpack-plugin | 升级 | 6.1.0 | 
| copy-webpack-plugin | 升级 | 9.1.0 | 
| css-loader | 升级 | 5.2.7 | 
| css-minimizer-webpack-plugin | 新增 | 3.4.1 | 
| eslint | 升级 | 7.32.0 | 
| eslint-loader | 废弃 | -- | 
| eslint-plugin-vue | 升级 | 7.20.0 | 
| extract-text-webpack-plugin | 废弃 | -- | 
| eslint | 升级 | 7.32.0 | 
| eslint-webpack-plugin | 新增 | 3.1.1 | 
| file-loader | 废弃 | -- | 
| html-webpack-plugin | 升级 | 5.5.0 | 
| happypack | 废弃 | -- | 
| less-loader | 升级 | 8.1.1 | 
| less | 升级 | 4.1.2 | 
| mini-css-extract-plugin | 新增 | 1.6.2 | 
| optimize-css-assets-webpack-plugin | 废弃 | -- | 
| postcss-import | 升级 | 14.1.0 | 
| postcss-loader | 升级 | 6.2.1 | 
| postcss-url | 升级 | 10.1.3 | 
| scss-loader | 升级 | 10.2.0 | 
| uglify-webpack-plugin | 废弃 | -- | 
| url-loader | 废弃 | -- | 
| style-loader | 新增 | 3.3.1 | 
| terser-webapck-plugin | 新增 | 5.3.3 | 
| vue-loader | 新增 | 15.10.0 | 
| vue-style-loader | 废弃 | -- | 
由于涉及到babel相关依赖包比较多,暂时没有详细列出。如果不想手动更新babel相关依赖包的版本,可以使用babel-upgrade自动更新.babelrc配置以及package.json依赖包。
- 使用babel-upgrade的方法
            
            
              js
              
              
            
          
          // 1. 安装 babel-upgrade
npm install babel-upgrade
// 2. 运行babel-upgrade的更新命令
npx babel-upgrade --write
// 3. 输出的日志详情
updating .babelrc config at .babelrc
==========================================
{
    "presets": [
        [
            "env",
 +          "@babel/preset-env",
            {
                "modules": false,
                "targets": {
                    "browsers": ["> 1%", "last 15 versions", "not ie <= 8"]
                }
            }
-       ],
-       "stage-1",
 +      ]
    ],
    "plugins": [
        "transfrom-vue-js",
-       "transfrom-runtime",
-       "syntax-decorators-legacy",
-       "transfrom-class-properties",
+       [
+           "@babel/plugin-transfrom-runtime",
+           {
+               "corejs": 2
+           }
+       ],
+       "@babel/plugin-syntax-dynamic-import"
+       [
+           "@babel/plugin-proposal-decorators",
+           {
+               "legacy": true
+           }
+       ],
+       "@babel/plugin-proposal-function-sent",
+       "@babel/plugin-proposal-export-namespace-from",
+       "@babel/plugin-proposal-numeric-separator",
+       "@babel/plugin-proposal-throw-expressions",
+       "@babel/plugin-proposal-export-default-from",
+       "@babel/plugin-proposal-optional-chaining",
+       [
+           "@babel/plugin-proposal-pipeline-operator",
+           {
+               "proposal": "minimal"
+           }
+       ],
+       "@babel/plugin-proposal-mullish-coalescing-operator",
+       "@babel/plugin-proposal-do-expressions"
    ],
    "env": {
        "test": {
            "presets": [
-               "env",
-               "stage-1"
+               "@babel/preset-env"
            ],
            "plugins": [
                "transform-vue-js",
-               "transform-es2015-modules-commonjs",
+               "@babel/plugin-transform-modules-commonjs",
                "dynamic-import-node",
-               "istanbul"
-               "istanbul",
+               "@babel/plugin-syntax-dynamic-import",
+               "@babel/plugin-syntax-import-meta",
+               "@babel/plugin-proposal-class-properties",
+               "@babel/plugin-proposal-json-strings",
+               [
+                   "@babel/plugin-proposal-descorator",
+                   {
                        "legacy": true
+                   }
+               ],
+               "@babel/plugin-proposal-function-sent",
+               "@babel/plugin-proposal-export-namesapce-from",
+               "@babel/plugin-proposal-numeric-separator",
+               "@babel/plugin-proposal-throw-expressions",
+               "@babel/plugin-proposal-export-default-from",
+               "@babel/plugin-proposal-logical-assignment-operators",
+               "@babel/plugin-proposal-optional-chaining",
+               [
+                   "@babel/plugin-proposal-pipeline-operator",
+                   {
+                       "proposal": "minimal"
+                   }
+               ],
+               "@babel/plugin-proposal-mullish-coalescing-operator",
+               "@babel/plugin-proposal-do-expressions"
            ]
        }
    }
}
// updating closest package.json dependencies
"devDependencies": {
+   "@babel/core": "^7.0.0",
+   "@babel/plguin-proposal-class-properties": "^7.0.0",
+   "@babel/plugin-proposal-decorators": "^7.0.0",
+   "@babel/plugin-proposal-do-expressions": "^7.0.0",
+   "@babel/plugin-proposal-export-default-from": "^7.0.0",
+   "@babel/plugin-proposal-export-namespace-from": "^7.0.0",
+   "@bable/plugin-proposal-function-sent": "^7.0.0",
+   "@babel/plugin-proposal-json-strings": "^7.0.0",
+   "@babel/plugin-proposal-logical-assignment-operators": "^7.0.0",
+   "@babel/plugin-proposal-nullish-coalescing-opertaor": "^7.0.0",
+   "@babel/plugin-proposal-numeric-separator": "^7.0.0",
+   "@babel/plugin-proposal-optional-chaining": "^7.0.0",
+   "@babel/plugin-proposal-pipeline-operator": "^7.0.0",
+   "@babel/plugin-proposal-throw-expressions": "^7.0.0",
+   "@babel/plugin-syntax-dynamic-import": "^7.0.0",
+   "@babel/plugin-syntax-import-meta": "^7.0.0",
+   "@babel/plugin-transform-modules-commonjs": "^7.0.0",
+   "@babel/plugin-transform-runtime": "^7.0.0",
+   "@babel/preset-env": "^7.0.0",
+   "@babel/register":  "^7.0.0",
    "autoperfixer": "^10.4.7",
-   "babel-core": "^6.22.1",
-   "babel-esint": "^8.2.1",
+   "babel-core": "^7.0.0-bridge.0",
+   "babel-eslint": "^9.0.0",
    "babel-helper-vue-jsx-merge-props": "^2.0.3",
-   "babel-jest": "^21.0.2",
+   "babel-jest": "^23.4.2",
    "babel-loader": "^8.2.5",
    "babel-plugin-dynamic-import-node": "^1.2.0",
    "babel-plugin-istanbul": "^4.1.5",
-   "babel-plugin-syntax-dynamic-import": "^6.18.0",
-   "babel-plugin-syntax-jsx": "^6.18.0",
-   "babel-plugin-transform-class-properties": "^6.24.1",
-   "babel-plugin-transform-decorators-legacy": "^1.3.4",
-   "babel-plugin-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-1": "^6.24.1",
-   "babel-preset-stage-2": "^6.22.0",
-   "babel-register": "^6.22.0",
    "chalk": "^2.0.1",
}webpack 配置
plugin 以及配置项调整
- webpack3 升级到webpack5,webpack-dev-server版本也对应进行了升级,npm run dev的命令需要改为webpack serve
- extract-text-webpack-plugin和optimize-css-assets-webpack-plugin已经过时,需要更新为mini-css-extract-plugin和css-minimizer-webpack-plugin\
- UglifyJsPlugin已经过时,可以使用webpack5开箱的TerserPlugin
- webpack5已支持资源模块替换url-loader, file-loader
- webpack-merge更新版本之后,需要解构出merge,const { merge } = require('webpack-merge')
- NamedModulesPlugin已移除,改为使用optimization.moduleIds: 'named'
- NoEmitOnErrorsPlugig已移除,改为使用optimization.emitOnErrors: true
- HashedModuleIdsPlugin已移除,改为使用optimization.moduleIds: 'hashed'
- CommonsChunkPlugin已移除,改为使用optimization.splitChunks
- devtool的值需要进行调整
- 由于vue-loader升级之后,原来css使用的/deep/需要调整为::deep
- 配置项添加模式
配置项具体调整
添加模式
            
            
              js
              
              
            
          
          module.exports = {
  // production: 生产模式  development: 开发模式
  mode: 'production'
}插件
- mini-css-extracct-plugin 配置
            
            
              js
              
              
            
          
          plugins: [
    new MiniCssExtractPlugin({
        filename: utils.assetsPath('css[name].[contentHash].css')
    })
]同时utils.js也需要做相应的调整
            
            
              js
              
              
            
          
          loader: [MiniCssExtractPlugin.loader,...loader]- css-minimizer-webpack-plugin 配置
            
            
              js
              
              
            
          
          optimization: {
    minimizer: [
        new CssMinimizerPlugin()   
    ]
}
plugins: [
    new CssMinimizerPlugin()   
]如果想在开发环境中启用css优化,请设置optimization.minimize 设置为 true
            
            
              yaml
              
              
            
          
          optimization: {
    minimize: true,
    minimizer: [
        new CssMinimizerPlugin()    
    ]
}- terser-webpack-plugin 配置
            
            
              js
              
              
            
          
          optimization: {
    minimizer: {
        new TerserPlugin({
            terserOptions: {
                sourceMap: config.build.productionSourceMap,
                format: {
                    beautify: false,
                    comments: false
                },
                compress: {
                    drop_debugger: true,
                    drop_console: true
                }
            },
            extractComments: false,
            arallel: true
        })
    }
}- copy-webpack-plugin 配置
            
            
              js
              
              
            
          
          // 调整前
new CopyWebpackPlugin([
    {
        from: path.resolve(__dirname, '../static'),
        to: config.dev.assetsSubDiractory,
        ignore: ['.*']
    }
])
// 调整后
new CopyWebpackPlugin({
    patterns: [
        {
            from: path.resolve(__dirname, '../static'),
            to: config.dev.assetsSubDiractory,
            globOptions: {
                ignore: ['.*']
            }
        }
    ]
})- eslint-webpack-plugin
eslint-loader已经被废弃,需要替换为eslint-webpack-plugin
            
            
              js
              
              
            
          
          // webpack.base.conf.js
module.expots = {
    plugin: [
        new EslintPlugin({
            extensions: ['js', 'vue'],
            context: path.resolve(__dirname, '../'),
            files: [resolve('src'), resolve('test')]
            exclude: [resolve('src/components'), resolve('src/assets'), resolve('src/libs')],
            formatter: require('eslint-friendly-formater'),
            emitWarning: !config.dev.showEslintErrorsInOverlay
        })
    ]
}devServer 配置
            
            
              js
              
              
            
          
          // 调整前
devServer: {
    clientLogLevel: 'warning',
    overlay: config.dev.errorOverlay ? { warnings: false, errors: true } :false
}
// 调整后
devServer: {
    client: {
        logging: 'warn',
        overlay: config.dev.errorOverlay ? { warnings: false, errors: true } :false
    }
}
            
            
              js
              
              
            
          
          // 调整前
devServer: {
    publicPath: config.dev.assetsPublicPath
}
// 调整后
devServer: {
    static: {
        directory: path.join(__dirname, './public'),
        publicPath: config.dev.assetsPublicPath
    }
}
            
            
              js
              
              
            
          
          // 调整前
devServer: {
    watchOptions: {
        poll: config.dev.poll
    }
}
// 调整后
{
    watch: true,
    watch  Options: {
        aggregateTimeout: 200,
        ignored: ['**/node_modules/', '**/test/'],
        stdin: true,
        poll: config.dev.poll
    }
}
            
            
              js
              
              
            
          
          // 去掉的配置
contentBase: false,
quiet: false资源配置
- 解析图片
            
            
              js
              
              
            
          
          // 调整前
module: {
    rules: [
        ...,
        {
            test: /\.(png|jpe?g|gif|svg)(\?.*)?$,
            loader: "url-loader",
            options: {
                limit: 10000,
                name: utils.assetsPath('img/[name].[hash:7].[ext]')
            }
        },
        {
            test: /\.(mp4|webm|ogg|mp3|wav|flac|acc)(\?.*)?$/,
            loader: "url-loader",
            options: {
                limit: 10000,
                name: utils.assetsPath('img/[name].[hash:7].[ext]')
            }
        },
        {
            test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
            loader: "url-loader",
            options: {
                limit: 10000,
                name: utils.assetsPath('img/[name].[hash:7].[ext]')
            }
        }
    ]
}
// 调整后
module: {
    rules: [
        ...,
        {
            test: /\.(png|jpe?g|gif|svg)(\?.*)?$,
            type: 'asset',
            generator: {
                filename: utils.assetsPath('img/[name].[hash:7].[ext]')
            },
            parser: {
                dataUrlCondition: {
                    maxSize: 8 * 1024
                }
            }
        },
        {
            test: /\.(mp4|webm|ogg|mp3|wav|flac|acc)(\?.*)?$/,
            type: 'asset',
            generator: {
                filename: utils.assetsPath('media/[name].[hash:7].[ext]')
            },
            parser: {
                dataUrlCondition: {
                    maxSize: 8 * 1024
                }
            }
        },
        {
            test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,            
            type: 'asset',
            generator: {
                filename: utils.assetsPath('fonts/[name].[hash:7].[ext]')
            },
            parser: {
                dataUrlCondition: {
                    maxSize: 8 * 1024
                }
            }
        }
    ]
}- 压缩资源调整
            
            
              js
              
              
            
          
          // 调整前
plugins: [
    new webpack.optimize.CommonsChunkPlugin({
        name: 'vendor',
        minChunks(module) {
            return (
                module.resource &&
                /\.js$/.test(module.resource) &&
                module.resource.indexOf(
                    path.join(__dirname, '../node_modules')
                ) === 0
            )
        }
    }),
    new webpack.optimize.CommonsChunkPlugin({
        name: 'mainfest',
        minChunk: Infinity
    }),
    new webpack.optimize.CommonsChunkPlugin({
        name: 'app',
        async: 'vendor-async',
        children: true,
        minChunks: 3
    })
]
// 调整后
optimization: {
    splitChunks: {
        chunks: 'all',
        minSize: 30000,
        minChunks: 1,
        cacheGroups: {
            vendors: {
                name: 'vendors',
                test(module) {
                    return (
                        module.resource &&
                        /\.js$/.test(module.resource) &&
                        module.resource.indexOf(
                            path.join(__dirname, '../node_modules')
                        ) === 0
                    )
                }
            },
            styles: {
                name: 'styles',
                type: 'css/mini-extract',
                test: /\.(sc|c)ss$/,
                enforce: true
            },
            manifest: {
                name: 'manifest',
                minChunks: Infinity
            },
            app: {
                name: 'app',
                minChunks: 3
            }
        }
    }
}devtool 调整
            
            
              js
              
              
            
          
          'cheap-module-eval-source-map' -> 'eval-cheap-module-source-map'命令行 API
            
            
              js
              
              
            
          
          // 调整前
"dev": "webpack-webpack-server --line --progress --config build/webpack.dev.conf.js --host 0.0.0.0"
// 调整后
"dev": "webpack serve --progress --config build/webpack.dev.conf.js --host 0.0.0.0"node
            
            
              js
              
              
            
          
          // 调整前
node: {
    setImmediate: false,
    dgram: 'empty',
    fs: 'empty',
    net: 'empty',
    tls: 'empty',
    child_process: 'empty'
}
// 调整后
node: {
    global: true
}在之前的配置文件中使用了类似于node.fs: 'empty',需要改为resolve.fallback.fs: false
            
            
              js
              
              
            
          
          resolve: {
    fallback: {
        fs: false
    }
}loader
- vue-loader
升级vue-loader@15.x版本时,需要在配置文件中new HtmlWebpackPlugin()后面添加new VueLoaderPlugin()
            
            
              javascript
              
              
            
          
          const { VueLoaderPlugin } = require('vue-loader')
plugin: [
    new HtmlWebpackPlugin(),
    new VueLoaderPlugin()
]- sass-loader
在utils.js文件进行调整
            
            
              js
              
              
            
          
          // 调整前
return {
    ...,
    sass: generateLoaders('sass', {
        indentedSyntax: true,
        data: '@import "common/css/_variable";',
        includePaths: [
            path.join(__dirname, '../src')
        ]
    }),
    scss: generateLoaders('scss' {
        indentedSyntax: true,
        data: '@import "common/css/_variable";',
        includePaths: [
            path.join(__dirname, '../src')
        ]
    })
}
// 调整后
return {
    ...,
    sass: generateLoaders('sass', {
        additionalData: '@import "common/css/_variable";',
        sassOptions: {
            indentWidth: 4,
            includePaths: [
                Path.join(__dirname, '../src')
            ]
        }
    }),
    scss: generateLoadrs('scss', {
        additionalData: '@import "common/css/_variable";',
        sassOptions: {
            indentWidth: 4,
            includePaths: [
                Path.join(__dirname, '../src')
            ]
        }
    })
}性能优化
参考文章: webpack5 - 性能优化
缓存
cache
通过配置cache: 'filesystem'对构建过程中的模块进行缓存,二次构建从缓存中拉取模块,缩短打包时间。
配置方式:
            
            
              js
              
              
            
          
          // webpack.base.conf.js
module.exports = {
    cache: {
        type: 'filesystem'
    }
}cache-loader
cache-loader已经被webapck5的cache或取代,不需要引入cache-loader
多进程
thread-loader
thread-loader的配置方式:
            
            
              js
              
              
            
          
          // webpack.base.conf.js
module.export = {
    module: {
        rules [
            {
                test: /\.js$/,
                exclude: /(node_modules|bower_components)/,
                include: [
                    resolve('src'),
                    resolve('test'),
                    resolve('node_modules/webpack-dev-server/client')
                ],
                use: [
                    {
                        loader: 'thread-loader',
                        options: {
                            works: os.cpus().length - 1
                        }
                    },
                    {
                        loader: 'babel-loader',
                        options: {
                            cacheDirectory: true
                        }
                    }
                ]
            }
        ]
    }
}happypack
在webpack5中不推荐使用,请使用thread-loader
升级过程中遇到的报错
Happypack插件报错
            
            
              js
              
              
            
          
          [webpack-cli] compiler.plugin is not a function 
at HappyPlugin.apply(..\node_modules\happypack\lib\HappyPlugin.js:95:12)解决方法:
在webpack.base.conf.js文件中去掉Happypack插件
Postcss 依赖报错
            
            
              js
              
              
            
          
          error: true is not a postcss plugin
at processor.normalize解决办法:
core-js 依赖报错
            
            
              js
              
              
            
          
          module not found: error: can't resolve '@babel/runtime-corejs2/core-js/object/keys' in ....解决办法:
安装@babel/runtime-corejs2@7.18.9
参考文章:bael的兼容性方案
autoprefixer 双行注释报错
            
            
              js
              
              
            
          
          warning: autoprefixer: second autoprefixer control comment was ignored. autoprefixer applies control comment to whole block, not to next rules.解决方法:
将autoprefixer的两条注释中后面的一条注释去掉,改为一条注释
            
            
              js
              
              
            
          
          // 修改前
/*! autoprefixer: off */
...
/*! autoprefixer: on */
// 修改后
/* autoprefixer: ignore next */
...引用.css样式报错
            
            
              js
              
              
            
          
          warning: in ./node_modules/handsontable/dist/handsontable.full.css
warning: postcss-import: @charset must precede al other statements解决方法:
修改引用.css样式的位置,把引用放在样式表的第一行,
魔法注释报错
            
            
              js
              
              
            
          
          ChunkLoaderError: loading chunk /dashboard faild. (error: http://dashboard.js/)
at Object.__webpack_require__.f.j解决方法:
去取魔法注释中webpackChunkName内容
compression-weback-plugin 打包配置报错
asset配置报错
            
            
              js
              
              
            
          
          webpack-socket-error validationError: Invalid options object. Compression Plugin has been initialized using an options that does not match the API scheema. 
- options has an unknow property 'asset'. These properties are valid: object { test?, include?, exclude?, algorithm?, compressionOptions?, threshold?, minRatio?, delteOriginalAssets?, filename?, cache? }解决方法:
修改compression-webapck-plugin配置
            
            
              js
              
              
            
          
          // 修改前
new CompressionWebpackPlugin({
    asset: '[path].gz[query]',
    algorithm: 'gzip',
    test: new RegExp(
        '\\.(' +
        config.build.productionGzipExtensions.join('|') +
        ')$'
    ),
    threshold: 10240,
    minRatio: 0.8
})
// 修改后
new CompressionWebpackPlugin({
    filename: '[path].gz[query]',
    algorithm: 'gzip',
    test: new RegExp(
        '\\.(' +
        config.build.productionGzipExtensions.join('|') +
        ')$'
    ),
    threshold: 10240,
    minRatio: 0.8
})文件路径重复报错
            
            
              js
              
              
            
          
          error in conflict: Mutiple assets emit different content to the same filename static/js/.gz修改compression-webpack-plugin配置
            
            
              js
              
              
            
          
          // 修改前
new CompressionWebpackPlugin({
    filename: '[path].gz[query]',
    algorithm: 'gzip',
    test: new RegExp(
        '\\.(' +
        config.build.productionGzipExtensions.join('|') +
        ')$'
    ),
    threshold: 10240,
    minRatio: 0.8
})
// 修改后
new CompressionWebpackPlugin({
    filename: '[path][base].gz',
    algorithm: 'gzip',
    test: new RegExp(
        '\\.(' +
        config.build.productionGzipExtensions.join('|') +
        ')$'
    ),
    threshold: 10240,
    minRatio: 0.8
})html-webpack-plugin 打包配置报错
            
            
              js
              
              
            
          
          (node:956) UnhandledPromiseRejectionWarning: Error: 'dependency' is not a valid chunk sort mode
at sortEntryChunks修改方法:
修改htmlwebpack-plugin配置参数chunksSortMode的值改为auto,或者去掉chunksSortMode参数
参考文章:html-webpack-plugin
optimization.moduleIds 配置的值错误
            
            
              js
              
              
            
          
          warning in configuration
The value 'hashed' for option 'optimization.moduleIds' is deprecated. Use 'deterministic' instead解决方法:
修改optimization.moduleIds的值为deterministic
参考文章:webpack优化配置