依赖调整
包名 | 处理方式 | 版本 |
---|---|---|
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优化配置