技术文章

技术慢生活
2026-06-10 10:52
阅读 1285

入职两个月我重构了公司的前端构建流程

刚入职新公司两个月,目前还在试用期的“生死线”上疯狂试探。平时除了写业务代码,我最大的爱好就是扒各种开源项目的源码,对性能优化更是有着近乎偏执的狂热。顺便提一嘴,作为一个折腾狂,市面上各种AI编程工具我基本都试了个遍,从GitHub Copilot、Codeium到各种套壳大模型插件,最后兜兜转转还是把主力工具换成了Cursor。不得不说,Cursor对上下文的理解和多文件编辑能力确实是降维打击,现在写代码基本离不开它了。

今天想跟大家聊聊我最近干的一件“疯狂”的事——重构了公司老项目的前端构建流程。

事情是这样的,上周五晚上快下班的时候,产品经理拿着杯奶茶凑过来,说线上有个紧急的客诉Bug需要马上修复。我一看,小问题,五分钟搞定。改完代码准备提测,顺手跑了个 npm run build 准备打包验证。结果你猜怎么着?进度条卡在 98% 足足四分半钟没动!当时看着终端里幽幽的光,我真的想砸电脑。

等包打完,天都黑透了。测试小姐姐也跟我吐槽,说每次发版等构建的时间,都够她刷完两个短视频了。作为对性能优化有执念的人,这能忍?于是周末我加了个班,决定深入理解一下咱们这套祖传的构建工具,顺手把流程给优化了。

咱们老项目用的是 Webpack 4,里面堆满了各种老旧的 loader 和 plugin。我先是跑了个 speed-measure-webpack-plugin 看看瓶颈在哪,好家伙,不看不知道,一看吓一跳。除了常规的 babel-loader 慢得离谱,还有一个自定义的 svg-sprite-loader 简直是性能杀手,每次构建都要吃掉将近 40 秒。

因为刚来两个月,直接上 Vite 或者 Turbopack 这种 Rust 系的构建工具风险太大。业务代码里一堆 CommonJS 的写法,还有各种魔改的 Webpack 特有 API,强行迁移大概率会导致线上事故,到时候试用期就直接“毕业”了。权衡之下,我决定先在 Webpack 5 的基础上做深度优化。

第一步,升级 Webpack 5 并开启持久化缓存。这步其实很简单,但收益极大。

// webpack.config.js
module.exports = {
  // ...
  cache: {
    type: 'filesystem',
    buildDependencies: {
      config: [__filename],
    },
  },
};

开启 filesystem 缓存后,二次冷启动的时间直接从 120 秒降到了 20 秒左右。这感觉就像是从绿皮火车换上了高铁。

第二步,榨干 CPU 的多核性能。老项目用的是单线程构建,现在的 CPU 都是八核十六线程了,闲着也是闲着。我引入了 thread-loader,把耗时的 babel-loader 和那个万恶的 svg-sprite-loader 扔进 worker 池里并行处理。

const os = require('os');
const threadLoader = require('thread-loader');

threadLoader.warmup(
  {
    workers: os.cpus().length - 1,
  },
  ['babel-loader', 'svg-sprite-loader']
);

第三步,缩小构建范围。我把 ECharts、Lodash 和 React 这些体积大且不怎么变动的基础库,通过 externals 配置剥离出去,走公司的 CDN。这不仅让打包体积瘦了 30%,构建速度也跟着提了上来。

搞定这些常规操作后,重点来了:怎么优化那个自定义的 svg-sprite-loader

为了搞清楚这个 loader 到底在干嘛,我打开了最近很火的 Zed 编辑器。不得不说,Zed 用 Rust 写的底层确实丝滑,打开咱们项目那好几个 G 的 node_modules 都不带喘气的。以前在 VSCode 里搜这种跨文件的复杂逻辑,经常卡得我想死,现在用 Zed 简直是一种享受。

更绝的是,我直接使用了 Zed 内置的 AI搜索 功能。我把那段几百行的 loader 源码和相关的调用链路选中,让 AI 帮我分析性能瓶颈。几秒钟的时间,AI 就把核心问题给我揪出来了:这个 loader 在每次构建时,都在全量遍历 node_modules 去匹配 SVG 文件,而且没有做任何文件系统的缓存,导致大量的磁盘 I/O 和内存分配。

找到病因就好办了。我借助 Cursor 的多文件编辑能力,快速重构了这个 loader。把全量遍历改成了基于 watchpack 的增量监听,并且引入了 lru-cache 对解析结果做内存缓存。改完一跑,那个 40 秒的毒瘤瞬间缩短到了 3 秒!当时看着终端里飞速滚动的日志,心里那叫一个舒坦。

周一上班,我把优化后的代码提了 PR。为了说服技术总监,我还专门做了一份详细的性能对比数据:

构建场景 优化前耗时 优化后耗时 提升幅度
本地冷启动 (dev) 125s 18s 85.6%
本地热更新 (HMR) 3.5s 0.4s 88.5%
生产环境打包 (build) 280s 65s 76.7%
内存峰值 2.1GB 850MB 59.5%

总监看完数据,当场在群里@我表扬了一波,还顺带批了个小奖金,美滋滋。测试小姐姐也跑来问我是不是偷偷给服务器升级了,怎么发版这么快。

回顾这次重构,我有几点比较深的体会。

首先,构建工具的选型和升级不能盲目追新。虽然 Vite 很快,但在复杂的历史包袱面前,稳扎稳打地在现有体系上做深度优化,往往是性价比最高、风险最低的选择。技术选型永远要服务于业务场景和团队现状。

其次,工欲善其事,必先利其器。这次能这么快定位到 loader 的底层逻辑问题,Zed 和它的 AI搜索 功能功不可没。研究开源源码或者排查复杂工程问题时,一个响应迅速且具备强大上下文分析能力的编辑器,真的能帮你省下大把掉头发的时间。当然,平时写业务代码,我还是会切回 Cursor,两者搭配,干活不累。

最后,性能优化不仅仅是线上运行时的优化,开发体验(DX)的优化同样重要。把构建时间从 4 分钟缩短到 1 分钟,一天哪怕只构建 10 次,就能帮团队省下半个多小时。这半个多小时,大家用来摸鱼或者喝杯咖啡,团队的幸福感和战斗力绝对直线上升。

现在试用期算是稳了,接下来我打算把这套优化经验沉淀成团队的最佳实践文档。如果你也在被老旧项目的构建速度折磨,不妨试试从这几个维度去扒一扒你的构建配置,说不定会有意想不到的惊喜。不说了,产品经理又拿着奶茶过来了,我先去改 Bug 了。

评论 0

最热最新
暂无评论
技术慢生活Lv.1
0
影响力
0
文章
0
粉丝