构建 (vext build)
vext build 将 TypeScript/JavaScript 源码编译为生产级 JavaScript,输出到 dist/ 目录。基于 esbuild 实现,编译速度极快——典型项目(50+ 源文件)的编译时间在 1 秒以内。
快速开始
# 编译生产产物
vext build
# 运行编译后的产物
NODE_ENV=production node dist/index.js
# 或使用 vext start(自动检测 dist/ 目录)
NODE_ENV=production vext start
编译策略
vext build 采用逐文件编译模式,而非 bundle 模式——每个源文件独立编译为一个输出文件,保持 src/ 的目录结构映射:
src/ dist/
├── index.ts → ├── index.js + index.js.map
├── config/ ├── config/
│ ├── default.ts → │ ├── default.js + default.js.map
│ └── production.ts → │ └── production.js + production.js.map
├── routes/ ├── routes/
│ ├── users.ts → │ ├── users.js + users.js.map
│ └── posts.ts → │ └── posts.js + posts.js.map
├── services/ ├── services/
│ ├── user.ts → │ ├── user.js + user.js.map
│ └── auth.ts → │ └── auth.js + auth.js.map
├── plugins/ ├── plugins/
│ └── redis.ts → │ └── redis.js + redis.js.map
├── middlewares/ └── middlewares/
│ └── auth.ts → └── auth.js + auth.js.map
└── models/ └── models/
└── user.ts → └── user.js + user.js.map
为什么不 Bundle?
编译选项
输出格式
优化选项
自动注入
编译时自动注入以下定义:
define: {
'process.env.NODE_ENV': '"production"'
}
确保生产环境配置文件(config/production.ts)被正确加载。
文件扫描规则
包含的文件
vext build 扫描 src/ 目录下所有匹配以下模式的文件:
排除的文件
编译自动排除以下文件(两层排除规则):
通用排除(与开发模式共享)
生产编译额外排除
Tip
这意味着 dist/ 中不会包含开发/测试/本地配置文件,避免敏感信息泄漏到生产环境。
Source Map
外部 Source Map
vext build 生成外部 .js.map 文件(与 vext dev 的 inline source map 不同):
dist/
├── index.js # 编译后的 JavaScript
├── index.js.map # Source Map(映射回 src/index.ts)
├── routes/
│ ├── users.js
│ └── users.js.map
└── ...
启用 Source Map 支持
在 Node.js 运行时启用 source map,让错误堆栈显示 TypeScript 行号:
node --enable-source-maps dist/index.js
未启用时的错误堆栈:
Error: Something went wrong
at UserService.findById (dist/services/user.js:23:11)
启用后的错误堆栈:
Error: Something went wrong
at UserService.findById (src/services/user.ts:42:11)
Source Map 用途
Warning
生产环境部署时,.js.map 文件可以保留在服务器上(不会被 HTTP 暴露),但不要部署到 CDN 或静态文件服务中。
与 DevCompiler 的对比
vext build 和 vext dev 共享相同的 esbuild 基础配置(createBaseEsbuildConfig()),确保开发和生产环境的编译行为一致:
共享配置
两者共享的 esbuild 配置包括:
platform: 'node' — Node.js 运行时
target: 'node18' — 最低支持 Node.js 18
format: 'cjs' — CommonJS 输出
bundle: false — 逐文件编译
treeShaking: true — 死代码消除
keepNames: true — 保留函数名
charset: 'utf8' — UTF-8 编码
loader — .ts/.js/.json 等文件类型映射
编译结果
vext build 执行完成后,输出编译报告:
vext build
✓ Compiled 42 files in 487ms
✓ Output: dist/
Files: 42 JS + 42 Source Maps
Errors: 0
Warnings: 0
BuildResult 结构
运行编译产物
直接运行
# 基本启动
NODE_ENV=production node dist/index.js
# 启用 source map(推荐)
NODE_ENV=production node --enable-source-maps dist/index.js
# 增大内存上限
NODE_ENV=production node --enable-source-maps --max-old-space-size=4096 dist/index.js
使用 vext start
vext start 会自动检测 dist/ 目录:
# 自动检测 dist/ 并使用 node 运行
NODE_ENV=production vext start
# 如果 dist/ 不存在,回退到 tsx 运行 src/(开发模式)
vext start
VEXT_BUILT 标记
当运行编译后的产物时,框架内部设置 VEXT_BUILT=1 环境变量。这影响:
- 路径解析:
src/routes/ → dist/routes/
- 模块加载:从
dist/ 目录加载 routes、services、plugins、middlewares
- Model 加载:MonSQLize 从
dist/models/ 加载 Model 定义
你不需要手动设置这个变量——框架自动处理。
部署清单
使用 vext build 部署到生产环境的推荐步骤:
# 1. 安装依赖
npm ci
# 2. 编译
npx vext build
# 3. 仅安装生产依赖(可选,用于 Docker 等场景)
npm ci --omit=dev
# 4. 启动
NODE_ENV=production node --enable-source-maps dist/index.js
Docker 多阶段构建
# 阶段 1: 编译
FROM node:22-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY src/ src/
COPY tsconfig.json ./
RUN npx vext build
# 阶段 2: 运行
FROM node:22-alpine
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev && npm cache clean --force
COPY --from=builder /app/dist ./dist
ENV NODE_ENV=production
CMD ["node", "--enable-source-maps", "dist/index.js"]
.gitignore
确保 dist/ 目录在 .gitignore 中(编译产物不应提交到 Git):
dist/
.vext/
node_modules/
故障排查
编译失败
Error: [vextjs] No source files found in /project/src
确保 src/ 目录存在且包含 .ts 或 .js 文件。
运行时找不到模块
Error: Cannot find module './routes/users.js'
可能原因:
vext build 后没有重新安装依赖(npm ci)
- 某些文件被排除规则跳过了(检查是否符合排除规则)
- 使用了动态
import() 引用 .d.ts 文件
Source Map 不生效
确保启动时传入了 --enable-source-maps 参数:
# ✅ 正确
node --enable-source-maps dist/index.js
# ❌ 参数位置错误
node dist/index.js --enable-source-maps
下一步