尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Webpack 5构建优化实战:从定位瓶颈到体积瘦身的完整方案

Webpack 5构建优化实战:从定位瓶颈到体积瘦身的完整方案 说实话看到这个标题能点进来的人多半和我当初一样被Webpack 5的构建速度折磨过。我接手的那个公司核心项目启动一次要等四十多秒热更新都快赶上一次小型发布会了生产构建更离谱产物直逼8MBgzip之后还有2MB多首屏加载慢到运营天天在群里发截图催我。坦白讲构建优化这种事没有什么魔法一蹴而就它就是一堆小事叠加出来的结果。但如果你理清了优化路径用对了Webpack 5的Cache、多进程、SplitChunks这些能力效率提升会非常明显。这篇我就把这次Webpack 5构建优化实战完整复盘一遍。我会从“怎么定位瓶颈”讲起再一步步拆解构建速度优化、产物体积优化最后附上完整配置和踩坑实录。里面所有配置都是跑过真实项目的你照着改基本能少走几天的弯路。1. 构建优化先想清楚一件事慢在哪一步很多同学一上来就开始改配置说“Webpack慢就用thread-loader”。但我建议你先别急着动手先回答我一个问题你的时间到底花在编译上还是花在压缩上还是花在序列化和文件读写上连瓶颈都不清楚就乱上优化容易浪费时间甚至把一个本来没问题的项目改出问题。1.1 先用数据说话给Webpack做一次体检第一步是给构建过程做个体检。我用的方式是给Webpack挂一段计时脚本或者使用速度分析插件speed-measure-webpack-plugin。不过要提醒一下这个插件对Webpack 5的兼容性不是特别好我在实际使用中遇到过它输出了不准确数据的情况插件本身比较老。所以我的建议是先把插件跑起来看个大概方向再用自己写的计时脚本去验证关键节点。自己写计时脚本很简单在webpack.config.js里加一个自定义插件监听compilation、emit这些阶段记录时间差。大概长这样class TimePlugin { constructor() { this.startTime Date.now(); } apply(compiler) { compiler.hooks.beforeRun.tap(TimePlugin, () { this.startTime Date.now(); }); compiler.hooks.done.tap(TimePlugin, (stats) { const end Date.now(); console.log(总耗时: ${(end - this.startTime) / 1000}s); }); } }这样你至少能拿到一个总耗时。但真正要定位是哪个环节慢就要靠下面这几个数据编译阶段耗时loader处理时间、模块解析时间、构建依赖图时间。代码生成阶段耗时chunk生成、文件emit、source map生成时间。压缩阶段耗时terser、cssnano等压缩器的耗时。把这些时间段拆开之后你才能判断如果压缩阶段占了大头说明优化重点在压缩并行化如果编译阶段占大头说明loader缓存、多进程才是关键。我实际测下来很多中大型项目的耗时大头是压缩和source map生成很多人却一直以为是loader慢白白浪费了改动。1.2 大项目构建慢的四个典型瓶颈结合我带过的团队和实际项目经验Webpack 5构建慢通常逃不出下面这四个原因依赖体积和数量太大。node_modules里躺着几百个包每个包被解析、被转换整体开销成倍增长。loader配置过宽。babel-loader没有做include限制把node_modules也拉进去编译了或者让ts-loader去处理所有.ts、.tsx文件却没用transpileOnly开关。单进程编译和压缩。Webpack默认是单线程的loader链和压缩任务都挤在一起。项目小的时候感觉不到项目大了之后单线程就是最大的瓶颈。每次都重新编译没有缓存。Webpack 5之前没有成熟的持久化缓存很多人也没开cacheDirectory。结果就是改一行代码整个依赖图重新来一遍耗时全花在重复劳动上。这四点往往叠加。我在项目里还见过更夸张的ts-loader开了全量类型检查每次构建直接多出来20多秒。这不是Webpack的问题是配置问题。所以第二件事就是找到自己项目里最“贵”的那个环节。1.3 不要盲目改造先把优化目标定下来我建议在动刀之前先和团队约定一个可量化的目标比如开发环境冷启动从45秒降到10秒以内。热更新延迟控制在1秒内极端场景允许2秒。生产构建从3分钟降到60秒内。产物体积从8MB降到3MB以内。为什么非要先定目标因为优化是永无止境的没有目标你就不知道什么时候该停。构建从45秒降到9秒这个投资回报率是极高的但从9秒再降到6秒可能需要耗费同样甚至更多的精力实际收益却没那么大。项目优先要的是稳定可维护不是“最快构建性能大赛冠军”。2. 产物体积优化先想清楚你的包为什么会这么大构建速度之外压缩产物体积是另一个大工程。很多人会有个误区觉得体积大是因为“代码多”。其实很多时候不是因为功能多而是因为重复打包、全量引入、压缩不到位。下面把体积问题拆细。2.1 用Bundle Analyzer看清楚谁吃掉了你的体积我先用webpack-bundle-analyzer把所有模块的可视化图生成出来。它的配置很简单在plugins里加一个const BundleAnalyzerPlugin require(webpack-bundle-analyzer).BundleAnalyzerPlugin; // webpack.config.js module.exports { plugins: [ new BundleAnalyzerPlugin({ analyzerMode: static, reportFilename: ../dist/report.html, openAnalyzer: false, }), ], };跑一次构建之后打开生成的report.html你会看到一张巨大的可交互矩形图。我当时看到的第一眼心里凉了半截一眼望去antd的图标库占了一大块moment.js的时间处理库又占了一大块几个业务模块反复出现。而这种“不知道谁占了体积”的项目通常就是没有做按需引入和代码分割。2.2 体积膨胀的三宗罪全量引入、重复打包、不压缩组件库全量引入。很多项目里import { Button } from antdCSS也是直接import antd/dist/antd.css整个组件库样式全进来了。这个只要改成按需引入体积立刻能降一大截。如果项目已经上了antd 4.x配合babel-plugin-import这套按需引入已经很成熟可以放心用。重复打包。多个chunk引用了同一份公共依赖比如React、Redux这些如果不做splitChunks这些依赖会被各自打包进不同chunk导致重复体积。更隐蔽的是版本冲突A依赖lodash 4B依赖lodash 3最后两份都进了产物。Bundle Analyzer里能看到同一类库出现多个色块那就是重复了。没开压缩或压缩配置不全。有人只压缩了JS没压缩CSS只用了默认的terser没开parallel没启用gzip/brotli。这些都属于“做了一半的优化”。2.3 制定体积瘦身清单按收益排序拿到报表后不要眉毛胡子一把抓我把收益排序给你组件库按需引入这一项通常能砍掉几百KB到1MB。splitChunks拆分公共chunk能避免重复通常能减少20%~30%的打包体积。动态import路由懒加载把首屏体积从“全量”变成“当前路由”。换掉重依赖比如用dayjs替代moment.js用lodash-es配合tree shaking。开启压缩gzip这个几乎是无痛的收益却立竿见影。排序逻辑很简单先做不影响代码结构的再做需要改代码的先做风险低的再做改动面大的。这样每一步都有正反馈团队也愿意配合。3. 构建提速的核心手段一步步把耗时压下来这一章是这次优化里面最核心的部分。我会给你一份可以直接抄走的生产级配置每一项都会解释清楚为什么这么配、有什么注意点。3.1 限定loader的活动范围include/exclude与cacheDirectory先说最基础也是很多人容易忽略的一个点babel-loader默认遍历所有文件包括node_modules。你让它处理node_modules里动辄几MB的第三方包纯属浪费CPU。我的做法const path require(path); module.exports { module: { rules: [ { test: /\.jsx?$/, exclude: /node_modules/, use: { loader: babel-loader, options: { cacheDirectory: true, cacheCompression: false, }, }, }, ], }, };exclude: /node_modules/是必须的cacheDirectory: true可以让babel-loader把转换结果缓存起来二次构建的时候命中缓存。cacheCompression: false的意思是缓存文件不做gzip压缩缓存读写会快一点代价是磁盘占用稍大对大多数人来说划算。注意并不是所有第三方包都不需要转译。如果某个npm包发布的代码里有高版本ES语法且没有提供main指向ES5产物你就不能简单exclude。老项目里遇到过一个小插件直接发布ES2020导致低版本浏览器报语法错误。解决办法是把exclude改成更精确的写法只exclude那些确定能用的包或者反过来用include把需要转译的业务目录圈出来。3.2 真正值得用的多进程加载器thread-loader与更优替换thread-loader可以把后续loader的工作丢进worker池并行处理。它的原理很直观Webpack默认单进程就像只有一个厨师的厨房菜多就要排队。thread-loader相当于多请了几个帮厨。const path require(path); module.exports { module: { rules: [ { test: /\.jsx?$/, exclude: /node_modules/, use: [ { loader: thread-loader, options: { workers: 2 } }, { loader: babel-loader, options: { cacheDirectory: true }, }, ], }, ], }, };注意几个坑thread-loader有进程启动和通信开销处理速度快的loader用了反而更慢。所以只对babel、ts这类重量级loader开启。thread-loader的worker和babel-loader的cacheDirectory组合时要小心缓存目录权限或者进程间的缓存读写问题。我在Windows上遇到过奇怪问题后来把cacheDirectory关掉改为依赖Webpack 5的持久化缓存。新项目或能承受改造成本的可以考虑esbuild-loader或swc-loader。它们用原生语言实现转译单挑的速度几乎是babel的十几倍。但我也要提醒你esbuild不支持所有babel插件做代码转换时语义会有差异上生产前必须全量跑一遍测试和构建。对老项目我建议逐步引入先在某个新模块里试用别一把梭全量替换。3.3 核心武器Webpack 5的持久化缓存Webpack 5官方推出了内置的持久化缓存这个对构建速度的提升是革命性的。以前我们用babel-loader的cacheDirectory只能缓存转译结果Webpack的module graph、resolve结果等很多中间产物还是每次都要重算。现在这些都可以直接缓存到磁盘。配置非常简单module.exports { cache: { type: filesystem, buildDependencies: { config: [__filename], }, }, };type: filesystem会把编译中间产物缓存到node_modules/.cache/webpack目录。下次构建时只要文件内容没有被修改Webpack会直接复用之前的解析结果和转换结果速度提升肉眼可见。这里有两个细节值得说一下buildDependencies配置。如果你的构建配置本身比如webpack.config.js、postcss.config.js、babel.config.js改了整个缓存应该失效。日常开发中你改了babel配置却还在用旧缓存很容易出现诡异的报错。加上buildDependencies之后Webpack会监测这些配置文件变了就自动失效。缓存失效的常见情况。有时候你改了业务代码但Webpack仍然用旧缓存表现就是改了代码没生效或者模块解析不对。这种时候先手动删掉node_modules/.cache再重新构建排查起来很快。3.4 解析加速resolve配置别小看模块解析也是构建时间里很隐蔽的一部分。每次import xxxWebpack都要去按规则找文件找到之后还要解析文件类型。如果你的配置里面连着十几个extensions还是用默认的node_modules递归往上找那解析耗时自然高。我的建议配置module.exports { resolve: { extensions: [.js, .jsx, .ts, .tsx], alias: { : path.resolve(__dirname, src), }, modules: [path.resolve(__dirname, node_modules), node_modules], }, };extensions只留项目实际用到的后缀别把.json、.wasm什么都塞进去。alias能把绝对路径缩短同时避免深层级解析。特别是你用了指到src目录能减少不少路径解析开销。modules指定先查找项目内的node_modules避免像蜗牛一样一层层往上找。这块提升不会像cache那么夸张但积少成多。3.5 devtool选择source map策略导致的构建耗时差异开发环境默认经常有人直接devtool: source-map这个配置在大型项目里极其耗时因为它要做最完整的source map生成。实际上开发环境根本不需要这么完整浏览器只要能正确映射到原始源码就够。我建议的开发环境方案module.exports { mode: development, devtool: eval-cheap-module-source-map, };eval-cheap-module-source-map生成速度快同时保留了模块语义浏览器里能看到原始源码和模块路径调试体验基本无差。生产环境的source map如果必须保留我建议生成成.map文件后上传到监控平台比如Sentry而不是直接暴露在dist目录既避免源码泄露也能减小线上资源体积。但只是想减小体积的话生产环境完全可以把devtool关掉或设置成hidden-source-map。3.6 压缩并行化不要忽略terser的parallel很多人优化构建只盯着loader其实对于生产构建来说代码压缩才是最耗时的一环。Webpack 5内置的TerserPlugin如果不显式配置默认会开启parallel: true但这并不代表不需要配置。我的生产配置长这样// webpack.prod.js const TerserPlugin require(terser-webpack-plugin); const CssMinimizerPlugin require(css-minimizer-webpack-plugin); module.exports { optimization: { minimizer: [ new TerserPlugin({ parallel: true, terserOptions: { compress: { drop_console: true, }, }, }), new CssMinimizerPlugin({ parallel: true, }), ], }, };drop_console: true会移除console.log这个对生产体积和性能都有帮助但要注意线上需要日志排查问题的时候别开。更多时候我们会把它做成环境变量控制的参数而不是写死在配置里。另外CSS压缩默认没有开启很多人都漏了CssMinimizerPlugin结果CSS一直没压缩过却不自知。4. 体积瘦身组合拳splitChunks、Tree Shaking、动态导入构建速度提上来之后就要开始解决体积问题了。这一章里三个词大家都很熟但真正把它们用到位的项目并不多。4.1 splitChunks把公共依赖从重复打包里救出来Webpack 4之后就内置了splitChunks默认会做一些自动拆包。但默认配置对大型项目来说远远不够它只会抽取体积大于30KB的公共模块而且不会做特别细的分层。想要掌控拆包效果还是要自己配置。我用的配置module.exports { optimization: { splitChunks: { chunks: all, cacheGroups: { vendor: { test: /[\\/]node_modules[\\/]/, name(module) { const match module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/); return npm.${match ? match[1].replace(, ) : unknown}; }, priority: 10, chunks: all, }, common: { name: chunk-common, minChunks: 2, priority: 5, chunks: all, enforce: true, }, }, }, }, };这个配置把node_modules里的依赖按包名拆成一个个独立chunk这样当某个npm包被多个业务模块引用时它只会被加载一次浏览器也能利用长缓存命中不需要因为改了业务代码就把第三方库重新下载一遍。这里有个常见的误区拆分得越细越好。不是的。chunk太多会导致HTTP请求数量暴增特别是HTTP/1.1时代浏览器对同域并发请求数有限制拆出几百个chunk反而会让首屏加载更慢。如果项目已经上了HTTP/2chunk多一些问题不大但也要权衡。我建议你先用默认配置跑一次再根据Bundle Analyzer的结果针对性调整而不是直接套别人的大而全配置。4.2 Tree Shaking的原理与配置让未使用的代码真正消失Tree Shaking的原理是基于ES Module的静态分析能力在打包时把未被引用的export标记为副作用并剔除。听起来很美好但实际能生效需要满足三个条件代码必须是ES Module语法import/exportCommonJS的require/module.exports是无法静态分析的。所以构建配置里Babel别把ESM转成CommonJS。有点反直觉的地方是很多人为了让老浏览器支持会把ESM转成CommonJS结果Tree Shaking就失效了。Webpack官方推荐的姿势是在Webpack处理后再转而不是Babel提前转。如果你用babel/preset-env可以这样module.exports { presets: [ [babel/preset-env, { modules: false }], ], };一定要标记sideEffects。在package.json里设置{ name: my-project, sideEffects: [ *.css, *.scss ] }告诉Webpack除了CSS这类文件其他模块都没有副作用可以安全删除。这一步非常关键很多项目没写sideEffects导致Webpack不敢删除任何未使用代码。使用能支持tree shaking的第三方库版本。像lodash如果引入lodash全量包tree shaking几乎没效果换成lodash-es才能让按需引入真正生效。antd 4之后也提供了ESM版本配合babel-plugin-import或直接按需路径引入能大幅减少打包体积。4.3 动态import路由懒加载是一本万利的优化动态import是前端首屏体积优化最划算的手段之一。原理也简单把路由组件变成按需加载用户访问哪个路由才下载对应的JS。路由配置改造示例import { createBrowserRouter } from react-router-dom; const Home React.lazy(() import(/pages/Home)); const List React.lazy(() import(/pages/List)); const Detail React.lazy(() import(/pages/Detail)); const router createBrowserRouter([ { path: /, component: Home }, { path: /list, component: List }, { path: /detail, component: Detail }, ]);Webpack会把每个动态import的模块单独打包成一个chunk。这样首屏只加载必要模块其他页面走按需加载。懒加载也有坑组件级别懒加载比如弹窗、表格里的某个大组件如果使用不当会造成交互时白屏等待。我建议只对路由级别和体积特别大的业务组件做懒加载普通小组件不需要。动态import的chunk名需要配置魔法注释不然一堆乱码chunk排查问题非常痛苦const Detail React.lazy(() import(/* webpackChunkName: detail */ /pages/Detail));懒加载会带来额外的网络请求和路由切换体验问题。建议配合Suspense和骨架屏避免用户看到白屏。4.4 gzip与brotli线上服务器压不压缩决定了用户能不能秒开打包层面的压缩只能减小文件体积但传输层的压缩才能真正减少网络传输时间。很多团队只做了Webpack打包优化没做服务端压缩配置白白浪费前面的努力。生产环境我建议用compression-webpack-plugin生成.gz和.br文件然后让Nginx开启对应压缩。Webpack插件部分配置const CompressionPlugin require(compression-webpack-plugin); module.exports { plugins: [ new CompressionPlugin({ algorithm: gzip, test: /\.(js|css|html|svg)$/, threshold: 10240, minRatio: 0.8, }), new CompressionPlugin({ algorithm: brotliCompress, filename: [path].br, test: /\.(js|css|html|svg)$/, threshold: 10240, }), ], };之后Nginx开启gzip或brotligzip on; gzip_types application/javascript text/css application/json; gzip_proxied any;注意如果Webpack已经生成了.gz文件Nginx通常会直接使用静态压缩文件需要配置gzip_static on;不会再重复压缩。如果没配置Nginx会动态压缩开销反而大。另一个坑是brotli压缩级别高时构建时间会明显变长建议在CI中生成.br文件而不是本地构建。4.5 外部化和CDN什么时候该用externals对于一些超大的、基本不会变的第三方库比如React、Vue、ECharts可以用externals把它们从打包产物里排除掉并在HTML里直接通过CDN script标签引入。这样打包体积能骤减CDN又能提供快速的全球分发。配置示例module.exports { externals: { react: React, react-dom: ReactDOM, echarts: echarts, }, };然后在HTML模板里引入CDNscript srchttps://cdn.example.com/react/18.2.0/react.production.min.js/script script srchttps://cdn.example.com/react/18.2.0/react-dom.production.min.js/scriptexternals的坑在于CDN地址必须稳一旦CDN挂了页面直接崩。大厂会用自建CDN或采购多家CDN做冗余。版本要锁定不然哪天CDN默认版本悄悄升级React兼容性出问题都查不出来。开发环境和生产环境要区分开发环境还是用本地依赖方便调试不然断网没法开发。4.6 资源文件的处理图片、字体别让它们白占体积除了JS和CSS图片和字体经常是体积隐形杀手。Webpack 5的Asset Modules已经内置了静态资源处理配合type: asset可以实现小图片自动内联为base64大图片保留为文件module.exports { module: { rules: [ { test: /\.(png|jpe?g|gif|svg)$/, type: asset, parser: { dataUrlCondition: { maxSize: 8 * 1024, // 8KB以下转base64 }, }, }, ], }, };这个策略的意义在于小图片内联可以减少HTTP请求大图片保留文件可以避免JS体积被无限撑大。我见过有的项目把maxSize调到1MB结果几张大图全被塞进JS文件打包产物直接爆炸这是典型矫枉过正。字体同理保留为静态资源尽量用woff2格式替代ttf/otf体积能小一半以上而且现代浏览器都支持。5. 实测数据对比与踩坑记录讲完所有优化方法下面是最具价值的部分我在真实项目上的优化结果、以及遇过的问题。5.1 优化前后数据对比这是我在一个中等规模React项目大约200个路由40个公共组件库上实测的数据指标优化前优化后提升幅度开发环境冷启动45秒6秒86.7%热更新延迟约3秒800ms73.3%生产构建耗时3分20秒55秒72.5%打包产物体积8.1MB2.6MB67.9%gzip后传输体积2.3MB780KB66.1%各手段贡献占比按我自己的观察排序持久化缓存开发构建40%。loader多进程限定范围25%。splitChunks和按需引入20%。动态import路由懒加载10%。压缩与gzip5%。当然不同项目比例完全不一样这个数字仅供参考但它至少说明cache绝对是Webpack 5最大的红利应该第一时间用起来。5.2 优化过程中踩过的坑坑一thread-loader导致磁盘占用过高在CI环境里使用thread-loader跑构建worker数量开到了CPU核数结果内存和磁盘占用直接拉满构建失败。后来检查发现CI机器CPU核数很多workers数量也跟着变大但内存不够。解决方案是显式限制workers: 2并在CI上关闭thread-loader或减少workers。坑二cache.filesystem导致改代码不生效有次同事说“改了代码但页面没变化”排查半天发现是持久化缓存的问题。原因是他改了src/router/index.js但路由文件被其他文件通过别名引用而resolve缓存把旧路径缓存住了。最后删了node_modules/.cache问题消失。之后我建议团队在改动Webpack配置或升级依赖后先清缓存再构建不用怀疑别的地方。坑三antd按需引入后样式乱了这个很经典。项目在打包体积优化时加了babel-plugin-import做按需引入结果Button的样式对了Modal的样式却乱了。查了以后发现是因为项目中有些地方直接import { Modal } from antd有些地方import Modal from antd/lib/modal两套引入方式混用babel-plugin-import只处理了前者后者输出了不同类型的副本。统一成一种引入方式并删掉手动引入的样式之后解决。坑四node-sass和sass-loader的版本兼容这个属于老生常谈。升级Node版本之后node-sass编译老报错后来把node-sass换成了sassdart-sass配置里也改了loader对应项。不过dart-sass有少数不兼容的语法比如/除法、老的import行为改完要全量构建一次把报错修完再上线。坑五source map导致的生产环境源码泄露有次安全扫描报告说dist目录暴露了JS源码原因是生产构建配置里用了devtool: source-map.map文件直接放在了线上。这是很严重的风险点。后来生产环境改成devtool: false或hidden-source-map.map文件只用于收集错误堆栈不上传到公开目录。5.3 一套可以直接用的完整配置骨架最后我把经过实战验证的配置骨架贴在这里。开发环境和生产环境分开两个配置文件公共配置抽出来。// webpack.common.js const path require(path); module.exports { entry: ./src/index.js, resolve: { extensions: [.js, .jsx, .ts, .tsx], alias: { : path.resolve(__dirname, src) }, modules: [path.resolve(__dirname, node_modules), node_modules], }, module: { rules: [ { test: /\.jsx?$/, exclude: /node_modules/, use: [ { loader: thread-loader, options: { workers: 2, workerParallelJobs: 50 }, }, { loader: babel-loader, options: { cacheDirectory: true, }, }, ], }, { test: /\.(png|jpe?g|gif|svg)$/, type: asset, parser: { dataUrlCondition: { maxSize: 8 * 1024 } }, }, ], }, cache: { type: filesystem, buildDependencies: { config: [__filename] }, }, };// webpack.dev.js const { merge } require(webpack-merge); const common require(./webpack.common.js); module.exports merge(common, { mode: development, devtool: eval-cheap-module-source-map, devServer: { historyApiFallback: true, hot: true, }, });// webpack.prod.js const { merge } require(webpack-merge); const common require(./webpack.common.js); const TerserPlugin require(terser-webpack-plugin); const CssMinimizerPlugin require(css-minimizer-webpack-plugin); module.exports merge(common, { mode: production, devtool: false, optimization: { minimize: true, minimizer: [ new TerserPlugin({ parallel: true, terserOptions: { compress: { drop_console: process.env.NODE_ENV production }, }, }), new CssMinimizerPlugin({ parallel: true }), ], splitChunks: { chunks: all, cacheGroups: { vendor: { test: /[\\/]node_modules[\\/]/, name(module) { const match module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/); return npm.${match ? match[1].replace(, ) : unknown}; }, priority: 10, chunks: all, }, common: { name: chunk-common, minChunks: 2, priority: 5, chunks: all, enforce: true, }, }, }, }, });这套配置是我个人比较推荐的起点不代表一定适合所有项目。比如如果你没有用antd就去掉babel-plugin-import相关配置如果路由不多动态import的收益也不会很大。Webpack 5构建优化的本质就是把“每一次构建都在做重复劳动”改成“能缓存就缓存能并行就并行能按需就按需”。这三个原则比任何具体配置都重要。我在这个项目里最大的体会是不要为了炫技而优化也不要一次性把所有手段都铺上去。每次只做一个改动跑一次构建看数据记录结果再决定下一步。这样即使出了问题也能精准回滚。你翻车之后才会发现构建优化最怕的不是慢而是改了之后项目直接跑不起来排查半天却发现是配置互相冲突。最后再分享一个小技巧优化完成之后记得把旧的构建产物和缓存目录都清一遍用完全干净的环境验证最终结果。因为很多优化效果会被缓存“美化”真实用户可没有本地缓存。务必让团队在干净环境里一起验收确认数据没有水分再发上线。希望这篇实战复盘能让你少踩几个坑我们的目标是一样的让构建快一点让用户少等一点。
返回列表