ไธไธช็ฐไปฃๅ็ Node.js Web ๆกๆถ๏ผๅผ็ฎฑๅณ็จ๏ผไธไธบๆๅปบ้ซๆง่ฝ RESTful API ่่ฎพ่ฎกใ
VextJS ๆไพ Adapter ๆถๆ๏ผๅบๅฑๅฏๆฟๆข๏ผใๆไปถ็ณป็ปใ็บฆๅฎๅผ่ทฏ็ฑใๆๅก่ชๅจๆณจๅ ฅใๅๆฐๆ ก้ชใOpenAPI ๆๆกฃ่ชๅจ็ๆ็ญไผไธ็บง็นๆง๏ผ่ฎฉไฝ ไธๆณจไบไธๅก้ป่พใ
- ๐ Adapter ๆถๆ โ ๅบๅฑ HTTP ๆกๆถๅฏๆฟๆข๏ผ้ป่ฎค Native Adapter๏ผ้ถๅค้จไพ่ต๏ผ๏ผไธๅกไปฃ็ ๆ ้ๆนๅจ
- ๐ ็บฆๅฎๅผ่ทฏ็ฑ โ
src/routes/ไธ็ๆไปถ่ชๅจๆซๆๅ ่ฝฝ๏ผๆไปถ่ทฏๅพๅณ่ทฏ็ฑๅ็ผ - ๐งฉ ๆไปถ็ณป็ป โ ๆๆๆๅบใไพ่ตๅฃฐๆใ็ๅฝๅจๆ้ฉๅญ๏ผ่ฝปๆพๆฉๅฑๆกๆถ่ฝๅ
- ๐ ๆๅก่ชๅจๆณจๅ
ฅ โ
src/services/ไธ็ class ่ชๅจๅฎไพๅๅนถๆ่ฝฝๅฐapp.services - ๐ก๏ธ ๅๆฐๆ ก้ช โ ้ๆ schema-dsl๏ผๅฃฐๆๅผๆ ก้ช + i18n ้่ฏฏๆถๆฏ
- ๐ OpenAPI ๆๆกฃ โ ่ทฏ็ฑๅ ไฟกๆฏ่ชๅจๆถ้๏ผ็ๆ OpenAPI 3.1 JSON
- ๐ฅ ๅผๅๆจกๅผ็ญ้่ฝฝ โ ไธๅฑ้่ฝฝ็ญ็ฅ๏ผSoft Reload + Cold Restart๏ผ๏ผๆฏซ็ง็บงๅ้ฆ
- ๐๏ธ ๅ ็ฝฎไธญ้ดไปถ โ requestIdใCORSใbodyParserใrateLimitใaccessLogใresponseWrapper ๅผ็ฎฑๅณ็จ
- โก ่ทฏ็ฑ็ผๅญ โ ๅฃฐๆๅผ
cache: 60๏ผLRU ๅ ๅญๅญๅจ๏ผๆ ็ญพๅคฑๆ๏ผVary headers๏ผๆกไปถ็ผๅญ - ๐ i18n ๆฏๆ โ
src/locales/่ฏญ่จๅ ่ชๅจๅ ่ฝฝ๏ผๆ ก้ช้่ฏฏๆถๆฏๅค่ฏญ่จ - ๐งช ๆต่ฏๅทฅๅ
ท โ ๅ
็ฝฎ
createTestApp๏ผๆ ้ๅฏๅจ HTTP ๆๅกๅจๅณๅฏๆต่ฏ่ทฏ็ฑ - โก TypeScript ๅ็ โ ๅฎๆด็ฑปๅๅฎไน๏ผๆ่ด็ IDE ่กฅๅ จไฝ้ช
- ๐ฆ ้ถ้ ็ฝฎๅฏๅจ โ ๅ็็้ป่ฎค้ ็ฝฎ๏ผๆๅฐ 5 ไธชๅญๆฎตๅณๅฏ่ฟ่ก
npm install vextjs้ป่ฎคไฝฟ็จ Native Adapter๏ผๅบไบ Node.js
http.createServer+find-my-wayradix trie๏ผ๏ผ้ถๅค้จ 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+find-my-wayradix trie ่ทฏ็ฑ๏ผๆฏ 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 # ๅบ็จ้
็ฝฎ
โ โโโ routes/
โ โโโ index.js # ่ทฏ็ฑๅฎไน
โโโ package.json
{
"name": "my-app",
"type": "module",
"scripts": {
"start": "vext start",
"dev": "vext dev"
},
"dependencies": {
"vextjs": "^0.2.3"
}
}// 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/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 --port 8080 # ๆๅฎ็ซฏๅฃ
vext start --host 127.0.0.1 # ๆๅฎ็ๅฌๅฐๅๅฏๅจๆต็จ๏ผๆฃๆต้กน็ฎ็ปๆ โ ๅ ่ฝฝ้ ็ฝฎ โ ๆณจๅๆไปถ/ไธญ้ดไปถ/ๆๅก/่ทฏ็ฑ โ ๅฏๅจ HTTP ๆๅกๅจใ
ๅฆๆๅญๅจ dist/ ็ผ่ฏไบง็ฉ๏ผ่ชๅจไฝฟ็จ็ผ่ฏๅ็ JS ่ฟ่ก๏ผTypeScript ้กน็ฎๆ dist/ ๆถ่ชๅจ้่ฟ tsx ๅ ่ฝฝใ
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 # ๆฏๆฌก้่ฝฝๅๆธ
็ฉบๆงๅถๅฐไธๅฑ้่ฝฝ็ญ็ฅ๏ผ
| 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 # TypeScript ็ผ่ฏไธบ JavaScriptmy-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ใ
// 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" },
};CLI ๅๆฐ --port / --host ไผๅ
็บงๆ้ซ๏ผ่ฆ็้
็ฝฎๆไปถไธญ็ๅผใ
่ทฏ็ฑ้้กนไธญ็ 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.1 ๆๆกฃ๏ผๅนถๆไพไบคไบๅผๆๆกฃ้กต้ขใ
| ็ซฏ็น | ่ฏดๆ |
|---|---|
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ไธๅฑๅๅนถ + ๅป็ป - ๅๅปบ App โ ๅๅงๅ loggerใvalidatorใadapterใthrow
- i18n ๅ ่ฝฝ โ ่ชๅจๆซๆ
src/locales/ - ๆไปถๅ ่ฝฝ โ ๆๆๆๅบ + ไพๆฌก
setup() - ไธญ้ดไปถๅ ่ฝฝ โ ๆ
config.middlewares็ฝๅๅๅ ่ฝฝ - ๆๅกๅ ่ฝฝ โ ๆซๆ
src/services/๏ผๅฎไพๅๆณจๅ ฅapp.services - ่ทฏ็ฑๅ ่ฝฝ โ ๆซๆ
src/routes/๏ผๆณจๅๅฐ adapter - ๅ ็ฝฎไธญ้ดไปถๆณจๅ โ requestId โ cors โ bodyParser โ rateLimit โ responseWrapper โ accessLog โ errorHandler
- HTTP ็ๅฌ โ
adapter.listen(port, host) - ๅฐฑ็ปช้ฉๅญ โ ๆง่ก
onReadyๅ่ฐ
| ๅ้ | ่ฏดๆ | ้ป่ฎคๅผ |
|---|---|---|
NODE_ENV |
่ฟ่ก็ฏๅข | production๏ผstart๏ผ/ development๏ผdev๏ผ |
VEXT_PORT |
่ฆ็็ๅฌ็ซฏๅฃ | โ |
VEXT_HOST |
่ฆ็็ๅฌๅฐๅ | โ |
VEXT_DEV_POLL |
ๅผบๅถ่ฝฎ่ฏขๆจกๅผ๏ผ1 / 0๏ผ |
่ชๅจๆฃๆต |
VEXT_DEV_NO_HOT |
็ฆ็จ Soft Reload | โ |
VEXT_DEV_DEBOUNCE |
้ฒๆ้ด้๏ผๆฏซ็ง๏ผ | 0๏ผไธๅผๅฏ๏ผ |
- Adapter ๆถๆ๏ผNative ้ป่ฎค + Hono / Fastify / Express / Koa ๅฏ้๏ผ
- Native Adapter๏ผ้ถๅค้จไพ่ต๏ผ
http.createServer+find-my-wayradix trie๏ผ - ็บฆๅฎๅผ่ทฏ็ฑ + ไธๆฎตๅผ่ฏญๆณ
- ๆไปถ็ณป็ป๏ผๆๆๆๅบ + ็ๅฝๅจๆ๏ผ
- ๆๅก่ชๅจๆณจๅ ฅ
- ๅ ็ฝฎไธญ้ดไปถ๏ผrequestId / CORS / bodyParser / rateLimit / accessLog๏ผ
- ๅๆฐๆ ก้ช๏ผschema-dsl ้ๆ๏ผ
- OpenAPI 3.1 ๆๆกฃ็ๆ
- CLI๏ผstart / dev / build / stop / reload / status๏ผ
- ๅผๅๆจกๅผ็ญ้่ฝฝ๏ผSoft Reload + Cold Restart๏ผ
- ๆต่ฏๅทฅๅ ท๏ผcreateTestApp๏ผ
- Cluster ๅค่ฟ็จ๏ผMaster/Worker + Rolling Restart๏ผ
- ๆง่ฝๅบๅๆต่ฏ๏ผautocannon ่ชๅจๅ + ๅค่ฝฎๅไธญไฝๆฐ๏ผ
- AsyncLocalStorage ๅฏ้ ็ฝฎ่ทณ่ฟ
- Native Adapter ๆง่ฝไผๅ๏ผOverhead ้่ณ
18%๏ผ้ขๅ Fastify 2651%๏ผ -
vext create้กน็ฎ่ๆๆถ - ๆๆกฃ็ซ๏ผrspress๏ผ
- ่ทฏ็ฑ็บงๅๅบ็ผๅญ๏ผLRU ๅ ๅญๅญๅจ๏ผๆ ็ญพๅคฑๆ๏ผVary headers๏ผ
- SSE ๆฏๆ
- WebSocket ๆฏๆ
ๆฌข่ฟๆไบค 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