本文作者:xiongxiao01在尝试升级webpack5之前,建议大家先尽可能阅读官方文档,这样可以少走很多弯路。本文基于具体的业务场景。总结补充。backgroundmusic-musician-web-node是音乐家场景的核心应用。它涵盖了许多页面和大量代码。在使用webpack4的情况下,本地开发的编译效率一直不是很好。笔者使用的MacBookProM1是以musicians+copyrights一共45页,开始fullbuild需要140s左右(加入了happypack等并行打包策略)。增量构建一般需要4-5s,但是一旦修改了引用的数量,比如withthepublictsdefinition,增量编译时间一次可以达到80s以上。因此,随着业务需求的增加,提升需求交付效率,解决开发体验问题变得十分迫切。在解决开发体验方面,升级webpack是带来巨大收益的最快捷直接的方式。webpack5带来的升级毕竟从webpack4到webpack5有很多breakchanges。为了让大家有升级的热情,还是要展示一下升级带来的提升。我们用创作者中心的数据来说明。在上面的背景中,我们已经说过,原来开发时webpack启动和增量构建的时间分别是140s,平均4-5s。这里我们直接列出升级后的结果。启动时间减少,webpack启动时间缩短到55s左右。增量构建时间减少了近60%,增量构建时间非常夸张,直接到1s左右。甚至可能导致构建时间达到80s以上的ts定义修改也被降低到3s左右,生产包平均减少80%以上。之前本地构建时间大约240s,升级后200s左右。注意:务必将terser-webpack-plugin升级到最新版本,否则与webpack4相比,生产包构建时间可能会减少。包体积变化因为创作者中心的项目页面比较多,所以不好比较webpack4和webpack5打包结果的体积变化,但是从官方的优化策略来看(这个优化策略也造成了很多breakchanges,将在下面详细描述)和根据许多实际结果,优化包大小。升级前的准备就此开始,我们正式开始webpack的升级。在正式升级之前,我们需要做一些准备工作,这样可以帮助我们避免在升级过程中出现一些奇怪的问题。升级webpack到最新版v4:如果你当前使用的版本是v4,升级应该是无痛的,但是如果webpack是v3甚至更早版本,请参考官方文档升级到v4,升级webpack-cli到最新版本会将使用的loader和plugin升级到兼容v4的最新版本:这里需要注意各个插件和Loader对webpack版本的要求,因为部分loader/plugins的最新版本只兼容webpack5,我们这里还没有升级到这一步的必要,因为每个项目使用的loader和plugin都有一些差异,这里不方便一一列举对应的版本。只能以作者自己的项目为例,比较常用的plugin和loaderwebpack4。列出了最新版本。其他的请根据自己项目的情况去npm或者github上找到readme或者阅读release记录。几乎所有符合标准的工具库都会给terser-webpack-plugin:webpack4请升级到4.x,webpack5升级到最新的babel-loader:不管是v4还是v5,都可以升级到7.x或者8.xextract-text-webpack-plugin:v4请升级到最新版,v5后替换为mini-css-extract-pluginoptimize-css-assets-webpack-plugin:v4升级到最新版,v5替换ts-loaderwithcss-minimizer-webpack-plugin:v4升级到8.x,v5升级到最新版本less-loader:7.x兼容webapck4sass-loader:10.x最后一个版本兼容withwebpack4css-loader:5.xisthelastversioncompatiblewithwebpack4postcss-loader:4.xisthelastversioncompatiblewithwebpack4...fixwarninganderrors完成以上前置准备后,会有一些告警甚至在运行编译过程时无一例外地出错。请解决这些问题。更改v4版本的过时措辞。v4版本的过时的写法是warning,在v5版本中会直接丢弃,所以我们需要根据官方的指引进行修改,否则升级webpack5后webpack不会启动optimization.hashedModuleIds:true→optimization.moduleIds:'hashed'optimization.namedChunks:true→optimization.chunkIds:'named'optimization.namedModules:true→optimization.moduleIds:'named'NamedModulesPlugin→optimization.moduleIds:'named'NamedChunksPlugin.chopt'HashedModuleIdsPlugin→optimization.moduleIds:'hashed'优化.noEmitOnErrors:false→optimization.emitOnErrors:trueoptimization.occurrenceOrder:true→optimization:{chunkIds:'total-size',moduleIds:'size'→optimization.splitChunks.cacheGroups.defaultVendorsoptimization.splitChunks.cacheGroups.test(module,chunks)→optimization.splitChunks.cacheGroups.test(module,{chunkGraph,moduleGraph})Compilation.entries→Compilation.entryDependencyserveisserveremoDevServerRule。查询(deprecatedsincev3)→Rule.options/UseEntry.options测试webpack5的兼容性非常重要。与webpack4相比,webpack5有非常显着的区别。webpack5为了优化bundlesize,默认不再支持nodepolyfill,所以一旦一些node的全局变量在node和浏览器环境的公共包内部使用,就会在runtime阶段造成非常严重的错误。为了尽早发现问题,我们需要在去掉node的全局变量的情况下测试代码的运行情况。注意:这里的写法只在webpack4测试兼容阶段使用。升级webpack5后记得去掉module.exports={//...node:{Buffer:false,process:false,},};添加以上代码后,先运行自己的代码,看看会不会遇到页面错误。注意这些错误是在runtime阶段,不是编译阶段,所以你要实际运行页面看看你的代码是直接还是间接依赖了node的process和Buffer变量,那你肯定会遇到如下报错ReferenceError:BufferisnotdefinedorReferenceError:processisnotdefined在实际业务场景中,我们往往在一个项目中有很多页面,每个页面都有很多状态,无法简单的看是否存在运行时错误,所以我建议读者直接把它当作代码中node全局变量的引用,然后在升级webpack5时手动进行polyfill,这样可以将出现问题的概率降到最低。具体怎么polyfill,接下来会讲到。开始webpack5升级以上的前期准备工作完成后,我们就可以开始正式的升级了。安装最新的webpack版本nenpminstall-Dwebpack@latest更改配置去掉optimization.moduleIds和optimization.chunkIds的配置,webpack5优化了chunkId和moduleId的默认生成策略,使用[hash]占位符会更高效直接用默认的地方可以换成[contenthash],后者效率会更高IgnorePlugin当入参为regexp时,写法改为newIgnorePlugin({resourceRegExp:/regExp/})对于webpack4如node.fs:'empty'写法,在webpack5中,节点属性只支持三个字段,global,__dirname,__filename,reference,所以这三个属性以外的节点属性需要放在resolve.fallback中,所以node.fs:'empty'需要改成resolve.fallback.fs:falseurl-loader,raw-loader,file-loader建议直接替换成AssetsModule,虽然暂时不会影响,但是在以后的versions,这三个loader为了优化可能去掉.splitChunks,在v5版本尝试参考下面的配置splitChunks推荐使用默认配置,或者直接optimization.splitChunks:{chunks:'all'}如果有这样的optimization.splitChunks.cacheGroups:{default:false,vendors:false}的写法,需要改成optimization.splitChunks.cacheGroups:{default:false,defaultVendors:false}需要更正或省略/*webpackChunkName:'...'*/在之前的代码逻辑中,我们会使用这个注释来编写代码拆分的chunk命名,但是在v5版本中,你不需要这样做。当模式为development时,webpack会自动用文件名命名Chunk指的是Json的变化。import{version}from'./package.json'的原始写法;控制台日志(版本);需要更改为从“./package.json”导入pkg;console.log(pkg.version);处理升级过程中的错误一般来说,在升级过程中,你会遇到三类问题:schema错误,webpack配置语法错误,这种错误很容易解决,webpack会提示错误原因和错误信息中有详细说明改进方法,按照提示修复即可编译报错解决此类问题并不难。最常见的是webpack5升级后,不再做node的polyfill,报modulenotfound。这里是webpack4官方默认的polyfill。可以根据业务场景报错,自行下载对应的npm模块,然后添加配置(不需要全部添加,根据报错内容按需添加)module.exports={//...解决:{回退:{断言:require.resolve('断言'),缓冲区:require.resolve('buffer'),控制台:require.resolve('console-browserify'),常量:require.resolve('constants-browserify'),crypto:require.resolve('crypto-browserify'),domain:require.resolve('domain-browser'),事件:require.resolve('events'),http:require.resolve('stream-http'),https:require.resolve('https-browserify'),os:require.resolve('os-browserify/browser'),path:require.resolve('path-browserify'),punycode:require.resolve('punycode'),process:require.resolve('process/browser'),querystring:require.resolve('querystring-es3'),stream:require.resolve('stream-browserify'),string_decoder:要求e.resolve('string_decoder'),系统:require.resolve('util'),定时器:require.resolve('timers-browserify'),tty:require.resolve('tty-browserify'),url:require。解决('url'),util:require.resolve('util'),vm:require.resolve('vm-browserify'),zlib:require.resolve('browserify-zlib'),},},};另一种可能的情况是,之前可以引用的npm包升级后不能再引用了,需要改一下写法。这种情况比较少见,但是创作者中心遇到过应用依赖的二方包依赖uuid库的情况。以前的写法是importuuidv4from'uuid/dist/v4';//...但是升级后这种写法编译的时候会报错,需要改成import{v4asuuidv4}来自“uuid”;错误是很难预测的,好在编译时还是有报错的痕迹。遇到他们之后,google其实问题不大。runtime阶段报错根据创作者中心的升级经验,runtime阶段报错的原因有两种。最常见的节点全局变量polyfill是节点polyfill的丢失。上面提到,一些node和browser共享的包会用到一些node全局变量(process,Buffer)。这些变量是没有require直接使用的,所以编译时不会暴露。为了解决这类问题,需要配置{plugins:[newwebpack.ProvidePlugin({Buffer:['buffer','Buffer'],process:'process/browser',}),],}使用ProvidePlugin注入变量要全局,注意这里下载对应的buffer和process/browser包。这里推荐大家加上buffer和process的polyfill,以防导入后变量丢失。这个其实是在升级过程中遇到的。有些npm包导出不是特别规范,webpack4版本会自动兼容,但是webpack5默认支持treeshaking,所以npm包的导出会比较严格,所以有一种情况,就是importwatermarkfrom'之后升级了watermark-dom,引用的变量未定义,没有需要改成import{watermark}from'watermark-dom'的警告和编译错误;这种运行时阶段的报错处理起来非常棘手,关键是不可预知,防不胜防。以上仅列举创作者中心升级过程中的运行时错误。不同的业务场景可能会遇到其他的错误,不要心存侥幸。唯一稳妥的做法是将升级的影响范围告知qa,让qa做一个完整的回归。部分加载程序优化删除了与缓存相关的加载程序和插件。webpack5对缓存的优化和利用已经很不错了。不需要使用webpack4中用来优化缓存的loader和plugin来提升性能。它只会引起未知的问题。建议全部去掉。将happypackhappypack替换为thread-loader的作者不再维护该模块,thread-loader是官方提供的多线程编译优化方案。据说它的性能要好得多。建议升级完成后更换。使用css-minimizer-webpack-plugin替换optimize-css-assets-webpack-plugin。此加载程序用于css代码压缩。官方建议将ts-loader替换为@babel/preset-typescript。推荐尝试一下,不仅配置简单了很多。一套babel配置就能吃掉所有js。同时在性能方面,亲身体验后感觉会快很多。但是@babel/preset-typescript不再使用tsc,所以编译时不会像ts-loader那样暴露编译错误。这里需要单独安装一个插件[fork-ts-checker-webpack-plugin](https://github.com/TypeStrong...)来检查编译过程中的语法Postscript中最难解决的问题webpack5升级是runtime阶段异常报错。这些错误与特定的业务场景相关联,无法一一列举。本文的目的也是基于当前业务场景的升级经验,提供一些解决问题的思路供大家参考。以上就是本次创作者中心对webpack升级的总结,希望对大家有所帮助。本文由网易云音乐技术团队发布。未经授权禁止任何形式的转载。我们常年招聘各种技术岗位。如果你准备换工作,又恰好喜欢云音乐,那就加入我们吧grp.music-fe(at)corp.netease.com!
