- 后端
- Web框架
- SSR
【免费下载链接】vinext
Vite plugin that reimplements the Next.js API surface — deploy anywhere
导读
examples/app-router-cloudflare是 vinext 仓库中一个最小化的实战示例,演示了如何让一套标准的 Next.js App Router 应用(包含服务端组件、客户端组件、动态路由与 API 路由处理器)通过 vinext 构建并直接跑在 Cloudflare Workers 上。本文以该示例为骨架,完整讲解本地开发、生产构建与预览的完整命令流程,并深入到vite.config.ts、wrangler.jsonc、Worker 入口、Middleware 与instrumentation.ts等关键文件的实现细节,让你既能照抄示例快速跑通,也能理解 vinext + Cloudflare 集成背后的原理,最终掌握把 App Router 应用"部署到任意平台"的能力。
示例概览:一个最小的 App Router on Workers
仓库中的 examples/app-router-cloudflare/README.md 只用了寥寥数行便勾勒出该示例的定位:
A minimal example of a Next.js App Router application running on Cloudflare Workers via vinext. Demonstrates server components, client components, dynamic routes, and API route handlers.
也就是说,这个示例刻意保持"最小",但它覆盖了 App Router 最具代表性的四类能力。从目录结构看,examples/app-router-cloudflare/app 下确实一一对应:
- 服务端组件(Server Components):根页面 app/page.tsx 是默认服务端渲染的页面,直接在组件内调用
new Date().toISOString()输出渲染时间戳,并在 app/layout.tsx 中定义了标准的<html lang="en">根布局; - 客户端组件(Client Components):app/components/counter.tsx 以
"use client"指令声明,使用useState实现一个计数器,演示了客户端交互逻辑在 Workers 环境下如何与 RSC 服务端渲染共存; - 动态路由(Dynamic Routes):app/blog/[slug]/page.tsx 使用
generateStaticParams预生成hello-world与getting-started两个静态 slug,并采用异步params: Promise<{ slug: string }>的写法解析路径参数——这正是 Next.js 15+ 中动态路由参数的官方形态; - API 路由处理器(API Route Handlers):app/api/hello/route.ts 导出一个异步
GET(),返回Response.json(...),并通过globalThis.navigator.userAgent探测运行时环境,验证请求确实由 Worker 运行时处理。
除此之外,示例还额外覆盖了 Server Actions 的 revalidate(app/action-revalidate)、并行路由与插槽(app/layout-identity/@aside)、拦截路由(app/optimistic-search-navigation/@modal)、Web Worker(app/echo.worker.ts)以及 WASM 模块导入(app/api/wasm)等进阶场景——如果你希望测试 vinext 在复杂 App Router 特性下的表现,这是一个非常好的实验场。
本地运行:一条龙命令流
原文档给出的运行流程非常精简,全部围绕 examples/app-router-cloudflare/package.json 中定义的三个脚本展开:
"scripts": { "dev": "vp dev", "build": "vp build", "preview": "vp preview" }可以看到,这里的命令统一通过vp(vite-plus 的 CLI,声明在 devDependencies 中)来驱动,而vinext、@vinext/cloudflare、@cloudflare/vite-plugin与wrangler都作为运行时依赖参与构建。
1. 安装依赖
pnpm install仓库根目录使用 pnpm workspace 管理(参见根目录 pnpm-workspace.yaml),vinext与@vinext/cloudflare都以workspace:*协议引用,因此直接执行pnpm install即可将本仓库内的 vinext 源码链接进示例,无需发布到 npm。
2. 启动开发服务器
pnpm dev即vp dev。此命令会拉起 Vite 开发服务器,并借助@cloudflare/vite-plugin在miniflare中模拟 Cloudflare Workers 运行时环境,让服务端代码(RSC 渲染、API 路由、Middleware)在尽可能接近生产的工作者沙箱里运行,而不是普通的 Node 进程。这意味着你在本地开发阶段就能捕获到诸如nodejs_compat兼容性、Worker 绑定(binding)访问等真实部署才会暴露的问题。
3. 生产构建
pnpm build即vp build。该命令会按照vite.config.ts中的配置构建所有 Vite 环境(worker 入口、RSC 环境、SSR 子环境等),产出可直接上传到 Cloudflare 的 Worker bundle。
4. 预览生产构建
pnpm preview即vp preview,用于在本地对生产构建产物进行预览验证,行为与线上部署尽可能一致,是"先预览、再上线"这一稳妥流程的关键一环。
关键配置逐行解读
vite.config.ts:vinext 与 Cloudflare 插件如何协作
examples/app-router-cloudflare/vite.config.ts 是这个示例的"心脏",完整展示了 vinext 与 Cloudflare 集成时的标准配置形态:
import { defineConfig } from "vite"; import vinext from "vinext"; import { cloudflare } from "@cloudflare/vite-plugin"; import { imagesOptimizer } from "@vinext/cloudflare/images/images-optimizer"; import { responseStoreAdapter } from "@vinext/cloudflare/cache/response-store-adapter"; import path from "node:path"; const responseStoreE2e = process.env.VINEXT_RESPONSE_STORE_E2E === "1"; export default defineConfig({ plugins: [ vinext({ cache: responseStoreE2e ? responseStoreAdapter({ mode: "self-contained" }) : undefined, images: { optimizer: imagesOptimizer() }, }), cloudflare({ configPath: responseStoreE2e ? "./wrangler.response-store.jsonc" : undefined, // The worker entry runs in the RSC environment, with SSR as a child. viteEnvironment: { name: "rsc", childEnvironments: ["ssr"], }, }), ], resolve: { alias: { "@test/og-font": path.resolve( import.meta.dirname, "../../tests/fixtures/og-font-package/lib", ), }, }, });其中值得注意的几个点:
vinext({ images: { optimizer: imagesOptimizer() } }):启用来自@vinext/cloudflare的图像优化器。配合wrangler.jsonc中的imagesbinding,next/image组件可以在边缘完成缩放、格式协商(AVIF/WebP)与质量变换。vinext({ cache: ... }):缓存适配器是可选配置。示例通过环境变量VINEXT_RESPONSE_STORE_E2E控制是否切换到 response-store 缓存适配器(对应 wrangler.response-store.jsonc 这份独立配置),默认情况下不启用,保持最小化。cloudflare({ viteEnvironment: { name: "rsc", childEnvironments: ["ssr"] } }):这一行定义了 Worker 入口运行在 RSC 环境中,并以 SSR 作为其子环境。注释明确写道 "The worker entry runs in the RSC environment, with SSR as a child",这是 vinext 将 App Router 的 RSC 渲染管线嵌入 Cloudflare Worker 的关键结构。resolve.alias:示例把@test/og-font指向仓库测试夹具(tests/fixtures/og-font-package/lib),用于 OG 图片生成的字体测试,属于示例自身的测试辅助配置。
wrangler.jsonc:Worker 的运行时契约
wrangler.jsonc 定义了部署到 Cloudflare 时的 Worker 配置:
{ "$schema": "node_modules/wrangler/config-schema.json", "name": "app-router-cloudflare", "compatibility_date": "2026-02-12", "compatibility_flags": ["nodejs_compat"], "main": "./worker/index.ts", "preview_urls": true, "assets": { "not_found_handling": "none", "binding": "ASSETS" }, "images": { "binding": "IMAGES" } }compatibility_flags: ["nodejs_compat"]:启用 Node.js 兼容层,使依赖 Node API 的应用代码(例如某些使用node:path、node:buffer的库)能够在 Workers 上运行——这是许多 Next.js 应用能跑起来的前提。assets.binding: "ASSETS":把静态资源以env.ASSETS的形式暴露给 Worker,注释说明这是为了让图像优化处理器能够以编程方式获取源图。images.binding: "IMAGES":Cloudflare Images binding,用于next/image的边缘图像优化。注释特别指出"无需用户额外设置——wrangler 会自动创建该 binding"。
worker/index.ts:极简的 Worker 入口
示例的 Worker 入口极其简洁,worker/index.ts 的全部逻辑就是代理给 vinext 的 fetch handler:
/** Cloudflare Worker entry point that delegates to vinext. */ import handler from "vinext/server/fetch-handler"; interface Env { ASSETS: Fetcher; } export default { fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> { return handler.fetch(request, env, ctx); }, };从源码结构看,vinext 以vinext/server/fetch-handler的形式导出了标准 Workers fetch handler,应用的整个 App Router 管线(路由匹配、RSC 渲染、API 路由、Server Actions)都被封装在这个 handler 内部。你只需要在自己的 Worker 里调用handler.fetch(request, env, ctx)并原样透传env与ctx,即可获得完整的 Next.js 运行时语义。
中间件(Middleware)在 Workers 上的真实表现
examples/app-router-cloudflare/middleware.ts 演示了next/server的NextRequest/NextResponseAPI 在 Workers 环境下的使用方式:
import { NextRequest, NextResponse } from "next/server"; export function middleware(request: NextRequest) { if (request.nextUrl.pathname === "/admin") { return new Response("Blocked by middleware", { status: 403 }); } if (request.nextUrl.pathname === "/_next/static/middleware-rewrite.js") { return new Response("rewritten missing asset", { headers: { "content-type": "text/plain" }, }); } const response = NextResponse.next(); if (request.nextUrl.searchParams.has("csp-nonce")) { response.headers.set( "content-security-policy", "script-src 'nonce-vinext-test-nonce' 'strict-dynamic';", ); } response.headers.set("x-mw-ran", "true"); return response; } export const config = { matcher: ["/api/:path*", "/", "/admin", "/_next/static/middleware-rewrite.js"], };这段中间件覆盖了三个典型场景:
- 路径拦截:直接对
/admin返回 403,验证中间件在请求进入页面渲染前生效; - 静态资源兜底:对缺失的静态资源返回自定义响应,测试资源请求的中间件匹配;
- 响应头注入:通过
NextResponse.next()继续传递请求,同时按查询参数注入 CSP 响应头(配合nonce测试)并统一添加x-mw-ran标记头。
config.matcher使用 Next.js 标准的路径匹配语法。这一文件也印证了:vinext 在 Cloudflare Workers 上完整实现了next/server的中间件 API,开发者现有的中间件代码可以近乎零改动地迁移。
可观测性与 instrumentation
examples/app-router-cloudflare/instrumentation.ts 展示了instrumentation.ts特性在@cloudflare/vite-plugin下的新工作机制。其文件注释描述得非常清楚:
- 生成的 RSC 入口会在导入应用模块之前await 缓存化的请求期 initializer 所返回的
register(); - 因此在
@cloudflare/vite-plugin存在时,register()运行在Cloudflare Worker 子进程(miniflare)内部,与 API 路由处于同一进程;当单独使用@vitejs/plugin-rsc时则运行在 RSC Vite 环境中; - 两种情况下都保证了"注册先于用户模块与请求处理完成",保留了 Next.js 的原始语义;
- 由于
register()与 API 路由共享同一个 Worker 模块图,instrumentation-state.ts 中的普通模块级变量可以直接在两者之间共享,无需临时文件桥接或globalThis技巧。
实现上,该文件通过@vercel/otel的registerOTel注册 OpenTelemetry,安装了一个自定义 span processor 用于记录 span 信息,并实现onRequestError钩子把请求错误(路径、方法、路由类型等)写入共享状态。仓库中对应有 instrumentation-state.ts 用于承接这些记录。
关于部署到 Cloudflare 的官方指南
本示例聚焦本地运行,而完整的部署流程在仓库文档 docs/deploying/cloudflare.mdx 中有系统说明,其中与示例相关的要点包括:
- 初始化:运行
pnpm dlx vinext init --platform=cloudflare(或对应的npx/yarn dlx/bunx/vpx形式),初始化器会创建或更新vite.config.ts与wrangler.jsonc,并引导你选择缓存与图像优化方案——本示例的手写配置与该流程生成的结果形态一致; - 认证:
pnpm dlx wrangler login进行浏览器登录,在 CI 场景则使用CLOUDFLARE_API_TOKEN环境变量; - 部署:
pnpm dlx @vinext/cloudflare deploy,支持--env staging指定环境、--preview部署到预览环境;部署命令会校验初始化配置、构建所有 Vite 环境并上传 Worker; - Workers bindings:在 Server Components、Route Handlers 与 Server Actions 中可以直接
import { env } from "cloudflare:workers"来访问各类 binding(如env.DB.prepare(...)操作 D1 数据库),binding 本身按 Wrangler 的常规方式在wrangler.jsonc中配置。
小结
通过 examples/app-router-cloudflare 这个最小示例,你可以完整看到"Next.js App Router 应用运行在 Cloudflare Workers 上"的全部要素:一条龙本地命令(pnpm install→pnpm dev→pnpm build→pnpm preview)、vinext 与@cloudflare/vite-plugin的配置协作、Worker 入口对vinext/server/fetch-handler的委托、Middleware 的完整实现,以及基于 miniflare 的 instrumentation 运行模型。如果你想进一步验证更复杂的能力(Server Actions 重验证、并行/拦截路由、WASM 模块、图像优化与 OG 图片生成),这个示例目录本身就是一座现成的测试矿藏——克隆仓库后按上述命令即可一键跑通。
- 后端
- Web框架
- SSR
【免费下载链接】vinext
Vite plugin that reimplements the Next.js API surface — deploy anywhere
相关推荐
Vike 官方示例实战:在 Cloudflare Workers 上运行 React SSR 应用
Vike 官方示例实战:在 Cloudflare Workers 上运行 React SSR 应用 本篇指南基于 Vike 仓库中的官方示例 examples/
前端后端Web框架SSR5分钟快速上手Fan Control:Windows电脑风扇控制的终极解决方案
5分钟快速上手Fan Control:Windows电脑风扇控制的终极解决方案 Fan Control是一款专为Windows系统设计的免费风扇控制软件,让你完
后端AI Agent人工智能流程编排WebSocketworkerd 入门实战:用 Hello World 示例理解 Cloudflare Workers 运行时配置
workerd 入门实战:用 Hello World 示例理解 Cloudflare Workers 运行时配置 本篇指南以仓库中的 samples/hello
后端语言运行时WebAssembly
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考