Qwik City
基于 Qwik 可恢复执行模型,提供路由、数据加载和 Server Action 的全栈 Meta-framework。
项目概述
Qwik City 为 Qwik 应用加入文件路由、嵌套布局、Loader、Action、Endpoint、Middleware、SSR 与 SSG,并延续按需加载而非整页水合的性能模型。
Qwik City 是 Qwik 的官方 Meta-framework:Qwik 核心负责组件、状态和可恢复执行,Qwik City 则提供构建完整网站所需的路由、页面、布局、服务端数据与部署能力。它通过 src/routes 目录定义页面和 Endpoint,使用 routeLoader$ 在服务端读取数据,使用 routeAction$ 处理写操作与渐进增强表单,并通过层级 Middleware 统一认证、缓存和日志。Qwik 的 Resumability 会把服务端执行状态序列化到 HTML 中,让浏览器在用户交互时按需加载精确代码,而不是启动时重新执行整棵组件树。Qwik City 同时支持 SSR 与 SSG,并可通过适配器部署到 Node.js、Cloudflare、Netlify、Vercel 等环境。
主要特点
Qwik City 将 Qwik 的细粒度懒加载扩展到完整应用生命周期,覆盖路由、服务端数据、表单、API 和多平台部署。
可恢复执行
服务端将应用状态和事件连接序列化到 HTML,浏览器无需重新执行整棵组件树,即可在交互发生时恢复对应逻辑。
细粒度 JavaScript Streaming
组件与事件代码按符号拆分并根据可见性、悬停或真实交互按需获取,避免以路由 Bundle 为唯一加载边界。
文件系统路由
src/routes 中的目录、index.tsx、index.ts、layout.tsx、动态参数和 Catch-all 文件共同定义页面、Endpoint 与嵌套布局。
Route Loader
routeLoader$ 在服务端执行数据读取,并以响应式 Signal 形式把类型化结果交给页面组件,支持 SPA 与 MPA 导航。
Server Action 与表单
routeAction$ 和 Form 处理数据库写入、邮件等副作用;原生表单在无 JavaScript 时仍可提交,启用脚本后自动获得 SPA 体验。
验证与错误结果
zod$ 可在 Action 执行前验证 FormData 并推断 TypeScript 类型,fail() 用于返回可区分的业务失败结果。
Endpoint 与 Middleware
onGet、onPost 等 Handler 可输出 JSON、XML、Stream 或代理响应,层级 Middleware 用于认证、安全、缓存和日志。
多平台渲染与部署
支持动态 SSR 和静态生成,并通过部署适配器连接 Cloudflare、Netlify、Vercel、Node.js Server 等目标。
适用场景
适合重视首屏与交互启动性能、页面数量较多,并希望使用 TypeScript 同时构建 UI 和服务端逻辑的 Web 产品。
电商与商品目录
服务端输出商品和 SEO 内容,筛选、购物车及购买交互只加载所需代码,适合页面数量多的商业站点。
内容与文档网站
Markdown/MDX、嵌套布局、SSG 和按需导航适合文档、博客、媒体与营销内容。
SaaS 控制台
Loader 读取用户数据,Action 处理写操作,Middleware 统一 Session 与权限,可构建服务端优先的业务界面。
低端设备与弱网应用
可恢复执行减少初始 JavaScript 和启动工作,适合对移动网络、CPU 消耗及交互响应敏感的产品。
API 与 BFF
Endpoint、server$ 和环境无关的 RequestEvent 可实现 REST、GraphQL、反向代理和前端专用聚合接口。
多平台 SSR
通过适配器在不同 Serverless、Edge 或 Node 环境复用页面和服务端逻辑,并按页面选择 SSR 或 SSG。
优点与注意事项
技术选型不仅要看能力,也要理解它带来的团队成本。
主要优点
Qwik City 擅长的地方
- 可恢复执行避免传统整页水合,初始交互成本不必随应用组件数量线性增长
- 代码按事件和组件符号细粒度懒加载,不需要手工为每个交互设计 Bundle
- Loader、Action、Endpoint 和 Middleware 覆盖完整的全栈请求生命周期
- Form 基于原生 HTML 表单,可在无 JavaScript 时工作并渐进增强为 SPA 提交
- 文件路由、动态参数和嵌套布局适合组织大型内容与业务应用
- 同时支持 SSR、SSG 和多种部署适配器,交付形态较灵活
- 内置 Zod 集成让表单输入在服务端验证并获得类型推断
需要注意
采用前应考虑的问题
component$、QRL、$ 后缀和序列化闭包与 React/Vue 的常规执行方式不同,团队需要理解代码何时在服务端或浏览器运行。
事件与延迟加载函数跨越服务端和客户端边界,不能随意捕获连接、复杂 Class 或不可序列化对象。
Qwik 专用组件、教程、招聘与生产案例少于 React/Next.js;浏览器依赖较强的库可能需要封装或替代。
Action 和 Endpoint 可被直接请求,必须独立执行认证、对象级授权、CSRF 防护与运行时输入验证。
SSR、Loader、CDN 与用户个性化数据的缓存边界应结合部署平台设置,避免把私有响应缓存给其他用户。
不同 Node、Serverless 和 Edge 平台在流式响应、文件系统、环境变量和运行时间限制上并不完全一致。
Resumability 优化启动阶段,但真实体验仍受网络请求、数据库、图片、第三方脚本和交互后的代码获取影响。
快速开始
使用官方 CLI 创建 Qwik City 项目,并实现类型化 Loader、带 Zod 验证的 Action、渐进增强表单和 JSON Endpoint。
bashnpm create qwik@latest
cd qwik-app
npm install
npm starttypescriptimport { component$ } from "@builder.io/qwik";
import { routeLoader$ } from "@builder.io/qwik-city";
type Task = {
id: string;
title: string;
completed: boolean;
};
export const useTasks = routeLoader$<Task[]>(async () => {
// 这里可以安全访问数据库和服务端环境变量
return [
{
id: "1",
title: "学习 Qwik City",
completed: false,
},
];
});
export default component$(() => {
const tasks = useTasks();
return (
<main>
<h1>任务</h1>
<ul>
{tasks.value.map((task) => (
<li key={task.id}>{task.title}</li>
))}
</ul>
</main>
);
});typescriptimport { component$ } from "@builder.io/qwik";
import {
Form,
routeAction$,
z,
zod$,
} from "@builder.io/qwik-city";
export const useCreateTask = routeAction$(
async ({ title }) => {
const task = {
id: crypto.randomUUID(),
title,
completed: false,
};
// 在这里写入数据库
return { success: true, task };
},
zod$({
title: z.string().trim().min(1).max(120),
}),
);
export default component$(() => {
const action = useCreateTask();
return (
<Form action={action}>
<input name="title" required maxLength={120} />
<button type="submit">添加任务</button>
{action.value?.success && (
<p>已添加:{action.value.task.title}</p>
)}
</Form>
);
});typescriptimport type {
RequestHandler,
} from "@builder.io/qwik-city";
export const onGet: RequestHandler = ({ json }) => {
json(200, {
status: "ok",
timestamp: new Date().toISOString(),
});
};
export const onPost: RequestHandler = async ({
json,
parseBody,
}) => {
const input = await parseBody();
json(201, {
id: crypto.randomUUID(),
input,
});
};typescriptimport type {
RequestHandler,
} from "@builder.io/qwik-city";
export const onRequest: RequestHandler = async ({
headers,
next,
sharedMap,
}) => {
const requestId = crypto.randomUUID();
sharedMap.set("requestId", requestId);
await next();
headers.set("x-request-id", requestId);
};下一步:先理解 component$、事件处理器的 $ 后缀和可序列化边界;Loader 与 Action 中的认证、授权和数据库访问始终发生在服务端,不要只依赖客户端 UI 限制。
类似项目
这些 Meta-framework 同样提供服务端渲染、文件路由和全栈数据能力,但采用 Islands、Server Components 或不同的客户端激活策略。
Fresh
基于 Deno、Preact 与 Islands 架构,默认服务端渲染的全栈 Web 框架。
查看项目Next.js
基于 React 的全栈 Web 框架,覆盖渲染、路由和部署。
查看项目Astro
面向内容网站的 Web 框架,默认发送更少的客户端 JavaScript。
查看项目Svelte
将组件编译为精简 JavaScript 的现代 Web UI 框架。
查看项目Nuxt
基于 Vue 的全栈 Web 框架,统一路由、服务端渲染、数据获取与后端 API。
查看项目SvelteKit
Svelte 官方应用框架,提供文件路由、服务端渲染、数据加载和渐进增强表单。
查看项目Qwik City vs Fresh
Qwik City 与 Fresh 都试图减少传统整页水合带来的客户端成本,也都提供服务端路由、数据读取、表单和边缘部署。Qwik City 依靠 Resumability 恢复任意组件交互;Fresh 则默认输出服务端 HTML,只水合显式声明的 Preact Islands。
| 比较维度 | Qwik City | Fresh |
|---|---|---|
| 核心技术 | Qwik、QRL 与可恢复执行 | Deno、Preact、Signals 与 Islands |
| 客户端激活 | 按事件和符号恢复,无需整棵组件水合 | 只有显式 Island 在浏览器水合 |
| 交互边界 | 编译器细粒度拆分组件与事件代码 | 开发者通过 islands 目录明确划分边界 |
| 服务端数据 | routeLoader$、routeAction$、server$ | Handler、Middleware、page() 与标准表单 |
| 局部导航 | Qwik City SPA Router、Link 预取 | Partials 从服务器替换命名 HTML 区域 |
| 主要运行时 | Node 与多平台适配器,包括 Edge | Deno 优先,可部署 Workers、Docker 等 |
| 生态 | Qwik 专用生态,可集成 npm 与 Partytown | Preact、Deno、JSR 与兼容 npm 模块 |
| 更适合 | 交互较多但仍追求低启动成本的应用 | 内容和表单优先、交互岛屿边界清晰的网站 |
如果产品包含大量分散交互,希望框架自动把事件代码细粒度延迟到真正需要时,Qwik City 的 Resumability 更有吸引力;如果网站主要是服务端内容和表单,团队希望明确控制少量 Preact Island,并偏好 Deno 工具链,Fresh 更直观。两者的心智模型都不同于传统 SPA,应通过真实页面验证交互后加载、生态兼容与部署平台行为。
资料核验
版本、维护信息与本页采用的官方资料来源。
本次核验覆盖 Qwik City 的核心定位、主要能力、官方入口与开源许可。项目版本持续更新,具体补丁版本、兼容性和迁移要求请在采用前继续核对官方发布记录。
官方仓库未归档,核验时最近可见的代码活动日期为 2026 年 7 月 25 日。该状态表示项目近期仍有公开维护活动,不代表固定发布频率或长期支持承诺。