
Product
Introducing Socket Scanning for VS Code Marketplace Extensions
Socket now scans VS Code extensions, giving teams early detection of risky behaviors, hidden capabilities, and supply chain threats in developer tools.
vextjs is a high-performance full-stack Node.js framework with integrated API runtime, scaffolding, typed client generation, and esbuild-powered frontend delivery.
一个现代化的 Node.js Web 框架,开箱即用,专为构建高性能 RESTful API 而设计。
vextjs 提供 Adapter 架构(底层可替换)、插件系统、约定式路由、服务自动注入、参数校验、OpenAPI 文档自动生成等企业级特性,让你专注于业务逻辑。
src/routes/ 下的文件自动扫描加载,文件路径即路由前缀src/services/ 下的 class 自动实例化并挂载到 app.servicescache: 60,LRU 内存存储,标签失效,Vary headers,条件缓存src/locales/ 语言包自动加载,校验错误消息多语言createTestApp,无需启动 HTTP 服务器即可测试路由vext typegen 可生成 app.services / app.extend() 声明并执行 tooling 层依赖诊断;vext doctor routes 已进入 Phase 2 预览vext.preload 与规范项目目录 src/preload/;适合 OpenTelemetry / APM / polyfill / 启动前环境桥接这类必须早于应用代码执行的能力config.frontend 可为同一个 Vext 路由加入 React SSR、hydration、导航、静态/再验证页面和本地媒体构建;URL 与服务端数据入口仍由 src/routes/** 和 res.render() 保持权威。
默认 frontend.render.streaming: "buffered" 使用兼容的 renderToString 路径。The default "buffered" mode remains the compatibility path. 对需要先送达骨架的页面,设置 frontend.render.streaming: "auto";Vext 会在 shell ready 后发送 document prefix 与 Suspense fallback,再继续输出延迟 boundary。Native, Hono, Fastify, Express, and Koa 使用同一生命周期:首字节前冻结响应,超时或客户端断开会中止未完成流。
vextjs/frontend 导出 Link、Form、navigate、prefetch、revalidate、useNavigation、useFetcher 和 useRouteData。浏览器仅在协商 application/vnd.vext.page+json;v=1 后取得 page envelope;请求仍经过 the same handler、middleware、auth、CSRF、validation、cache、redirect 和 error chain。协议、权限或资源不兼容时保留 LKG,并执行 one document navigation。该能力不会新增 second loader/action route DSL。
这条运行时路线不包含 React Server Components、Server Functions、Server Actions 或 partial prerendering (PPR);前端构建继续使用 esbuild,不引入 Webpack/Vite/Rollup/Rolldown 插件生态。
这不是缺少 SSR:RSC 需要独立的 server/client component graph、payload、cache、开发与部署契约,而当前 src/routes/** + res.render() 已提供 SSR、hydration、Suspense、Streaming SSR 和同一路由导航。不要从 React 版本、SSR 或 Suspense 推断 RSC 支持;完整决策边界见 Frontend Boundaries and Roadmap。
在既有路由的 RouteOptions.frontend 中声明 mode: "dynamic" | "static" | "revalidate"。静态路由可提供 staticParams,再验证路由提供以秒为单位的 revalidate,tags 用于失效;clientOnly 保留 document、data 与 assets,但不输出服务端 page body。Vext 以 filesystem store 提供 single-flight、atomic replace 与 last-known-good,因此这不是 PPR 或另一套路由 DSL。
config.frontend.media 只处理 src/frontend/assets/** 中的本地图片与字体,构建会生成 hashed variants、media manifest、SRI/deploy closure 和本地 WOFF2 subset。使用 Image 取得本地响应式图片,使用 defineFont 声明带许可证的本地字体;远程图片必须显式提供 allowlisted defineImageLoader,Vext 从不代理远程图片或下载远程字体。
如果你是第一次接触 VextJS,推荐按下面顺序阅读:
CLI 命令 章节配置 与 环境变量 章节npm install vextjs
默认使用 Native Adapter(基于 Node.js
http.createServer+route-core),零外部 HTTP 框架依赖,性能最优。
如需使用其他 adapter,请额外安装对应框架包:
# Fastify adapter
npm install fastify
# Hono adapter
npm install hono @hono/node-server
# Express adapter
npm install express
# Koa adapter
npm install koa
然后在配置中指定 adapter:
// src/config/default.js
export default {
adapter: "fastify", // 'native' (默认) | 'fastify' | 'hono' | 'express' | 'koa'
};
VextJS 提供 5 种 adapter,覆盖不同使用场景。以下为基准测试数据(5 轮取中位数):
| 场景 | Raw Native | Vext Native | Raw Fastify | Vext Fastify | Native 领先 |
|---|---|---|---|---|---|
| JSON 响应 | 44,932 | 36,819 | 45,619 | 29,203 | +26.1% |
| 路由参数 | 43,859 | 36,755 | 43,676 | 24,386 | +50.7% |
| 中间件链 | 28,337 | 31,698 | 41,286 | 22,719 | +39.5% |
Vext-Native 在所有场景领先 Vext-Fastify 26~51%(中间件链场景 Vext-Native 甚至超越裸跑 Native +11.9%)。
| Adapter | Vext RPS | Overhead | 额外依赖 | 推荐场景 |
|---|---|---|---|---|
| Native ⭐ | 36,819 | 18.1% | ✅ 零依赖 | 默认推荐,性能最优 |
| Express | 30,974 | -3.7% | express | 已有 Express 生态需复用 |
| Fastify | 29,203 | 36.0% | fastify | 需要 Fastify 生态插件 |
| Koa | 22,488 | 29.4% | koa | 已有 Koa 中间件需复用 |
| Hono | 15,684 | 24.2% | hono @hono/node-server | Web Standard API 兼容 |
测试环境: Node.js v24.14.0 + autocannon(50 connections, 10 pipelining, 10s × 5 轮取中位数, Windows x64, i7-9700, 32GB RAM,2026-03-23)
Native adapter 使用 Node.js 内置
http.createServer+route-core路由,是 VextJS 唯一不依赖第三方 HTTP 框架的 adapter。Vext-Native 比 Vext-Fastify 快 26.1%(JSON)/ 39.5%(中间件链),比 Vext-Hono 快 135%,比 Vext-Express 快 18.9%(Express v5 + Node.js v24 性能大幅提升)。所有数据经 5 轮中位数验证,绝大多数 CV(变异系数)< 3.5%。
| 你的场景 | 推荐 Adapter | 理由 |
|---|---|---|
| 新项目,无历史包袱 | native(默认) | 零外部依赖 + 性能最优 |
| 已有 Fastify 插件生态 | fastify | 可复用 Fastify 插件(如 fastify-multipart) |
| 已有 Express 中间件 | express | 兼容庞大的 Express 中间件生态 |
| 已有 Koa 中间件 | koa | 兼容 Koa 中间件 |
| 需要 Web Standard API | hono | Hono 支持 Request/Response Web API 标准 |
my-app/
├── src/
│ ├── config/
│ │ ├── default.js # 应用配置
│ │ └── bootstrap.js # 启动期远程配置 provider(可选)
│ └── routes/
│ └── index.js # 路由定义
└── package.json
package.json{
"name": "my-app",
"type": "module",
"scripts": {
"start": "vext start",
"dev": "vext dev"
},
"dependencies": {
"vextjs": "^1.0.0"
}
}
// src/config/default.js
export default {
port: 3000,
host: "0.0.0.0",
logger: {
level: "info",
},
openapi: {
enabled: true,
},
};
💡 只需声明你关心的字段,其他字段(
requestId、cors、bodyParser、rateLimit、accessLog等)由框架自动补全默认值。
src/config/bootstrap.js)当数据库、密钥、Nacos 远程配置等内容必须在配置冻结前生效时,可新增 src/config/bootstrap.js:
// src/config/bootstrap.js
import { defineBootstrapConfig } from "vextjs";
export default defineBootstrapConfig({
providers: [
{
name: "remote-config",
async load({ env, signal }) {
const response = await fetch(`https://config.example.com/${env}.json`, {
signal,
});
const remote = await response.json();
return {
database: remote.database,
};
},
},
],
});
配置优先级:
默认值 → default.js → {NODE_ENV}.js → local.js → bootstrap provider patch → CLI override
适合场景:
不适合场景:
这类“进程级提早执行”能力应继续使用 preload。
如果你希望在 Vext 应用里直接启用 Trace / Metrics / Logs,可安装 vextjs-opentelemetry:
npm install vextjs-opentelemetry
{
"vext": {
"otel": {
"serviceName": "my-app",
"endpoint": "http://otel-collector.internal:4318",
"sampling": { "ratio": 1 }
}
}
}
// src/plugins/otel.js
import { opentelemetryPlugin } from "vextjs-opentelemetry/vextjs";
export default opentelemetryPlugin({
serviceName: "my-app",
tracing: {
ignorePaths: ["/health", "/_otel/status"],
},
logs: {
bridgeAppLogger: true,
},
});
然后继续使用 vext dev / vext start 启动即可。CLI 会自动读取依赖包声明的 vext.preload,也会识别规范项目目录 src/preload/,并在应用代码前注入对应脚本,无需手动加 node --import ...。
如果你是应用项目而不是插件包,现在也可以直接创建:
src/preload/
├── 01-bootstrap-port.ts
└── 02-bootstrap-verbose.mjs
.mjs / .js 会直接作为 ESM preload 注入.ts / .mts 会在启动前编译到 .vext/preload/*.mjs 再注入vext dev 下修改 src/preload/ 中的文件会触发 cold restart,确保结果与手动重启一致vext build 会把 src/preload/ 编译到 dist/preload/*.mjs,便于生产部署只携带 dist/preload/ 仅保留迁移兼容:使用时会输出迁移 warning;不要同时在两个目录放置 preload 源文件,CLI 会 fail-fast 以避免重复执行更多说明:
vextjs-opentelemetry 在 VextJS 里有两个正式入口,但职责不同:
| 入口 | 生效阶段 | 适合放什么 | 不适合放什么 |
|---|---|---|---|
package.json → vext.otel | preload / 进程启动前 | serviceName、endpoint、protocol、headers、sampling 这类“SDK 一开始就要知道”的默认导出配置 | ignorePaths、capture、日志桥接、请求级逻辑 |
src/plugins/otel.js → opentelemetryPlugin() | plugin setup + request | tracing、metrics、lifecycle、logs.bridgeAppLogger,以及 setup 阶段对 exporter 的补充 / 覆盖 | 指望它回写 preload 阶段已经启动好的 SDK Resource |
✅ 推荐做法:把“导出到哪里、用什么协议、服务名是什么”优先收敛到
package.json vext.otel;把“请求要采什么、日志怎么桥接、哪些路径忽略”放进opentelemetryPlugin()。
endpoint / protocol 对照| 目标 | 推荐配置 | protocol | 结果 |
|---|---|---|---|
| 完全不上报 | 不写 endpoint,或显式写 "none" | — | SDK 可保持安全 noop / 不导出任何数据 |
| 本地文件调试 | "./otel-data" | — | 按 pid 写入 traces.*.jsonl / metrics.*.jsonl / logs.*.jsonl |
| OTLP HTTP Collector | "http://otel-collector.internal:4318" | "http"(默认) | 通过 OTLP/HTTP 上报 |
| OTLP gRPC Collector | "otel-collector.internal:4317" | "grpc" | 通过 gRPC h2c 上报 |
💡 如果你同时在
package.json vext.otel和opentelemetryPlugin()里都写了endpoint / protocol / headers,建议保持一致,避免/_otel/status、启动日志和最终实际导出目标出现认知偏差。
/_otel/status 显示 sdk: "noop"
vext dev / vext start 启动,而不是直接 node dist/server.jsvextjs-opentelemetry 在 dependencies 中--import vextjs-opentelemetry/instrumentationexportTarget 不是你期望的地址
package.json vext.otelsrc/plugins/otel.js 是否又追加了不同的 endpoint / protocol / headerstrace_id
/_otel/status 已是 initializedapp.logger 也桥接到 OTel Logs,开启 logs.bridgeAppLogger: true./otel-data 本地文件模式确认数据是否已生成capture.headers、capture.body 只建议白名单采集,不要把 authorization、cookie、密码、手机号、邮箱等敏感字段直接打进遥测/_otel/status 适合排障,但生产环境建议只开放给内网或经网关限制访问headers 中若需要放 API Key / Token,优先通过环境变量或部署平台 Secret 注入;不要把真实密钥硬编码进仓库里的 package.jsonpackage.json vext.otel 更适合放“默认导出目标与服务名”这类非敏感配置;真正的敏感凭证请交给运行时注入// src/routes/index.js
import { defineRoutes } from "vextjs";
export default defineRoutes((app) => {
app.get("/", {}, async (req, res) => {
res.json({ message: "Hello, VextJS!" });
});
app.get("/health", {}, async (req, res) => {
res.json({ status: "ok", uptime: process.uptime() });
});
});
# 开发模式(热重载)
npm run dev
# 生产模式
npm start
# 验证
curl http://localhost:3000/
# → {"code":0,"data":{"message":"Hello, VextJS!"}}
VextJS 提供内置 CLI,通过 npx vext 或 package.json scripts 调用。
vext start — 启动编译产物vext start # 使用默认配置启动
vext start --port 8080 # 指定端口
vext start --host 127.0.0.1 # 指定监听地址
NODE_ENV=production vext start # 加载 production 配置
NODE_ENV=sg-sit vext start # 加载 sg-sit 配置(需存在 src/config/sg-sit.ts)
启动流程:检测项目结构 → 加载配置 → 注册插件/中间件/服务/路由 → 启动 HTTP 服务器。
如果存在 dist/ 编译产物,自动使用编译后的 JS 运行;TypeScript 项目无 dist/ 时自动通过 tsx 加载。
环境配置文件通过运行时 NODE_ENV 选择:src/config/{NODE_ENV}.ts。
⚠️
vext build当前会将用户源码中的process.env.NODE_ENV静态注入为"production"。因此不要依赖 build 后源码里的process.env.NODE_ENV条件分支做运行时环境切换;环境差异应优先写入src/config/<env>.ts、bootstrap provider 或其他显式业务环境变量。
vext dev — 开发模式vext dev # 启动开发服务器
vext dev --poll # Docker / NFS 环境使用轮询模式
vext dev --poll-interval 2000 # 自定义轮询间隔(毫秒)
vext dev --debounce 50 # 自定义防抖间隔(毫秒,默认 0 不开启)
vext dev --no-hot # 禁用 Soft Reload,所有变更走 Cold Restart
vext dev --clear # 每次重载后清空控制台
在 0.3.7 起,vext dev 会在 initial start、文件变更、手动 reload / restart、以及子进程请求 cold restart 前统一执行一次 dev preflight:
typegen,保持 src/types/generated/*.generated.d.ts 与当前 services / plugins 定义同步;tsconfig.json 的语义诊断;三层重载策略:
| Tier | 触发条件 | 动作 | 速度 |
|---|---|---|---|
| T1 | 代码修改(modify) | Soft Reload — esbuild.transform() 热替换 | ⚡ 毫秒级 |
| T2 | 文件新增 / 删除 | Soft Reload — esbuild ctx.rebuild() 重建 | ⚡ 毫秒级 |
| T3 | 配置 / 插件 / .env 变更 | Cold Restart — kill + fork 重启子进程 | 🔄 秒级 |
键盘快捷键:
| 按键 | 功能 |
|---|---|
r | 手动 Cold Restart |
h | 手动 Soft Reload(全量) |
c | 清空控制台 |
? | 显示帮助 |
Ctrl+C | 退出开发服务器 |
vext build — 构建vext build # TypeScript 编译为 JavaScript
vext typegen / vext doctor routes — 工程辅助命令(experimental)Phase 1 / Phase 2 新增的静态工具链能力整体仍保持 tooling-only 边界:不会进入 start / build 的默认 runtime 主路径;但从 0.3.7 起,vext dev 会在 preflight 中自动执行基础 typegen,用于在开发态同步 generated 声明并阻断明显的 TypeScript 语义错误。
# 生成 app.services / app.extend() 声明,并执行 tooling 层 service 依赖诊断
vext typegen
# 仅校验 generated 产物是否需要更新,不写文件
vext typegen --check
# 输出服务索引 / app.extend / 依赖图的稳定 manifest
vext typegen --write-manifest
# 扫描静态路由信息,并将诊断结果写入 inspect + manifest
vext doctor routes --write-inspect --write-manifest
当前产物约定:
src/types/generated/services.generated.d.tssrc/types/generated/app-extensions.generated.d.ts.vext/inspect/services.manifest.json.vext/inspect/routes.json.vext/inspect/routes.manifest.json说明:
vext typegen 面向 services / plugins,解决声明生成与依赖诊断问题;vext dev 会自动执行基础 typegen(生成 services/app-extensions 两类声明),但如果你需要 --check / --write-manifest 等更强控制,仍应显式调用 vext typegen;vext typegen --write-manifest 会额外生成 services.manifest.json,把 service 索引、app.extend() 聚合结果与依赖图摘要固化为稳定消费层;vext doctor routes 面向静态路由治理,当前 doctor all 仍等价于 routes;routes.json 是诊断 / inspect 产物,routes.manifest.json 是给编辑器、CI、可视化等下游工具消费的稳定契约层;services.manifest.json 当前聚焦 service 索引、app.extend() 聚合信息与服务依赖图;routes 与 services 仍保持分层产物,避免过早合并成单一总 manifest。my-app/
├── src/
│ ├── config/
│ │ ├── default.js # 默认配置
│ │ ├── production.js # 生产环境覆盖(可选)
│ │ └── local.js # 本地覆盖,不提交到 Git(可选)
│ ├── routes/ # 路由目录(自动扫描)
│ │ ├── index.js # → /
│ │ ├── users.js # → /users
│ │ └── api/
│ │ └── posts.js # → /api/posts
│ ├── services/ # 服务层(自动注入到 app.services)
│ │ ├── user.js # → app.services.user
│ │ └── payment/
│ │ └── stripe.js # → app.services.payment.stripe
│ ├── middlewares/ # 自定义路由级中间件
│ ├── plugins/ # 插件(拓扑排序加载)
│ ├── locales/ # i18n 语言包(可选)
│ │ ├── zh-CN.json
│ │ └── en.json
│ └── ...
├── package.json
└── tsconfig.json # TypeScript 项目(可选)
路由使用 defineRoutes 定义,支持三段式 (path, options, handler) 和两段式 (path, handler) 语法。
// src/routes/users.js
import { defineRoutes } from "vextjs";
export default defineRoutes((app) => {
// 三段式:path, options, handler
app.get(
"/list",
{
docs: { summary: "获取用户列表" },
validate: {
query: { page: "number:1-", limit: "number:1-100" },
},
},
async (req, res) => {
const { page, limit } = req.valid("query");
const users = await app.services.user.findAll({ page, limit });
res.json(users);
},
);
// 两段式:path, handler(无 options)
app.get("/:id", async (req, res) => {
const user = await app.services.user.findById(req.params.id);
res.json(user);
});
app.post(
"/",
{
validate: {
body: { name: "string:1-50", email: "email" },
},
},
async (req, res) => {
const user = await app.services.user.create(req.valid("body"));
res.json(user, 201);
},
);
app.delete("/:id", {}, async (req, res) => {
await app.services.user.delete(req.params.id);
res.json({ deleted: true });
});
});
| 文件路径 | 路由前缀 |
|---|---|
src/routes/index.js | / |
src/routes/users.js | /users |
src/routes/api/posts.js | /api/posts |
src/routes/api/v2/orders.js | /api/v2/orders |
app.get(
"/protected",
{
// 路由级中间件引用(需在 config.middlewares 白名单中声明)
middlewares: ["auth", { name: "rbac", options: { roles: ["admin"] } }],
// 参数校验(schema-dsl 语法)
validate: {
query: { page: "number", limit: "number" },
param: { id: "string" },
body: { name: "string:1-100", email: "email" },
},
// OpenAPI 文档元信息
docs: {
summary: "获取受保护资源",
description: "需要认证和管理员角色",
tags: ["Admin"],
},
},
handler,
);
服务文件放在 src/services/ 下,导出一个 class,框架自动实例化并注入到 app.services。
// src/services/user.js
export default class UserService {
constructor(app) {
this.app = app;
this.logger = app.logger;
}
async findAll({ page = 1, limit = 20 }) {
this.logger.info(`Fetching users page=${page} limit=${limit}`);
// 数据库查询...
return { users: [], total: 0 };
}
async findById(id) {
// ...
}
async create(data) {
// ...
}
}
// 在路由中使用
app.get("/users", {}, async (req, res) => {
const result = await app.services.user.findAll({ page: 1 });
res.json(result);
});
services/
├── user.js → app.services.user
├── user-profile.js → app.services.userProfile
└── payment/
├── stripe.js → app.services.payment.stripe
└── alipay.js → app.services.payment.alipay
kebab-case 自动转换为 camelCase_ 开头的文件/目录会被跳过插件用于扩展框架能力,支持依赖声明和拓扑排序加载。
// src/plugins/redis.js
import { definePlugin } from "vextjs";
import Redis from "ioredis";
export default definePlugin({
name: "redis",
// 声明依赖(可选),框架自动按拓扑顺序加载
// dependencies: ['database'],
async setup(app) {
const redis = new Redis(app.config.redis);
// 扩展 app 对象
app.extend("cache", redis);
// 注册全局中间件
app.use(async (req, res, next) => {
req.cache = app.cache;
await next();
});
// 注册关闭钩子(优雅关闭时执行)
app.onClose(async () => {
await redis.quit();
app.logger.info("Redis disconnected");
});
},
});
// 在路由/服务中使用插件扩展的能力
const cached = await app.cache.get("user:123");
VextJS 内置以下中间件,全部开箱即用,无需手动注册:
| 中间件 | 功能 | 配置字段 |
|---|---|---|
| requestId | 为每个请求生成唯一 ID | config.requestId |
| cors | 跨域资源共享 | config.cors |
| bodyParser | 请求体解析(JSON / URLEncoded) | config.bodyParser |
| rateLimit | 速率限制 | config.rateLimit |
| responseWrapper | 统一响应格式 { code, data, message } | config.response |
| accessLog | 请求访问日志 | config.accessLog |
| errorHandler | 全局错误处理 + 404 兜底 | — |
// src/middlewares/auth.js
import { defineMiddleware } from "vextjs";
export default defineMiddleware(async (req, res, next) => {
const token = req.headers["authorization"];
if (!token) {
req.app.throw(401, "Unauthorized");
}
// 解析 token,设置用户信息...
await next();
});
// src/middlewares/rbac.js
import { defineMiddlewareFactory } from "vextjs";
export default defineMiddlewareFactory((options) => {
return async (req, res, next) => {
if (!options.roles.includes(req.user?.role)) {
req.app.throw(403, "Forbidden");
}
await next();
};
});
// 在路由中使用(需在 config.middlewares 白名单声明)
app.get(
"/admin",
{
middlewares: [{ name: "rbac", options: { roles: ["admin"] } }],
},
handler,
);
配置文件支持分层合并:框架内置默认值 → default → {NODE_ENV} → local → bootstrap provider patch → CLI override。
// src/config/default.js — 默认配置
export default {
port: 3000,
host: "0.0.0.0",
logger: {
level: "info", // 'debug' | 'info' | 'warn' | 'error' | 'silent'
},
cors: {
origins: ["*"], // 允许的来源列表(数组格式)
methods: ["GET", "POST", "PUT", "PATCH", "DELETE"],
},
bodyParser: {
maxBodySize: "1mb",
},
rateLimit: {
max: 100, // 每个窗口期最大请求数
window: 60, // 窗口期时长(秒,数字)
},
requestId: {
enabled: true,
header: "X-Request-Id",
},
response: {
hideInternalErrors: true, // 生产环境隐藏内部错误详情
},
openapi: {
enabled: true,
title: "My API",
version: "1.0.0",
},
shutdown: {
timeout: 10, // 优雅关闭超时(秒)
},
};
// src/config/production.js — 生产环境覆盖
export default {
logger: { level: "warn" },
response: { hideInternalErrors: true },
};
// src/config/local.js — 本地开发覆盖(加入 .gitignore)
export default {
port: 4000,
logger: { level: "debug" },
};
除了 development / production / test 之外,Vext 也支持任意环境名,例如:
src/config/sg-sit.js
src/config/us-uat.js
src/config/us-prod.js
启动时只要设置对应的 NODE_ENV,Vext 就会自动加载匹配文件:
NODE_ENV=sg-sit vext start
如果你希望在 package.json scripts 中跨平台设置环境变量,推荐安装 cross-env:
npm i -D cross-env
{
"scripts": {
"start:sg-sit": "cross-env NODE_ENV=sg-sit vext start",
"start:us-uat": "cross-env NODE_ENV=us-uat vext start"
}
}
CLI 参数 --port / --host 优先级最高,覆盖配置文件和 bootstrap provider patch 中的值。
路由选项中的 validate 字段使用 schema-dsl 语法,声明式校验请求参数。
app.post(
"/users",
{
validate: {
body: {
name: "string:1-50", // 字符串,长度 1-50
email: "email", // 邮箱格式
age: "number:0-150?", // 可选数字,范围 0-150
role: "enum:admin,user,guest", // 枚举值
tags: "[string]", // 字符串数组
},
query: {
format: "enum:json,xml?", // 可选枚举
},
},
},
async (req, res) => {
const body = req.valid("body"); // 类型安全的校验后数据
const query = req.valid("query");
// ...
},
);
校验失败时自动返回 400 错误,包含详细的字段错误信息。支持 i18n 多语言错误消息。
路由选项中的 cache 字段提供声明式响应缓存,支持数字简写或完整配置对象。
// 数字简写:缓存 60 秒
app.get("/products", { cache: 60 }, async (req, res) => {
res.json(await db.getProducts());
});
// 完整配置:TTL + Vary headers + 标签失效
app.get(
"/products",
{
cache: {
ttl: 120,
vary: ["accept-language"], // 不同语言单独缓存
tags: ["products"], // 标签(用于批量失效)
condition: (req) => !req.query.refresh, // 条件缓存
},
},
async (req, res) => {
res.json(await db.getProducts());
},
);
缓存命中时自动设置 X-Cache: HIT 和 Cache-Control: public, max-age=N 响应头。
// 按标签批量失效
await app.cache.invalidate("products");
// 清空所有缓存
await app.cache.clear();
// 查看缓存统计
const stats = app.cache.stats();
// → { entries: 42, hits: 128, misses: 31, hitRate: 0.805 }
// src/config/default.js
export default {
cache: {
enabled: true, // 是否启用(默认 true)
defaultTtl: 60, // 默认 TTL 秒数
maxEntries: 1000, // 最大缓存条目数
},
};
启用 openapi.enabled: true 后,框架自动从路由元信息生成 OpenAPI 3.0.3 文档,并提供交互式文档页面。
| 端点 | 说明 |
|---|---|
GET /openapi.json | OpenAPI JSON spec(供外部工具消费) |
GET /docs | Scalar API Reference 交互式文档页面(文档阅读 + Try it out) |
# 获取 OpenAPI JSON
curl http://localhost:3000/openapi.json
# 浏览器打开交互式文档
open http://localhost:3000/docs
// src/config/default.js
export default {
openapi: {
enabled: true,
title: "My API",
version: "1.0.0",
// Scalar API Reference 配置
scalar: {
theme: "default", // 主题: default / alternate / moon / purple / solarized / ...
darkMode: false, // 深色模式
layout: "modern", // 布局: modern / classic
showSidebar: true, // 显示侧边栏
},
},
};
路由的 docs 选项用于补充文档元信息:
app.get(
"/users/:id",
{
docs: {
summary: "获取用户详情",
description: "根据用户 ID 获取完整的用户信息",
tags: ["Users"],
},
validate: {
params: { id: "string" },
},
},
handler,
);
VextJS 提供内置测试工具,无需启动 HTTP 服务器即可测试路由。
import { describe, it, expect } from "vitest";
import { createTestApp } from "vextjs/testing";
describe("User API", () => {
it("should return user list", async () => {
const app = await createTestApp({
rootDir: "/path/to/project",
});
const res = await app.request.get("/users/list?page=1&limit=10");
expect(res.status).toBe(200);
expect(res.body.code).toBe(0);
expect(res.body.data).toBeDefined();
});
});
在 src/locales/ 下放置语言文件,框架自动加载并注册到 schema-dsl 校验器。
// src/locales/zh-CN.json
{
"validation.required": "{field} 不能为空",
"validation.string.min": "{field} 长度不能少于 {min} 个字符",
"validation.email": "{field} 格式不正确",
}
// src/locales/en.json
{
"validation.required": "{field} is required",
"validation.string.min": "{field} must be at least {min} characters",
"validation.email": "{field} is not a valid email",
}
用户请求
│
▼
┌──────────────────────────────────────────────┐
│ VextJS Framework │
│ │
│ ┌─── 内置中间件链 ───────────────────────┐ │
│ │ requestId → cors → bodyParser → │ │
│ │ rateLimit → responseWrapper → accessLog│ │
│ └────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─── 路由级中间件 ──┐ │
│ │ auth → rbac → ... │ │
│ └───────────────────┘ │
│ │ │
│ ▼ │
│ ┌─── 参数校验 ──────┐ │
│ │ validate(schema) │ │
│ └───────────────────┘ │
│ │ │
│ ▼ │
│ ┌─── 路由 Handler ──┐ ┌── Services ──┐ │
│ │ app.get/post/... │─→│ app.services │ │
│ └───────────────────┘ └──────────────┘ │
│ │ │
│ ▼ │
│ ┌─── Adapter Layer ─────────────────────┐ │
│ │ Native (默认) / Fastify / Hono / │ │
│ │ Express / Koa — 可替换 │ │
│ └───────────────────────────────────────┘ │
└──────────────────────────────────────────────┘
│
▼
HTTP 响应 → { code: 0, data: {...} }
default → {env} → local → bootstrap provider patch → CLI override + 冻结src/locales/setup()config.middlewares 白名单加载src/services/,实例化注入 app.servicessrc/routes/,注册到 adapteradapter.listen(port, host)onReady 回调| 变量 | 说明 | 默认值 |
|---|---|---|
NODE_ENV | 运行时环境名;用于匹配 src/config/{NODE_ENV}.ts | production(start 默认)/ development(dev 默认) |
VEXT_PORT | 覆盖监听端口 | — |
VEXT_HOST | 覆盖监听地址 | — |
VEXT_PORT_CONFLICT | 端口冲突策略(error / prompt / kill / next) | error |
VEXT_LIFECYCLE_LEVEL | 生命周期日志级别(concise / verbose) | concise |
VEXT_DEV_POLL | 强制轮询模式(1 / 0) | 自动检测 |
VEXT_DEV_NO_HOT | 禁用 Soft Reload | — |
VEXT_DEV_DEBOUNCE | 防抖间隔(毫秒) | 0(不开启) |
如果项目需要在
package.jsonscripts 中跨平台设置NODE_ENV,推荐使用cross-env;Vext 本身不内置该工具。
http.createServer + route-core)vext create 项目脚手架欢迎提交 Issue 和 Pull Request。
# 克隆项目
git clone https://github.com/vextjs/vext.git
cd vext
# 安装依赖
npm install
# 开发(TypeScript 监听编译)
npm run dev
# 运行测试
npm test
# 类型检查
npm run typecheck
# 构建
npm run build
FAQs
AI-first full-stack Node.js framework for APIs and server-rendered pages with typed contracts, OpenAPI, and machine-readable docs.
The npm package vextjs receives a total of 157 weekly downloads. As such, vextjs popularity was classified as not popular.
We found that vextjs demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Product
Socket now scans VS Code extensions, giving teams early detection of risky behaviors, hidden capabilities, and supply chain threats in developer tools.

Research
/Security News
Socket uncovered two malicious VS Code themes in a GlassWorm-linked cluster with thousands of installs across VS Code Marketplace and Open VSX.

Security News
/Company News
Capital One is partnering with Socket to proactively secure its open source supply chain.