Agent Developer Roadmap
构建工具

构建工具总结:从源码到可加载资源

构建从配置和入口开始,经过模块解析、内容加载、语法转换、依赖建图、分包与优化,最终输出浏览器或服务器能够加载的文件。工具名称会变化,这条过程相对稳定。排查问题时,找到第一个错误的中间结果,并确认它由配置、插件、构建器、部署系统还是运行宿主负责。

完整构建过程

config/source → resolve/load → parse/transform → graph/chunk → optimize → emit → browser/runtime

配置和输入

entrytargetformatplatformmode、环境变量和插件顺序都会改变输出。正式比较或排障前,先固定工作目录、工具版本、lockfile、最终生效配置和入口。开发机与 CI 若读取了不同环境变量或配置文件,后续比较文件内容没有意义。

配置中的环境变量需要区分构建期、服务端运行期和可公开给浏览器的值。被替换进客户端代码的变量会成为产物的一部分,不能再当作密钥。插件也在构建进程权限范围内运行,可以读取源码、环境和文件系统,因此依赖来源、版本锁定与升级审查都属于构建安全。

模块解析和加载

解析阶段把 import 中的说明符映射为文件、包导出、虚拟模块或 external。结果受 alias、扩展名、package.json exports、conditions、平台和导入者位置影响。大小写敏感文件系统、Monorepo 软链接和重复依赖,都会造成“本地正常、CI 或生产失败”。

调试时记录导入者、原始说明符、参与匹配的条件和最终模块 ID。解析到错误文件时应修正 exports、alias 或宿主条件,不宜通过复制文件或在业务代码散布路径分支绕过问题。

语法解析与转换

Babel、SWC、esbuild 以及构建器内置编译器会把 TypeScript、JSX、新语法或 CSS 转成目标宿主可执行的形式。能够解析某种语法,不等于已经将它转换到目标版本;删除 TypeScript 类型也不等于完成类型检查。应用通常仍需独立运行 tsc 或框架的类型检查器。

转换器通过 AST 修改代码,再生成文本和 Source Map。多个转换步骤必须把上游映射继续传递,否则生产堆栈只能指向中间文件。检查 Source Map 时,应确认 sources 指向预期源码、mappings 非空、关键位置可回溯,并避免发布本机绝对路径或不应公开的源内容。

模块关系、分包与优化

静态导入形成同步关系,动态 import() 通常形成异步边界。构建器结合入口、共享依赖、external 和拆分策略,将模块组织为 chunk。Tree Shaking 依赖静态关系和副作用声明;错误的 sideEffects: false 可能删除 CSS、注册代码或其他有意副作用。

产物体积变化应从 stats、manifest 或 metafile 回到具体模块和关系。先确认输入、target、minify、Source Map 和拆分条件相同,再比较大小与构建时间。单个总字节数无法说明首屏下载、延迟资源、缓存复用和运行成本。

生成资源并交给宿主

输出通常包含 JavaScript、CSS、图片、字体、HTML、manifest、运行时代码和 Source Map。HTML、manifest 与带 hash 的资源要属于同一发布版本;basepublicPath 或 CDN 前缀必须和真实部署路径一致。动态 chunk 的 URL 在运行时产生,静态首页正常并不能证明延迟路由一定能加载。

浏览器或服务器是最后的加载者。CSP、CORS、MIME、压缩、缓存头、Node 条件和边缘宿主限制都可能让正确生成的文件无法执行。构建成功只证明工具完成输出,用户能否加载和运行仍要通过真实部署验证。

不同工具各自负责什么

工具主要职责使用时容易混淆的边界
Babel单文件语法转换和可组合 AST 插件不建立完整应用模块关系,也不负责类型检查
SWC高性能 JavaScript/TypeScript 转换,可嵌入其他工具独立转换不等于完整应用构建
webpack从解析、Loader 到分包、输出和浏览器 runtime 的完整链路配置与插件能力强,也更需要控制隐式行为
Rollup以 ESM 为核心的建图、优化和多格式输出开发服务器、HTML 与框架体验通常由上层补充
ViteHTML 入口、开发服务器、按请求转换、HMR 和生产构建类型检查与业务后端仍需独立负责
esbuild快速 Transform/Build API 和可编程插件Transform API 不建完整模块关系,Build 也不自动提供框架工作流
Rspack与 webpack 相近的应用构建模型,核心由 Rust 实现webpack 插件和内部 API 并非全部等价
Rolldown面向 ESM 的建图、分包和输出,也作为 Vite 构建底座独立使用时不会自动获得 Vite 的 HTML、开发服务器与 HMR

工具可以组合使用。Babel 或 SWC 可以成为 webpack/Rspack 的转换层,esbuild Transform 可以嵌入测试和开发工具,Vite 负责上层工作流并使用底层构建器。选择时先确定需要的是单文件转换、库发布、应用构建还是完整开发体验,再比较生态、性能和迁移成本。

开发服务器、缓存和 HMR

开发服务器往往按浏览器请求转换模块,并维护一张适合快速失效的请求关系;生产构建则从入口出发生成稳定资源。两者使用不同执行路径,因此开发环境成功不能替代生产构建和部署验证。

缓存只有在输入声明完整时才可靠。源码、配置、依赖版本、插件版本、目标平台和相关环境变量都可能影响结果。缓存命中后出现旧代码,先检查键是否遗漏输入;直接清空缓存只能暂时恢复,无法解释下次为何安全。

Live Reload 会刷新整页,HMR 尝试替换受影响模块并保留部分状态。模块必须声明如何接受更新和释放旧副作用,否则定时器、订阅、样式或单例可能重复。HMR 正常也不说明重新打开页面、生产资源或旧标签能够工作。

共享示例怎样验证构建结果

examples/build-tools/src/ 使用同一组输入观察八种工具:入口文件引入 TypeScript、CSS、静态模块和动态模块;有意保留的副作用用于检查 Tree Shaking;动态导入用于检查异步资源;Source Map 用于检查源码回溯。

构建后应能从产物和元数据回答:入口加载哪些初始资源,动态模块落入哪个 chunk,CSS 和其他资源怎样引用,未使用代码是否删除,有意副作用是否保留,Source Map 是否指回源码,文件内部引用是否越出输出目录。截图只能证明某一刻页面可见,无法替代这些结构性证据。

运行示例时,以仓库当前 package.json 和 README 中的命令为准。验证结果不依赖固定文件数量或固定 hash,而关注资源关系和用户行为是否满足约定。

从常见症状回到负责阶段

症状优先检查
找不到模块或加载了错误实现import 说明符、exports、conditions、alias 和最终 resolved ID
新语法在旧环境报错parser、transform 配置、target 和实际运行宿主
生产堆栈无法定位源码每段转换的 Source Map 输入、输出与发布策略
动态页面在发布后 404HTML/manifest 版本、公开路径、CDN 和旧资源保留
CSS 或注册逻辑消失副作用声明、Tree Shaking 和插件顺序
本地正常而 CI 失败cwd、文件名大小写、Node 版本、环境变量和 lockfile
HMR 后行为重复更新接受边界、定时器、订阅和模块级单例清理
产物突然变大输入变化、重复依赖、拆分条件、target 和分析报告

一次资源加载事故中,先记录用户 URL、HTML 版本、失败资源 URL、响应状态、构建版本和 CDN 缓存头。若新 HTML 引用了新资源,而部分节点尚未发布,问题在发布一致性;若旧 HTML 请求的 chunk 已被删除,问题在旧资源保留;若 manifest 正确但浏览器请求路径错误,再检查公开路径和运行时代码。不要一开始就让所有用户清缓存,这会丢失最有价值的版本证据。

升级或迁移构建工具

迁移前先定义必须保持的行为:入口、别名、条件导出、TypeScript/JSX 转换、CSS、静态资源、动态导入、环境变量、插件副作用、Source Map、SSR external 和部署路径。随后选择一个真实入口做小范围对照,同时保留旧构建命令和可回退产物。

比较两套结果时,要在相同机器、依赖、输入、缓存状态和目标条件下记录构建时间、开发启动、增量更新、资源大小和用户路径。性能提高只有在语义、错误定位和部署行为仍正确时才有意义。迁移完成后删除临时兼容层,更新故障手册和所有权说明,避免团队长期维护两套不一致配置。

进入 JavaScript 运行时阶段

完成构建阶段后,应能从配置和源码追到解析结果、转换代码、模块关系、chunk、manifest、HTML 和浏览器请求,并解释缓存与 HMR 的失效条件。还要区分转换器、构建器、开发服务器、部署系统和最终宿主的责任。

接下来阅读 JavaScript 运行时。构建工具决定产物假设,运行时决定这些假设是否成立:模块格式怎样加载,事件循环怎样调度,文件与网络能力是否可用,权限和资源限制在哪里生效,进程或 isolate 又怎样结束。带着真实产物进入下一阶段,比从空白脚本比较运行时更接近生产问题。

相关内容:

在 GitHub 上编辑此页

本页目录