You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
webpack is a static module bundler for modern JavaScript applications. When webpack processes your application, it internally builds a dependency graph which maps every module your project needs and generates one or more bundles.
从结果出发
项目最近使用低代码前端框架amis进行开发,有很好的研发效率提升,但是构建速度却很慢,亟需进行优化。优化之后达到了将webpack构建速度提升80%左右的一个成绩,以下是优化前后的对比👇
30965ms ➡️ 6545ms
团队做了3件事情来达到这样的一个效果:
split-chunks
进行公共模块优化👇external
避免将比较大的第三方依赖打包到bundle中👇ts-loader
的优化:基于这次优化做了功课,看了一些资料,看看还有哪些可以优化的地方。
webpack是什么
官网的定义:
webpack is a static module bundler for modern JavaScript applications. When webpack processes your application, it internally builds a dependency graph which maps every module your project needs and generates one or more bundles.
也就是说 webpack 是一个用于现代 JavaScript 应用程序的静态模块打包工具,从入口出发,找到入口文件所有的依赖,生成浏览器可以用的bundle文件。webpack的出现使得前端的工程化更加地丰富。从webpack在2013的第一次release(v1.0.0-beta2)开始,至今已经有8、9年的历史了,是一个相当成熟的工具,其生态也比较完善,所以前端圈用webpack也是非常地广泛。
版本
尽量用较新的版本,新版本想较之前都会有一定的性能提升和优化,包括Node和Webpack。要注意的是
Node.js v8.9.10 - v9.11.1
ES6的Set
和Map
会有性能回退问题,现在LTS的node已经是v14.16.0
,所以假设Node
版本已经较新,并且用的是WP4
(webpack4
)。目前还不建议对求稳的或者已经很庞大的项目立即升级到WP5
,其一是因为webpack生态里面并不一定所有的插件都能跟的上最新的版本,可能会出现兼容性的问题;其二由于webpack5还并未被广泛地应用,到新版本的稳定和成熟还是需要一定的时间,为避免不必要的bug,建议暂时使用webpack4
。为什么要优化
对于开发者来说,每次在build的时候不希望花费较长的时间,优化构建速度能够减少开发成本;对于用户而言,优化bundle文件的数量和大小能减少用户的流失率,提升用户体验。所以webpack的性能优化是一个非常关键的技术手段。
优化手段
两个测量工具
speed-measure-webpack-plugin
(SMP),要对webpack的构建速度进行优化,得知道要优化的重点在哪里,而该插件则是帮助检查哪些地方需要进一步优化的工具。webpack-bundle-analyzer
,虽然webpack也有官方的分析工具,社区也有许多其他的工具可以参考,但是通过资料、技术分享以及项目经验,webpack-bundle-analyzer
用的还是不错的,它可以将bundle展示为交互式、可缩放的树状图形式,使用起来非常便捷。三个可优化阶段
webpack构建大概可分为loader解析 -> 依赖搜索 -> 打包等三个阶段,就这三个阶段我们分别展开阐述如何去优化。
loader解析:
include/exclude
,对于loader而言,不需要对项目中所有的文件进行文件转换,应将loader应用于最少数量的必要模块,常见的配置:如果项目中用到了
ts-loader
,那就要小心了,因为如果不做额外的配置,会发现构建速度是非常耗时的。原因是因为ts-loader
在每次构建的时候都会对所有文件进行类型检查,当项目越来越庞大,会发现构建速度越来越慢。这个时候需要设置transpileOnly: true
来提高构建速度,该配置只处理编译而不做类型检查;然而类型检查是使用TypeScript
的初衷,可以使用fork-ts-checker-webpack-plugin
插件来在单独的进程中做类型检查。那性能和类型检查都能cover到。如果使用的是
babel-loader
,可以设置其cache相关的选项,比如cacheDirectory
、cacheCompression
等;cache-loader
: 利用文件的modifier time来检查文件是否更新,如果没有更新则利用缓存的内容,是一个轻量级的比较。特点是在第一次构建的时候比较慢,后面的构建会快很多。但是用它也要特别注意,最好用在性能消耗比较昂贵的地方,否则基本没有什么效果。该loader已经被作者Archive了,因为webpack5内置了cache的相关配置,将来如果升级就不需要它了。使用cache-loader时要放在其他loader的前面。thread-loader
:也是应用于比较昂贵的地方,可以将打包任务划分多个node进程,把模块一次分配给这些进程,实现多进程构建。跟cache-loader
一样也需要放到其他loader的前面。最后一点是,尽量少用工具,因为每个loader/plugin都有其启动时间,不用就不会有性能问题啦。
依赖搜索:
减少
resolve.modules
,resolve.extensions
等 中条目数量,因为IO操作比较消耗性能;基本上webpack对这些配置有默认值,比如
resolve.modules
为node_modules
,告诉webpack解析模块时应该搜索node_modules
目录;resolve.extensions
默认值为['.wasm', '.mjs', '.js', '.json']
,如果用了TypeScript
还是要配置一下的,extensions
是说在引入模块时可以不需要带扩展:打包: Smaller = Faster
splitChunks
,本着“小即是快”的原则,尽量使chunk包越小越好。在webpack4之前,可以使用CommonsChunkPlugin
来避免模块与模块之间的重复依赖,webpack4内置了optimization.splitChunks
,可开箱即用。splitChunks
有它默认的行为,不同的项目根据需求做不同的调整。可以设置不同的cacheGroup,拆分前必须共享模块的最小chunk数量等等,能最大程度地优化重复依赖的问题。一个简单的🌰 :externals
,防止将某些 import 的包打包到 bundle 中,而是在运行时再去从外部获取这些扩展依赖。例如:当然需要在
index.html
里面引入cdn依赖,否则在runtime无法找到相应的模块:<script src="https://unpkg.com/moment@2.29.1/min/moment.min.js"></script>
。多环境
生产环境: 生产环境关注与压缩bundle、更轻量的source map等,建议不同环境写不同的配置,当然可以有共用的配置,利用
webpack-merge
可以实现配置共用;对于devTools,推荐使用source-Map
,相对于inline-source-map
和eval-cheap-module-source-map
性能好一点;代码压缩,在WP5中内置了terser-webpack-plugin
,现在使用WP4的话,需要安装插件,这个插件功能非常强大,除了基本的压缩功能以外,还可以使用多进程并发构建,以及去除注释等功能;不带路径的配置,path-info
会在bundle中包含模块信息的注释,但在庞大的项目中,会导致GC性能很差,应该关闭;开发环境: 同样地,生产环境有些配置也不适用于开发环境,比如
TerserPlugin
就不需要,因为在开发环境中压缩代码是没有意义的;devTools的最佳实践是eval-cheap-module-source-map
,我现在的项目比较轻量,但是也能看出对比:虽然是不到1000ms的差距,苍蝇肉也是肉不是?而且将来代码量越来越庞大的时候,差距就更明显了。
当然还有其他的可以优化的方法,比如使用ES module,能更好地利用webpack的tree shaking功能;Dll,为更改不频繁的代码生成单独的编译结果,但却是一个配置比较复杂的过程;还有对图片的压缩等等。以上是对于webpack4性能优化基本的配置,期待webpack5成熟稳定的那一天。
参考:
The text was updated successfully, but these errors were encountered: