配置
VextJS 采用 多层配置合并 机制,支持按环境覆盖配置,同时提供丰富的内置配置项覆盖框架行为。
配置加载机制
框架启动时,config-loader 按以下顺序加载配置文件并深度合并:
框架内置默认值 → default.ts → {NODE_ENV}.ts → local.ts → bootstrap provider patch → CLI override
每一层都可以只声明需要覆盖的字段,未声明的字段从上一层继承。
配置文件
环境文件通过 NODE_ENV 环境变量自动匹配。未设置 NODE_ENV 时默认为 development。
NODE_ENV 不限于 development / production / test,也可以是任意自定义环境名,例如:
src/config/sg-sit.ts
src/config/us-uat.ts
src/config/us-prod.ts
启动时只要设置:
NODE_ENV=sg-sit vext start
Vext 就会按同一套合并链路加载:default -> sg-sit -> local -> bootstrap provider patch -> CLI override。
Build 与 Runtime 的环境语义
vext build 当前会将用户源码中的 process.env.NODE_ENV 静态注入为 "production"。这不会改变 vext start 在运行时按 NODE_ENV 选择配置文件的行为,但会影响 build 后用户源码里的环境分支判断。
因此,推荐把环境差异放进:
src/config/<env>.ts
src/config/bootstrap.ts
- 其他显式业务环境变量
而不是依赖 build 后源码中的 process.env.NODE_ENV 条件分支。
合并规则
- 对象字段:深度合并(deep merge),环境文件只需声明需要覆盖的字段
middlewares 数组:智能 patch 策略——按 name 匹配并合并,而非简单替换整个数组
- 其他数组:后层覆盖前层
bootstrap provider patch:在 local.ts 之后、CLI override 之前参与同一套 merge / validate / freeze 流程
- 最终结果:深冻结(
deepFreeze),运行时不可修改
Bootstrap Config Provider
如果你需要在 配置定稿前 拉取远程配置(例如 Nacos / 配置中心 / 启动期密钥派发),可以新增 src/config/bootstrap.ts:
import { defineBootstrapConfig } from "vextjs";
export default defineBootstrapConfig({
providers: [
{
name: "remote-config",
timeoutMs: 10_000,
async load({ env, baseConfig, signal }) {
const response = await fetch(`https://config.example.com/${env}`, {
signal,
});
const remote = await response.json();
return {
database: remote.database,
logger: {
lifecycleLevel: baseConfig.logger?.lifecycleLevel ?? "concise",
},
};
},
},
],
});
provider 上下文字段:
约束:
- provider 必须返回 plain object patch 或
null
- patch 只支持 JSON-like 结构;不支持函数、类实例、adapter factory
- 默认优先级:
local < provider < CLI
- 未声明
required 时:production 默认 fail-fast,development / test 默认 warning 后继续
- Cluster 模式下,Master 会将本轮 provider patch 传递给 Worker 复用,避免同一启动周期出现配置漂移
配置文件格式
每个配置文件使用 export default 导出一个对象:
// src/config/default.ts
export default {
port: 3000,
host: "0.0.0.0",
logger: {
level: "info",
lifecycleLevel: "concise",
},
cors: {
origins: ["*"],
},
openapi: {
enabled: true,
},
};
// src/config/production.ts — 仅覆盖需要变更的字段
export default {
logger: {
level: "warn", // 生产环境减少日志输出
},
cors: {
origins: ["https://myapp.com"], // 生产环境限制来源
},
openapi: {
enabled: false, // 生产环境关闭文档
},
};
// src/config/local.ts — 本地开发特殊配置(不提交 Git)
export default {
port: 8080, // 本地使用其他端口
};
Middlewares Patch 策略
middlewares 数组使用智能合并,按中间件 name 匹配:
// src/config/default.ts
export default {
middlewares: [
"auth",
{ name: "check-role", options: { roles: ["user"] } },
{ name: "rate-limit-api", options: { max: 100 } },
],
};
// src/config/development.ts
export default {
middlewares: [
// 只需声明要覆盖的中间件,其余保留
{ name: "check-role", options: { roles: [] } }, // 开发环境不检查角色
{ name: "rate-limit-api", options: { max: 10000 } }, // 放宽限流
],
};
合并后结果:
middlewares: [
"auth", // 保留
{ name: "check-role", options: { roles: [] } }, // 被覆盖
{ name: "rate-limit-api", options: { max: 10000 } }, // 被覆盖
];
使用 Adapter
默认使用 Native Adapter(http.createServer + find-my-way)。要切换其他 Adapter,在配置中指定 adapter 字段:
// src/config/default.ts — 使用 Hono Adapter
import { honoAdapter } from "vextjs/adapters/hono";
export default {
adapter: honoAdapter(),
port: 3000,
};
// src/config/default.ts — 使用 Fastify Adapter
import { fastifyAdapter } from "vextjs/adapters/fastify";
export default {
adapter: fastifyAdapter(),
port: 3000,
};
// src/config/default.ts — 使用 Express Adapter
import { expressAdapter } from "vextjs/adapters/express";
export default {
adapter: expressAdapter(),
port: 3000,
};
// src/config/default.ts — 使用 Koa Adapter
import { koaAdapter } from "vextjs/adapters/koa";
export default {
adapter: koaAdapter(),
port: 3000,
};
Tip
不指定 adapter 时默认使用 Native Adapter,性能最高且零框架依赖。仅当需要使用特定框架的生态或特性时才切换。
完整配置项参考
基础配置
export default {
port: 3000,
host: "0.0.0.0",
trustProxy: false,
};
CORS 配置 (cors)
export default {
cors: {
origins: ["https://myapp.com"], // 生产环境限制来源(数组格式)
credentials: true,
methods: ["GET", "POST", "PUT", "DELETE"],
},
};
限流配置 (rateLimit)
export default {
rateLimit: {
enabled: true,
max: 100,
window: 60, // 1 分钟(单位:秒)
message: "Too many requests, please try again later",
keyBy: "ip",
},
};
路由级限流覆盖
可以在路由的 options.override.rateLimit 中为特定路由覆盖限流配置:
app.post(
"/login",
{
override: {
rateLimit: { max: 5, window: 60 }, // 登录接口更严格(window 单位:秒)
},
},
handler,
);
app.get(
"/health",
{
override: {
rateLimit: false, // 健康检查不限流
},
},
handler,
);
请求 ID 配置 (requestId)
export default {
requestId: {
enabled: true,
header: "x-request-id",
},
};
当请求中携带 X-Request-Id 头时,框架会透传该 ID 而不是生成新的。适合微服务链路追踪。
日志配置 (logger)
支持的日志级别(从低到高):'trace' → 'debug' → 'info' → 'warn' → 'error' → 'fatal' → 'silent'
export default {
logger: {
level: "info", // 生产环境建议 'warn'
lifecycleLevel: "concise", // 如需排障可设为 'verbose'
pretty: true, // 开发环境开启彩色格式化(生产环境默认关闭)
// prettySingleLine: true, // 额外字段压缩到同行(默认)
// prettyIgnore: 'pid,hostname,requestId', // 默认隐藏字段
},
};
VextJS 内置 pino 作为日志引擎,pretty 模式使用 pino-pretty 彩色格式化输出。完整的日志系统说明(Child Logger、存储方案、requestId 注入等)见 日志文档。
优雅关闭配置 (shutdown)
export default {
shutdown: {
timeout: 15, // 15 秒超时(单位:秒)
},
};
收到 SIGTERM / SIGINT 信号后,框架按注册的逆序执行所有 onClose 钩子(如关闭数据库连接),超时后强制退出。
响应配置 (response)
export default {
response: {
wrap: true,
hideInternalErrors: true,
logErrors: {
unknownErrors: true, // 未知错误必须记录
http5xx: true, // 5xx 是服务端责任
http4xx: false, // 4xx 默认不记录(高流量场景避免噪音)
},
},
};
启用 wrap: true 后,res.json(data) 的实际输出:
{
"code": 0,
"data": { "name": "Alice" },
"requestId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
设置 wrap: false 可关闭包装,res.json(data) 直接输出原始数据。
Body Parser 配置 (bodyParser)
export default {
bodyParser: {
enabled: true,
maxBodySize: "5mb", // 允许更大的请求体
},
};
maxBodySize 支持字符串格式('1mb'、'500kb')和数字格式(字节数)。
Multipart / 文件上传配置 (multipart)
export default {
multipart: {
enabled: true, // 开启内置解析
maxFileSize: 10 * 1024 * 1024, // 10MB
maxFiles: 5,
allowedMimeTypes: ["image/jpeg", "image/png", "application/pdf"],
},
};
Access Log 配置 (accessLog)
export default {
accessLog: {
enabled: true,
level: "info",
},
};
启用后,每个请求完成时自动记录:
INFO GET /api/users → 200 (12ms)
OpenAPI 配置 (openapi)
export default {
openapi: {
enabled: true,
title: "My App API",
description: "我的应用 API 文档",
version: "1.0.0",
docsPath: "/docs",
jsonPath: "/openapi.json",
scalar: {
theme: "default",
darkMode: false,
layout: "modern",
favicon: "/favicon.svg",
},
servers: [
{ url: "http://localhost:3000", description: "本地开发" },
{ url: "https://api.myapp.com", description: "生产环境" },
],
tags: [
{ name: "用户", description: "用户管理相关接口" },
{ name: "订单", description: "订单管理相关接口" },
],
securitySchemes: {
bearerAuth: {
type: "http",
scheme: "bearer",
bearerFormat: "JWT",
},
},
contact: {
name: "API Support",
email: "support@myapp.com",
},
license: {
name: "MIT",
url: "https://opensource.org/licenses/MIT",
},
},
};
请求上下文配置 (requestContext)
export default {
requestContext: {
enabled: true,
},
};
性能提示
禁用 requestContext 可提升约 3-8% RPS,但以下功能将失效:
app.logger 自动携带 requestId
app.throw() 自动解析请求 locale
app.fetch 自动传播 requestId
仅在极致性能场景下考虑禁用。
Cluster 配置 (cluster)
export default {
cluster: {
enabled: true,
workers: "auto", // 自动检测 CPU 核数
autoRestart: true,
maxRestarts: 5,
healthCheck: { enabled: true },
reload: { workerDelay: 2000 },
},
};
也可以通过环境变量 VEXT_CLUSTER=1 开启 Cluster 模式,无需修改配置文件。
Dev 模式配置 (dev)
export default {
dev: {
errorOverlay: {
enabled: true, // 设为 false 可禁用 HTML 错误覆盖层
theme: "dark",
maxFrames: 25,
},
},
};
仅开发模式生效
dev 配置项仅在 vext dev 开发模式下读取,生产模式(vext start)自动忽略所有字段。
Dev 错误覆盖层基于 Accept 内容协商,而非 HTTP 方法:
Accept: text/html(浏览器地址栏 GET、HTML 表单 POST)→ 返回 HTML 错误页
Accept: application/json(前端 fetch / axios / curl)→ 始终返回 JSON
控制台日志不受 overlay 影响——无论响应返回 HTML 还是 JSON,logErrors 配置的日志行为完全相同。
中间件白名单 (middlewares)
export default {
middlewares: [
// 普通中间件 — 字符串声明
"auth",
"timing",
// 工厂中间件 — 对象声明(附带默认参数)
{ name: "check-role", options: { roles: ["user"] } },
{ name: "cache-control", options: { maxAge: 3600 } },
],
};
只有在白名单中声明的中间件才能在路由的 options.middlewares 中被引用。
在代码中访问配置
路由中
export default defineRoutes((app) => {
app.get("/info", async (_req, res) => {
res.json({
port: app.config.port,
env: process.env.NODE_ENV,
openapi: app.config.openapi.enabled,
});
});
});
服务中
export default class MyService {
constructor(private app: VextApp) {}
getApiBaseUrl() {
const { host, port } = this.app.config;
return `http://${host}:${port}`;
}
}
插件中
export default definePlugin({
name: "my-plugin",
setup(app) {
const myConfig = app.config.myPlugin ?? { enabled: false };
if (!myConfig.enabled) return;
// ...
},
});
配置只读
app.config 在启动后被深冻结(deepFreeze),任何修改尝试都会抛出 TypeError。这确保配置在运行时不被意外修改。
自定义配置字段
VextConfig 接口允许扩展自定义字段。插件和业务代码可以在配置中添加任意字段:
// src/config/default.ts
export default {
port: 3000,
// 自定义字段
redis: {
url: "redis://localhost:6379",
db: 0,
},
mailer: {
smtp: "smtp://localhost:1025",
from: "noreply@myapp.com",
},
};
配合 declare module 获得类型提示:
// src/types/config.d.ts
declare module "vextjs" {
interface VextConfig {
redis?: {
url: string;
db?: number;
};
mailer?: {
smtp: string;
from: string;
};
}
}
环境变量
除了配置文件,部分设置也可以通过环境变量控制:
// src/config/default.ts — 使用环境变量
export default {
port: Number(process.env.PORT) || 3000,
logger: {
level: process.env.LOG_LEVEL || "info",
},
};
:::warning 安全提示
敏感信息(如数据库密码、API Key)不要硬编码在配置文件中。推荐:
- 使用环境变量:
process.env.DB_PASSWORD
- 使用
local.ts(已加入 .gitignore)存放本地开发的敏感配置
:::
配置校验
config-loader 在合并完成后会执行 Fail Fast 校验,检查以下内容:
port 必须是 1-65535 范围内的正整数
adapter 必须是已知的内置标识或合法的 adapter 对象/函数
middlewares 数组中每个元素必须是字符串或 { name: string } 对象
rateLimit.max 必须是正整数
rateLimit.window 必须是正整数
logger.level 必须是合法的日志级别
shutdown.timeout 必须是正整数
cluster.workers 必须是正整数或 'auto' / 'auto-1'
如果校验失败,框架会在启动时立即报错并给出清晰的错误信息,避免配置错误在运行时才暴露。
完整示例
// src/config/default.ts
export default {
port: Number(process.env.PORT) || 3000,
host: "0.0.0.0",
adapter: "native",
trustProxy: false,
logger: {
level: "info",
},
cors: {
origins: ["*"],
credentials: false,
},
rateLimit: {
enabled: true,
max: 100,
window: 60, // 单位:秒
keyBy: "ip",
},
requestId: {
enabled: true,
header: "x-request-id",
},
bodyParser: {
enabled: true,
maxBodySize: "1mb",
},
accessLog: {
enabled: true,
level: "info",
},
response: {
wrap: true,
hideInternalErrors: true,
},
shutdown: {
timeout: 10, // 单位:秒
},
requestContext: {
enabled: true,
},
openapi: {
enabled: true,
title: "My App API",
version: "1.0.0",
},
middlewares: ["auth", { name: "check-role", options: { roles: ["user"] } }],
// 自定义配置
redis: {
url: process.env.REDIS_URL || "redis://localhost:6379",
},
};
// src/config/production.ts
export default {
logger: { level: "warn" },
cors: { origins: ["https://myapp.com"], credentials: true },
openapi: { enabled: false },
accessLog: { level: "warn" },
cluster: {
enabled: true,
workers: "auto",
},
};
// src/config/local.ts — 不提交到 Git
export default {
port: 8080,
redis: {
url: "redis://localhost:6380",
},
};
下一步