上线、预览部署、CI 验证、性能审计时——都需要把源码变成体积小、压缩过、哈希命名的定稿产物,发给 CDN 或静态主机。
工程与栈 · 工程协作
构建Build
构建把源码经编译、类型擦除、打包摇树、压缩改名、哈希命名,产出体积小、压缩过、带哈希的可部署静态产物(dist/);失败则退出非 0、不生成可误发布的半成品。
把源码构建成可部署产物:亲手走一遍流水线
构建把开发时读的源码翻译成部署时发的定稿产物。点「开始构建」逐阶段推进,每一步把结果落在物件上:死代码被摇树剔除、代码片段被压缩、dist/ 产物清单逐行生成、产物体积从源码的 240 KB 变小。打开「模拟类型错误」还能看构建失败如何阻断产物。
目标:把这份源码构建成可部署产物。第 0 步——真实项目里触发这一流水线的入口是 npm run build(或框架自带的 next build / vite build);这里用「开始构建」按钮模拟同一条流水线。逐阶段推进,看每一步把结果落在物件上——源码树的死代码被剔除、代码片段被压缩、dist/ 产物清单逐行生成、产物体积从 240 KB 变小。
- 源码
- 类型擦除
- 摇树打包
- 压缩改名
- 哈希命名
- 产物就绪
app.tsx入口 · 引 Button、format96 KBButton.tsx被 app 引用64 KBformat.ts被 app 引用32 KBlegacy-icons.ts无人 import · 死代码48 KB未引用
interface User { id: number; name: string }
function handleSubmit(values: User) {
const label = formatUserName(values);
console.log("submit", label);
return label;
}已就绪:源码 240 KB,含类型注解、未压缩、含未引用模块 legacy-icons.ts。原因:开发时读源码是为了 HMR 快、可读、带类型检查。下一步:点「开始构建」逐阶段看产物如何变小。
知识点:构建流水线到底做了什么
把刚才面板里观察到的事实命名出来——这几条是「构建」区别于「直接跑源码」的核心。
- 编译 + 类型擦除TS 的 interface、类型注解在编译期被剥掉;浏览器只跑 JS,类型是开发期工具,不进产物。
- 打包 + 摇树(tree-shake)打包器从入口递归找引用,运行时到不了的模块(如 legacy-icons.ts)就是死代码,会被剔除;面板里它在「摇树」阶段被标「已剔除」。
- 压缩改名(minify)标识符被缩短(handleSubmit→a)、删空白、合并表达式,直接减小体积;面板代码片段在「压缩」阶段变成一行。
- 哈希命名产物文件名带内容哈希(app.a3f9b2c1.js);内容变则哈希变,浏览器能安全长缓存,改一行就强制刷新。
- 产物是定稿、可托管dist/ 里是 HTML/JS/CSS/资源,体积小、压缩过、哈希命名,可直接托管到 CDN 或静态主机;失败则不生成可误发布的半成品。
什么时候用构建
判断信号:这份代码要不要离开本机、交给真实用户或 CI。
本机写代码靠 dev server 的 HMR 直接读源码,保留类型和可读命名方便调试;每次保存都跑生产构建会拖慢反馈。
怎么用:从 npm run build 到部署产物
只走这条链,就能把源码变成可部署产物并验证。
- 触发构建:在仓库根目录跑
npm run build(或框架自带入口,如next build、vite build)。 - 读退出码:成功退出 0 并写出 dist/;类型或语法错误时退出非 0、不生成可误发布的半成品。
- 查产物清单:在 dist/ 里核对 HTML/JS/CSS 与资源,确认哈希命名、死代码已剔除、体积合理。
- 本地预览 + 部署:用静态服务器预览 dist/,再把产物托管到 CDN 或静态主机;CI 用同一命令复现。
正反例:要不要摇树打包
同一个目标——把产物体积降下来——只换一处关键选择,看体积差多少。
legacy-icons.ts 这种无人 import 的模块在打包阶段被剔除,产物 37.7 KB。源码里留着它不碍事,构建边界把它挡在产物外。
死代码被原样打进产物,多出约 14 KB,还可能把不必要的大依赖一起带上;面板里勾选「保留未引用模块」即可看到 52.3 KB 的对照。
快速自测
同一份源码,构建后的产物体积明显比源码小很多,最主要的原因是什么?
继续查证
术语的技术定义和行为以这些一手或权威资料为准。
下一步学
和本知识点经常一起出现的概念。