SvelteKit 服务端运行时统一配置:用 `builder.generateServerInstance` 取代 `Server` 类
2026/9/21 2:42:23 网站建设 项目流程

SvelteKit 服务端运行时统一配置:用builder.generateServerInstance取代Server

【免费下载链接】kitweb development, streamlined项目地址: https://gitcode.com/gh_mirrors/kit/kit

SvelteKit 在 3.0 系列中重构了服务端运行时(server runtime)的启动方式:将原本分散在适配器(adapter)各处的环境变量、manifest、静态资源读取等配置集中到统一的入口,并由builder.generateServerInstance在构建期生成可直接消费的server对象,取代此前需要手动new Server(manifest)Server类。本文结合当前仓库的源码实现,讲解这一新 API 的签名、生成物形态、底层configure机制,以及 Node、Bun 等官方适配器的迁移示例,帮助适配器作者与应用开发者理解并完成迁移。

背景:为什么要把服务端运行时配置"集中到一处"

在旧的设计中,SvelteKit 暴露了一个公开的Server类,适配器需要自己拿到 SSR manifest,然后手动完成一整套启动流程:

const { Server } = await import('@sveltejs/kit'); const server = new Server(manifest); await server.init({ env, read }); // 之后用 server.respond(request, options) 处理请求

这套流程存在两个问题:

  1. 启动配置散落在适配器代码里envread(读取静态资源的实现)、assetsbuildingprerenderingfix_stack_trace等运行时状态由每个适配器各自处理,难以统一演进。
  2. manifest 的获取依赖旧 API:构建期通过builder.generateManifest生成 manifest 字符串,再由适配器自行拼装启动代码,环节多、易出错。

当前仓库中的变更集(.changeset/server-boot-configure.md)对此的表述是:"在一个地方配置服务端运行时,弃用Server,改用builder.generateServerInstance写出的server对象"(chore: configure the server runtime in one place, deprecateServerin favour of theserverobject written bybuilder.generateServerInstance)。

这一变更把"配置运行时"这一职责收拢到框架内部,适配器只需要拿到一个已经配置好的server对象,调用initrespond即可。

核心 API:builder.generateServerInstance

新的构建期 API 是Builder上的generateServerInstance方法,实现在 packages/kit/src/core/adapt/builder.js:

generateServerInstance(dest, { routes: subset, serverDirectory } = {}) { const relative = relative_path( path.dirname(dest), serverDirectory ?? this.getServerDirectory() ); write( dest, dedent` import { create_server } from '${relative}/index.js'; const manifest = ${generate_manifest({ build_data, prerendered: prerendered.paths, relative_path: relative, routes: subset ? subset.map((route) => /** @type {import('types').RouteData} */ (lookup.get(route))) : route_data.filter((route) => prerender_map.get(route.id) !== true), remotes, root: vite_config.root })}; export const server = create_server(manifest); ` ); }

参数说明

  • dest(必填):生成文件的输出路径。官方适配器通常输出到builder.getServerDirectory()下的server.js(见后文)。
  • opts.routes(可选):路由子集,用于只把部分路由纳入生成的 manifest(例如 split 部署场景下每个部署单元只包含自己的路由)。未传时默认包含所有未被预渲染的路由:route_data.filter((route) => prerender_map.get(route.id) !== true)
  • opts.serverDirectory(可选):服务器代码所在目录,默认取builder.getServerDirectory()(即outDir/output/server)。

它在public.d.ts中的公开类型签名位于 packages/kit/src/exports/public.d.ts,标注为@since 3.0.0

生成物的形态

generateServerInstance会写入一个模块,它只做三件事:

  1. 从服务器目录的index.js导入create_server
  2. 构建期generate_manifest生成 SSR manifest 的静态代码;
  3. export const server = create_server(manifest),导出一个已绑定 manifest 的server对象。

也就是说,适配器最终拿到的是一个"开箱即用"的server,manifest 的拼装完全由框架在构建期完成,不再需要适配器在运行时自行加载 manifest。

create_serverconfigure:运行时配置的单一入口

生成的server对象来自create_server,定义在 packages/kit/src/runtime/server/index.js:

export function create_server(manifest) { let server; return { // adapters get to set `env` and `read`, nothing else init: async ({ env, read }) => { server = await configure({ manifest, env, read }); await server.init(); }, respond: (request, options) => server.respond(request, options) }; }

这里的设计意图非常明确:适配器能设置的只有envread,其他一律不许碰(源码注释原话:"adapters get to setenvandread, nothing else")。init内部把manifestenvread一起交给configure

configure:真正的统一配置点

configure位于同一文件 packages/kit/src/runtime/server/index.js,接受一个ServerConfigureOptions

export async function configure({ building, prerendering, manifest, read, assets, fix_stack_trace, env }) { if (building) set_building(); if (prerendering) set_prerendering(); if (manifest) set_manifest(manifest); if (read) set_read_implementation(read); if (assets !== undefined) set_assets(assets); if (fix_stack_trace) set_fix_stack_trace(fix_stack_trace); const instance = await import('./instance.js'); if (env) instance.set_env(env); return instance; }

它的行为是:

  • 把各类模块级运行时状态(buildingprerenderingmanifestreadassetsfix_stack_trace)写入对应的内部 setter(如set_manifestset_read_implementation定义于 packages/kit/src/runtime/server/internal.js);
  • 延迟导入instance.js,也就是所有会求值用户代码(包括 env 配置)的部分都放在这次 import 之后(源码注释:"Everything that evaluates user code, the env config included, sits behind this import"),确保状态先就绪;
  • 通过instance.set_env(env)注入环境变量,然后返回一个完整的运行时实例。

ServerInstance类型

configurecreate_server返回的实例类型是ServerInstance,定义在 packages/kit/src/types/internal.d.ts:

export interface ServerInstance { init(): Promise<void>; respond(request: Request, options: InternalRequestOptions): Promise<Response>; set_env(env: Record<string, string | undefined>): void; }

ServerConfigureOptions则位于同文件 packages/kit/src/types/internal.d.ts,是Partial<ServerInitOptions>并额外支持manifestassetsbuildingprerenderingfix_stack_trace等字段。生成的server/index.js的模块类型ServerModule(internal.d.ts)暴露configurecreate_serverformat_response

Server类的弃用与generateManifest的移除

Server类进入弃用状态

Server类仍然保留,但已被标注@deprecated,位于 packages/kit/src/runtime/server/index.js:

/** @deprecated use the `server` written by `builder.generateServerInstance`, or `configure` */ export class Server { #server; constructor(manifest) { this.#server = create_server(manifest); } init(opts) { return this.#server.init(opts); } respond(request, options) { return this.#server.respond(request, options); } }

从源码看,它现在只是对create_server(manifest)的薄封装,行为与新的server对象完全一致——这正是一个典型的"先内部收敛、再逐步移除"的弃用路径。

generateManifest已被移除

旧的builder.generateManifest在 3.0 中已经不可用,调用会直接抛出错误,见 packages/kit/src/core/adapt/builder.js:

generateManifest() { throw new Error( 'The `generateManifest` adapter API has been removed — use `generateServerInstance` or `builder.manifest` instead. You may need to update your adapter' ); }

同时,SSRManifestServer构造函数也已从公开类型中移除(见 packages/kit/CHANGELOG.md 中 3.0.0-next.27 的 breaking 记录:"removeServerconstructor andSSRManifestfrom public types"、"replace thebuilder.generateManifestwithbuilder.generateServerInstanceandbuilder.manifest")。generateManifest的公开类型声明上也标注了@deprecated removed in 3.0(public.d.ts)。

官方适配器中的实际用法

adapter-node

@sveltejs/adapter-nodeadapt()中调用generateServerInstance,见 packages/adapter-node/index.js:

const server = builder.getServerDirectory(); builder.generateServerInstance(`${server}/server.js`);

即把生成的模块写到output/server/server.js,随后随服务器代码一起拷贝到输出目录。运行时,适配器的处理器(packages/adapter-node/src/handler.js)这样使用它:

import { server, dir, base, ... } from '#@sveltejs/adapter-node'; await server.init({ env: process.env, read: (file) => createReadableStream(`${asset_dir}/${file}`) });

然后对每个请求调用server.respond(request, { platform, getClientAddress })(handler.js)。注意适配器层只负责传入envread,完全符合上文create_server注释中"adapters get to setenvandread, nothing else"的约束。

adapter-bun

@sveltejs/adapter-bun的用法与 Node 版对称,见 packages/adapter-bun/index.js:

const server = builder.getServerDirectory(); builder.generateServerInstance(`${server}/server.js`);

测试与类型验证

仓库中仍有旧式用法的测试遗留(例如 packages/kit/test/apps/basics/test/vitest/server.spec.js 使用new Server(manifest),packages/adapter-bun/test/handler.spec.ts 的 mock 也构造new Server()),它们对应弃用前的行为;新适配器代码则应统一改为generateServerInstance产出的server

迁移指南

如果你是适配器作者

  1. 移除generateManifest调用:它在 3.0 中会抛错;如需路由子集,改传给generateServerInstance(dest, { routes })
  2. generateServerInstance生成启动模块:输出到服务器目录(builder.getServerDirectory())下,例如server/server.js
  3. 消费server对象await server.init({ env, read })后,用server.respond(request, options)处理请求;不要再new Server(manifest),也不要直接引用公开的SSRManifest类型。
  4. 如需手动配置:也可以直接使用生成的模块中导出的configure(options)(类型见ServerModule),它是全部运行时状态的唯一注入点。

如果你只是应用开发者

通常你无需改动业务代码:这些变化发生在适配器层。只要使用支持 3.0 的官方适配器(Node、Bun 等)重新构建应用,server对象的生成与启动就会自动切换到新机制。

小结

本次变更的核心是把 SvelteKit 服务端运行时的配置动作收敛到框架内部:

  • 构建期builder.generateServerInstance在构建时生成包含完整 manifest 的server模块,取代旧generateManifest+new Server(manifest)的组合;
  • 运行时create_serverconfigure成为唯一配置入口,适配器只能注入envread,其余状态由框架统一管理;
  • 兼容期Server类被标记弃用并退化为create_server的薄封装,为后续彻底移除留出过渡空间。

对适配器生态而言,这意味着更少的样板代码、更一致的行为,以及更小的出错面——这正是"在同一个地方配置服务端运行时"这一变更的价值所在。

【免费下载链接】kitweb development, streamlined项目地址: https://gitcode.com/gh_mirrors/kit/kit

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询