webpack3升级到webpack5

参考地址:webpack.docschina.org

依赖调整

包名 处理方式 版本
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

解决办法:

安装postcss@8.1.10

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优化配置

相关推荐
理想不理想v2 小时前
vue种ref跟reactive的区别?
前端·javascript·vue.js·webpack·前端框架·node.js·ecmascript
~甲壳虫12 小时前
说说webpack中常见的Plugin?解决了什么问题?
前端·webpack·node.js
Beamon__12 小时前
element-plus按需引入报错AutoImport is not a function
webpack·element-plus
CodeToGym12 小时前
Webpack性能优化指南:从构建到部署的全方位策略
前端·webpack·性能优化
~甲壳虫12 小时前
说说webpack中常见的Loader?解决了什么问题?
前端·webpack·node.js
~甲壳虫13 小时前
说说webpack proxy工作原理?为什么能解决跨域
前端·webpack·node.js
lin-lins1 天前
模块化开发 & webpack
前端·webpack·node.js
柳鲲鹏3 天前
LINUX/CMAKE编译opencv_contrib
linux·opencv·webpack
前端李易安3 天前
webpack的常见配置
前端·webpack·node.js
魏大帅。3 天前
Webpack入门教程:从基本概念到优化技巧
前端·webpack·node.js