release · 

Nitro v3 候选发布版来了!

Nitro v3 RC 已发布,API 现已稳定。安装体积缩小 5 倍,支持运行时模式和 Vitest,还有更多更新。

自从上一个测试版以来,40 多位贡献者提交了 240 多个变更;为 Nitro 提供支持的 H3 和 UnJS 生态也进行了许多改进。我们补齐了最后几项重要功能,完善了 API 的各个细节,并清理了遗留代码,让 v3 正式版有一个干净的起点。下面是本次更新的重点。

开始使用 ↓

#📦 运行时模式

Nitro 一直是服务器构建工具。现在,你可以完全跳过构建步骤,直接将其用作运行时(实验性功能)。

npx nitro serve

新的 nitro serve 命令(别名 nitro start)可以在任意 Nitro 项目中直接从源文件启动生产服务器,与配置的构建器无关:

  • 无需构建。 源文件会直接运行,无需提前编译。
  • 适用于生产环境。 支持 WebSocket、定时任务、公共资源、.env 文件,并会在收到 SIGINT/SIGTERM 时平稳关闭。
  • 运行迅速。 它会在内存中使用相同的编译路由器;在我们的基准测试中,其每秒请求数与 srvx 上直接运行 h3 的结果相近。
  • 适合开发。 运行 nitro serve --dev 可监听源文件变化并自动重启。

源文件会加载到主进程中;使用 buildPlugins 时,则会加载到 Node.js worker 中。TypeScript、JSX、别名、import.meta.*、raw/text/bytes 导入以及 WebAssembly 都与打包构建一样可用。文件会按需转换,虚拟模块由内存提供。nitro preview 仍只提供构建输出。

阅读更多 →

#开发模式下的运行时模式

若要在 nitro dev 中也使用运行时模式,请设置 builder: false:

nitro.config.ts
import { defineConfig } from "nitro";

export default defineConfig({
  builder: false,
});

此时源文件会在 worker 中运行,并在每次变更时替换 worker。未安装 rolldown 时,nitro dev 现在会自动回退到运行时模式。若要以运行时模式创建新项目,请在 nitro create 中选择 Runtime 模板(参见下方“开始使用”)。

阅读更多 →

#nitro fetch

如果只需要获取一次响应,而不是启动服务器,可以使用 nitro fetch 或 nitro curl:它会从源文件启动服务器,发送单个请求,打印响应后退出。

npx nitro fetch /api/hello

阅读更多 →

#🧩 构建插件

新的 buildPlugins 选项接收一个插件列表,适用于所有构建器:rollup、rolldown、vite,甚至运行时模式。

nitro.config.ts
import { defineConfig } from "nitro";

export default defineConfig({
  buildPlugins: [
    {
      name: "my-virtual-module",
      resolveId: {
        filter: { id: /^virtual:my-module$/ },
        handler: (id) => `\0${id}`,
      },
      load: {
        filter: { id: /^\0virtual:my-module$/ },
        handler: () => `export default "Hello!"`,
      },
    },
  ],
});

阅读更多 →

#🪶 安装体积缩小 5 倍

Nitro 现在只有 6 个直接依赖。构建器、polyfill 和驱动(rolldown、unenv、unstorage、db0)会在项目需要时按需安装。

与 Nitro v2(nitropack)相比,安装体积现在约缩小了 15 倍:外部依赖从 338 个减少到 6 个,安装文件从 7000 多个减少到 600 个以内。

nitropack@2 nitro@beta nitro@rc 安装体积 69 MB 26 MB 4.7 MB 外部依赖 338 20 6 安装文件 7,102 1,418 558

在 linux-x64 上通过全新安装 npm i 测得(v2 使用 [email protected])。

开发错误页现在已内置。Nitro 仍然没有 peer 依赖。框架可以通过新的 deps 选项传入自己的可选依赖副本。

#🧪 使用 Vitest 零配置测试

在 Vite 配置中添加 nitro(),然后运行 vitest 即可。

api.test.ts
import { expect, test } from "vitest";
import { serverFetch } from "nitro";

test("GET /api/hello", async () => {
  const res = await serverFetch("/api/hello");
  expect(await res.json()).toEqual({ hello: "world" });
});

测试会在 nitro 环境中运行,路由、插件、运行时配置和 KV 的行为与服务器中完全相同。无需启动开发服务器。每个测试文件都会获得独立应用,vi.mock 可以正常工作,并且监听模式会在路由变化时重新运行测试。

阅读更多 →

完整项目请参阅 Vitest 示例。

#🔌 服务器入口选项

现在可以在 server.ts 中配置其运行的服务器。将默认导出包装在 defineServerEntry() 中,即可获得类型化选项:

server.ts
import { defineServerEntry } from "nitro";

export default defineServerEntry({
  port: 8080,
  maxRequestBodySize: 1024 * 1024,
  fetch(req) {
    return new Response("Hello from server entry!");
  },
});

在 Node.js、Bun 和 Deno 预设中,这些选项会直接传给 srvx:port、hostname、reusePort、protocol、tls、silent、gracefulShutdown、maxRequestBodySize、trustProxy,以及运行时专属的 node、bun 和 deno 设置。NITRO_PORT 和 NITRO_HOST 等环境变量仍具有更高优先级,因此仍可在运行时配置服务器。

阅读更多 →

#🏷️ 自定义环境

Nitro 之前已支持 $development 和 $production 配置覆盖。现在,你可以通过 nitro dev、nitro build、nitro serve 和 nitro deploy 的新 --envName 标志选择任意环境名称:

nitro.config.ts
import { defineConfig } from "nitro";

export default defineConfig({
  $env: {
    staging: { runtimeConfig: { apiBase: "https://staging.example.com" } },
  },
});
npx nitro build --envName staging

服务器代码可以通过 import.meta.envName 获取环境名称,该值会由所有构建器在构建时替换。预渲染路由也使用相同的名称,因此会获得与服务器相同的配置覆盖。

routes/env.ts
import { defineHandler } from "nitro";

export default defineHandler(() => ({ env: import.meta.envName })); // "staging"

阅读更多 →

#🥟 运行时原生开发服务器

nitro dev 现在可以原生运行在 Bun 和 Deno 上。开发服务器会使用运行时自带的服务器(Bun.serve(),或通过 srvx 调用 Deno.serve()),而不再经过 node:http 兼容层。

bun --bun nitro dev

WebSocket 会使用代码运行所在运行时的适配器, devProxy 也可正常工作:HTTP 请求通过 fetch 代理,WebSocket 则通过 crossws 代理。在 Node.js 上没有变化。

#▲ Vercel

  • 显式 ISR。 只有 isr 路由规则会启用 ISR。与其他平台一样,swr 和 cache 规则会使用 Nitro 内置缓存。
  • 查询参数。 设置 allowQuery 后,这些参数现在也会传递给处理器。
  • 路由行为与应用一致。 Vercel 路由配置使用 rou3 构建,因此按请求方法匹配的规则、仅匹配标头的规则和 redirect: false 例外都会在运行时按预期匹配。
  • 从 package.json 选择运行时。 函数运行时会像 Vercel 一样从 engines.node 或 engines.bun 读取。
  • waitUntil 和可观测性。 event.waitUntil() 可在 Node.js 运行时中使用,并且始终会生成可观测性路由。

阅读更多 →

#☁️ 本地 Cloudflare

Durable Objects、Workflows 和 RPC 服务绑定现在可在 nitro dev 和 vite dev 中使用,并支持热重载。请在 server.ts 中导出它们,并在 Wrangler 配置中声明:

server.ts
import { DurableObject } from "cloudflare:workers";

export class Counter extends DurableObject {
  async fetch() {
    const count = ((await this.ctx.storage.get<number>("count")) || 0) + 1;
    await this.ctx.storage.put("count", count);
    return Response.json({ count });
  }
}

export default { fetch() {} };

开发模式下也支持绑定和 waitUntil。cloudflare_durable 预设已合并到 cloudflare_module:添加 $DurableObject 绑定后,WebSocket 升级请求就会转发给共享的 Durable Object,并支持发布/订阅和休眠。

阅读更多 →

#🎁 更多更新

  • H3 v2 和 rou3 v1: Nitro 现在基于它们的稳定版本运行。
  • KV 存储: useStorage 现在是 nitro/kv 中的 useKV。旧名称仍可使用。
  • 缓存存储: 缓存处理器和函数现在拥有独立的 cache 存储。
  • 异步插件: definePlugin(async (nitroApp) => {}) 现在适用于所有运行时。
  • HTTP: 支持 QUERY 方法路由、带 Allow 标头的 405,以及由 GET 路由处理的 HEAD 请求。
  • 中间件: 现在也会在缓存路由上运行。
  • 更快的 Node.js: 全局 Response 使用 srvx 的 FastResponse。
  • 通过 URL 引用资源: 通过 new URL("./file.wasm", import.meta.url) 加载的文件会随构建输出。
  • tsconfig paths: 所有构建器在开发和生产环境中都会解析这些路径。
  • 平台路由: Vercel、Netlify、Cloudflare Pages 和 EdgeOne 配置使用 rou3,因此路由行为与应用一致。
  • 开发体验: Chrome DevTools 工作区、Unix 套接字、devServer.drain 以及 Vite 8 内置开发模式。
  • 其他更新: db0 追踪、prerender.ignoreStatusCodes,以及 nitro/builder 中的 startPreview()/deploy()。

完整变更列表请参阅更新日志。

#🏁 开始使用

Nitro 现在内置了 nitro create 命令,用于取代 create-nitro-app:

npx --min-release-age=0 nitro@latest create

Note

--min-release-age=0(npm)和 --config.minimum-release-age=0(pnpm)标志会跳过你配置的最低发布时间限制,因此可以在 RC 发布当天获取它。

选择一个模板:

  • Vite: 带前端的全栈应用。
  • Rolldown: 为生产环境打包的 API 服务器。
  • Runtime: 使用运行时模式且无需构建步骤的 API 服务器(实验性功能)。

#⬆️ 从测试版升级

大多数测试版应用无需修改即可升级。请先检查以下内容。

要求

  • Node.js >=22.22.0。
  • 将构建器(rolldown、rollup 或 vite)添加到 devDependencies。

行为变化

  • 缓存条目默认存储在内存中。设置 cache: { driver: "kv" } 可继续使用 KV 存储。
  • routes/docs/[...slug].ts 这样的捕获所有路由现在也会匹配 /docs。
  • 扫描文件名中的点分后缀必须是方法(.get)、环境(.dev)或已知文件扩展名(.xml、.json 等)。其他后缀(例如 routes/hello.world.ts)会导致构建失败。请重命名文件,或将后缀添加到 scanSuffixes。
  • 配置中的钩子会在预设钩子之后运行,而不是替换它们。
  • Node.js 预设会将 srvx FastResponse 用作全局 Response。设置 features: { fastResponse: false } 可禁用此行为。
  • 使用 rollup 和 rolldown 时,tsconfig paths 指向包名对应源文件的路径现在会将这些源文件打包。

重命名

之前之后
rollup:before / rollup:reload 钩子build:config / build:reload
experimental.vite.*vite.*
unenv 选项alias、inject、polyfills、builtinModules
cloudflare_durable 预设cloudflare_module
deno_deploy 预设deno_server
platform_sh 预设upsun
exports.cloudflare.ts / cloudflare.exports从 server.ts 导出
Vercel future.nativeSWRisr 路由规则

已移除

  • winterjs 预设。
  • netlify.images、vercel.regions、prerender.retry 和 prerender.retryDelay 选项。
  • cloudflare:email 和 cloudflare:queue 钩子中的 event 字段。

预设输出

  • Netlify 输出已移至 .netlify/v1。
  • Azure 默认使用 Functions v4 编程模型。
  • Cloudflare Pages 和 EdgeOne 不再为相对 redirect 目标添加 baseURL 前缀。

更多详情请参阅迁移指南。


欢迎试用 RC,并报告遇到的问题。正式版即将发布!🚀