前端工程化,从脚手架到上线的一地鸡毛
上周五晚上十一点半,我正戴着 AirPods 听着《Lover Boy 88》,一边啃冷掉的麦当劳巨无霸,一边盯着 CI/CD 流水线卡在最后一步——部署失败。屏幕上红色的报错信息刺得我眼睛疼:“Error: EACCES: permission denied, open '/app/dist/index.html'”。那一刻我真的想砸键盘。明天就是婚礼前最后一次婚纱试穿,结果我还在这儿跟权限问题死磕。
我是上海某二线互联网公司的前端,白天写代码、晚上备婚,最近还在偷偷啃 Rust(别问,问就是被隔壁组大佬安利的)。公司项目节奏快得离谱,产品经理上周五提的需求,这周一就要上线——还是个涉及全站重构的大改版。在这种“既要马儿跑又要马儿不吃草”的环境下,前端工程化成了我们团队活下来的救命稻草。
为什么我们非搞工程化不可?
去年双11期间,我们线上崩了一次。原因特别蠢:两个同事分别写了两套重复的 utils 函数,一个叫 formatDate,另一个叫 dateFormat,结果在某个边界场景下返回格式不一致,导致订单页面渲染异常。测试没覆盖到,运维半夜打电话叫醒我,我在床上边哭边修 Bug。
那之后,领导拍板:必须上工程化流水线。不是为了炫技,而是为了少背锅、少加班、少掉头发。
前端工程化说白了,就是把那些重复、琐碎、容易出错的手动操作,变成自动、标准化、可追溯的流程。从代码怎么写、依赖怎么管,到测试怎么跑、包怎么打、服务怎么上线,全链路打通。
工具链选型:站在巨人的肩膀上,还是自己造轮子?
一开始我们团队吵翻了天。有人坚持用 Create React App(CRA),理由是“开箱即用”;有人主张上 Vite,说“快得飞起”;还有人想直接拿 Webpack 从零配——这位兄弟后来被我们集体“制裁”了,毕竟没人想花两周时间调 loader。
最终我们做了个对比表格(基于实际项目体验):
| 工具 | 启动速度 | 配置灵活度 | 社区生态 | 学习成本 | 适合场景 |
|---|---|---|---|---|---|
| CRA | 中等 | 低(需 eject) | 极强 | 低 | 快速原型、中小型项目 |
| Vite | ⚡️极快 | 高 | 强(增长迅猛) | 中 | 新项目、追求开发体验 |
| Webpack | 慢(大型项目尤甚) | 极高 | 最成熟 | 高 | 复杂定制需求、遗留系统 |
| Parcel | 快 | 低 | 一般 | 极低 | 超简单静态页 |
我们选了 Vite + TypeScript + ESLint + Prettier + Husky 的组合。理由很简单:开发时热更新快到飞起,配置文件清晰易懂,而且和 GitHub Actions 集成丝滑。
顺便吐槽一句:现在新项目还用 CRA?除非你真的不想升职加薪(笑)。
代码质量:不只是 Lint,更是团队契约
光有构建工具不够。我们吃过太多“本地跑得好好的,CI 上一跑就挂”的亏。于是我们强制推行了这几条规矩:
提交前自动格式化 + Lint
用husky+lint-staged,只检查改动的文件:// package.json "lint-staged": { "*.{js,jsx,ts,tsx}": ["eslint --fix", "prettier --write"] }TypeScript 不只是类型检查,更是文档
我们要求所有函数必须有明确的类型签名,连内部 utils 都不能偷懒。虽然初期写得慢,但后期重构时简直救命。Commit Message 规范化
用了commitlint+@commitlint/config-conventional,强制遵循 Angular 规范。好处是自动生成 CHANGELOG 和判断是否需要发新版本。
有一次我偷懒写了 fix bug,结果被 CI 直接拒绝提交。当时心里骂骂咧咧,但现在看 Git 历史记录,清清楚楚知道哪次改了什么,再也不用猜“这个 commit 到底修了啥”。
自动化测试:不是摆设,是上线前的最后一道防线
以前我们测试靠手动点点点,结果上线后用户反馈“按钮点不动”,一看是忘记 import CSS 了。现在我们分三层:
- 单元测试:用 Vitest(Vite 官方测试框架),跑得比 Jest 快三倍
- 组件测试:用 Testing Library,模拟用户真实交互
- E2E 测试:用 Playwright,覆盖关键路径(登录 → 下单 → 支付)
// example.test.ts
import { test, expect } from 'vitest'
import { render, screen } from '@testing-library/react'
import Button from './Button'
test('按钮能正确显示文本', () => {
render(<Button>提交</Button>)
expect(screen.getByText('提交')).toBeInTheDocument()
})
最开始大家觉得写测试浪费时间,直到有一次 PR 改了一个公共 Hook,导致首页数据加载失败——但单元测试提前捕获了这个问题,避免了一次线上事故。从此全员真香。
部署流程:从“手动 FTP 上传”到“一键发布”
以前上线是这样的:打包 → 登录服务器 → 删除旧文件 → 上传新文件 → 重启 Nginx。中间任何一步手抖,网站就挂了。
现在我们用 GitHub Actions 实现全自动部署:
# .github/workflows/deploy.yml
name: Deploy to Production
on:
push:
branches: [ main ]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Deploy to server
uses: appleboy/ssh-action@v0.1.10
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.SSH_KEY }}
script: |
cd /var/www/app
rm -rf dist
mkdir -p dist
# 这里其实用 rsync 更安全,但我们运维懒...
每次合并到 main 分支,自动触发构建和部署。还能加上人工确认步骤,防止误操作。
小插曲:第一次配置 SSH 密钥时,我把私钥直接写进了 YAML 文件,被 GitHub Security 扫描告警,吓得我赶紧删库跑路(不是)。
AI 辅助编程:Claude Code vs Kimi,谁更懂前端?
最近公司推 AI 编程助手,给了两个选项:Claude Code 和 Kimi。作为技术宅+备婚狗,我当然要试试哪个更能帮我省时间。
简单说结论:
- Claude Code:上下文理解强,尤其擅长根据项目结构生成符合规范的代码。比如让它写一个带 loading 和 error 状态的 fetch hook,它会自动加上 TypeScript 类型、单元测试模板,甚至注释风格都和我们项目一致。
- Kimi:中文理解无敌,对国内生态(如阿里云、微信小程序)支持更好。但它有时会“过度发挥”,生成一堆我们不用的库。
举个例子,我让它们帮我写一个图片懒加载组件:
Claude Code 输出:
- 使用 Intersection Observer API(现代浏览器兼容性好)
- 自动 fallback 到 scroll 事件(照顾老旧设备)
- 包含完整的 TypeScript 接口定义
- 附带 Jest 测试用例
Kimi 输出:
- 直接推荐用
react-lazyload库(但我们项目禁止随意引入第三方) - 提到了“可以结合七牛云 CDN 做优化”(虽然我们用的是 AWS)
- 注释全是中文,但变量命名又混着拼音(😅)
最后我们团队统一用 Claude Code,主要是它更尊重现有工程规范,不会乱来。
性能与体验:工程化的终极目标
所有这些工具链、流程、规范,最终都是为了用户体验。
我们上线后做了几件事:
- Bundle 分析:用
rollup-plugin-visualizer看包体积,砍掉不必要的依赖 - 关键资源预加载:在
<head>里加<link rel="preload"> - 错误监控:集成 Sentry,实时捕获 JS 错误
- 性能埋点:记录 FCP、LCP 等指标,接入公司数据平台
最让我骄傲的是,重构后的首屏加载时间从 3.2s 降到 1.1s,用户跳出率下降了 18%。产品经理终于没再半夜打电话骂我了(感动哭)。
写在最后:工程化不是银弹,但能让你睡个好觉
说实话,搭这套工程化体系花了我们小半个月,期间踩了无数坑:Webpack 和 Vite 插件冲突、GitHub Actions 权限问题、测试覆盖率阈值设太高导致 PR 卡住……
但值了。
现在我可以安心去试婚纱,不用担心周末突然被叫去修线上 Bug。因为我知道,每一行代码都经过 Lint,每一个功能都有测试覆盖,每一次上线都经过自动化验证。
前端工程化不是炫技,而是一种职业尊严——我们不是“切图仔”,而是能交付高质量、可维护、可持续迭代的产品工程师。
哦对了,下周我就要结婚了。如果婚礼现场音响系统崩了……应该不会吧?毕竟我老公也是程序员,他答应我用 Rust 写了个备用播放器(开玩笑的,别信)。
P.S. 如果你也正在搭建前端工程化体系,别怕麻烦。从一个小规范开始,比如先加上 Prettier,再慢慢扩展。完美的敌人是完成,先跑起来,再优化。
P.P.S. 备婚的程序员姐妹们,记得给自己留点时间休息。代码可以重构,婚礼只有一次。

评论 0