构建 (vext build)
vext build 会将服务端源码编译为可部署的 JavaScript 产物;当 frontend.enabled 为 true 时,还会把浏览器客户端打包到 dist/client/。当前版本的 vext build 按 production-target build 设计:它会对用户源码中的 process.env.NODE_ENV 做生产模式静态注入;运行时实际加载哪个配置 profile,由 vext start --config <name> 或 VEXT_CONFIG=<name> 决定。基于 esbuild 实现,编译阶段针对本地与 CI 反馈速度做了优化。
快速开始
构建前置产物刷新
TypeScript 项目执行 vext build 时,会先刷新开发工具链需要的 generated 与 manifest 产物,再进入可选类型检查和 esbuild 编译:
vext typegen基础刷新:写入.vext/types/*.generated.d.ts、src/types/generated/index.d.ts与.vext/manifest/services.jsondoctor routes --refresh --write-manifest:重新扫描路由并写入.vext/manifest/routes.json- 如果传入
--typecheck,此时再执行tsc --noEmit - 由 esbuild 将服务端运行时代码输出到
dist/ - 如果
config.frontend.enabled为 true,再由 esbuild 将浏览器客户端打包到dist/client/
这保证新脚手架或刚清理过 .vext/ 的项目,也能在 vext build --typecheck 中先拿到最新 generated 类型,再进入 TypeScript 校验。
编译策略
逐文件编译(File-by-File Transform)
vext build 对服务端代码采用逐文件编译模式,而非 bundle 模式——每个源文件独立编译为一个输出文件,保持 src/ 的目录结构映射。src/frontend/** 不进入服务端逐文件编译步骤,而是由前端 bundler 和 SSR renderer 构建步骤单独处理。
为什么不 Bundle?
编译选项
CLI 参数
vext build 不支持位置参数。--outdir、--config 等取值参数必须紧跟非 option 值,例如 --outdir dist;--outdir --minify 或 --config --clean 会作为缺值错误失败。
普通重复构建会自动清理已删除或重命名服务端源码留下的 dist/**/*.js 与 dist/**/*.js.map 后端 stale 产物,并保留 dist/client/ 前端产物;--clean 用于在编译前彻底清空整个输出目录。
前端构建
当 config.frontend.enabled 为 true 时,浏览器流水线使用 esbuild bundle 模式:
前端构建会写入:
启用前端但缺少 dist/client/index.html 时,vext start 会 fail fast。生产启动前请先执行 vext build。
浏览器端页面、layout、错误页和 locale 会通过动态 import 形成页面级 chunk;React 等公共依赖默认通过 Vext-managed vendor entry 配合 esbuild splitting 形成共享 chunk。frontend.build.client.external 可把模块排除出 browser bundle,但必须用 frontend.build.client.externalRuntime 给浏览器提供 import map URL,否则浏览器无法加载该外置模块。
frontend.deploy.integrity=true 时,Vext 会把构建期计算出的 SRI 写入生成 HTML 的 JS/CSS 标签。deploy-manifest.json 同时覆盖 esbuild 输出资源和 public/** 复制资源,可用于 vext deploy assets 的真实上传与增量发布;默认不包含服务端渲染的 index.html 和 source map。
输出格式
优化选项
自动注入
编译时自动注入以下定义:
这会让 build 后用户源码中的 process.env.NODE_ENV 分支按 production 语义被静态折叠。
注意,这个注入并不等于“运行时只能加载 config/production.ts”。运行时实际加载哪个配置 profile,仍由 vext start --config <name> 或 VEXT_CONFIG=<name> 决定,例如:
会尝试加载:
因此,当前 vext build 的推荐用法是:
- 用它生成 production-target artifact
- 用
vext start --config <profile>或VEXT_CONFIG=<profile>选择配置 profile - 不要依赖 build 后用户源码中的
process.env.NODE_ENV条件分支做 sit/uat/prod 切换
文件扫描规则
包含的文件
vext build 扫描 src/ 目录下所有匹配以下模式的文件:
服务端逐文件编译会忽略 src/frontend/**;前端文件由浏览器 bundle 和 SSR renderer 构建步骤处理。
排除的文件
编译自动排除以下文件(两层排除规则):
通用排除(与开发模式共享)
生产编译额外排除
这意味着 dist/ 中不会包含开发/测试/本地配置文件,避免敏感信息泄漏到生产环境。
Source Map
外部 Source Map
vext build 生成外部 .js.map 文件(与 vext dev 的 inline source map 不同):
启用 Source Map 支持
在 Node.js 运行时启用 source map,让错误堆栈显示 TypeScript 行号:
未启用时的错误堆栈:
启用后的错误堆栈:
Source Map 用途
生产环境部署时,.js.map 文件可以保留在服务器上(不会被 HTTP 暴露),但不要部署到 CDN 或静态文件服务中。
与 DevCompiler 的对比
vext build 和 vext dev 共享相同的 esbuild 基础配置(createBaseEsbuildConfig()),确保开发和生产环境的编译行为一致:
共享配置
两者共享的 esbuild 配置包括:
platform: 'node'— Node.js 运行时target: 'node20'— 最低支持 Node.js 20.19.0format: 'cjs'— CommonJS 输出bundle: false— 逐文件编译treeShaking: true— 死代码消除keepNames: true— 保留函数名charset: 'utf8'— UTF-8 编码loader—.ts/.js/.json等文件类型映射
编译结果
vext build 执行完成后,输出编译报告:
BuildResult 结构
运行编译产物
如果 TypeScript 项目缺少 dist/ 或关键构建产物,vext start 会直接失败并提示先执行 vext build。开发期源码启动请使用 vext dev。
如果启用了前端,vext start 还会检查 dist/client/index.html,并在 API / 文档路径之外以 SPA fallback 服务 dist/client/。
通用脚手架项目没有固定的 dist/index.js 启动入口;直接 node dist/index.js 只适用于你自己维护入口文件并显式调用框架启动逻辑的高级场景。
VEXT_BUILT 标记
通过 vext start 运行有效 dist/ 构建产物时,CLI 会设置 VEXT_BUILT=1 环境变量。这影响:
- 路径解析:
src/routes/→dist/routes/ - 模块加载:从
dist/目录加载 routes、services、plugins、middlewares - Model 加载:MonSQLize 从
dist/models/加载 Model 定义
你不需要手动设置这个变量,使用 vext start 时框架会自动处理。
部署清单
使用 vext build 部署到生产环境的推荐步骤:
Docker 多阶段构建
.gitignore
确保 dist/ 目录在 .gitignore 中(编译产物不应提交到 Git):
故障排查
编译失败
确保 src/ 目录存在且包含 .ts 或 .js 文件。
运行时找不到模块
可能原因:
vext build后没有重新安装依赖(npm ci)- 某些文件被排除规则跳过了(检查是否符合排除规则)
- 使用了动态
import()引用.d.ts文件
Source Map 不生效
确保启动时通过 NODE_OPTIONS 传入 --enable-source-maps 参数:
下一步
- 了解 部署与生产环境 的完整部署指南
- 查看 热重载 了解开发模式的编译策略
- 学习 CLI 命令 中
vext build的完整参数 - 探索 Cluster 多进程 充分利用多核 CPU