Skip to content

필사 모드: 解读 SvelteKit 3.0 预发布版 — 会破坏什么、收紧了哪些默认值,以及还有哪些仍是 experimental

中文
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.

引言 — 没有发布公告,先悄悄上了 npm

svelte.dev 博客上还没有出现过「介绍 SvelteKit 3」这样的文章。但 npm 注册表上的痕迹已经很清楚了 —— @sveltejs/kit3.0.0-next.0在 2026 年 6 月 5 日上线,截至本文撰写时(2026-07-17),最新的预发布版本是 7 月 14 日的3.0.0-next.8。不到六周的时间里出了九个预发布版本,和稳定版2.69.3(7 月 13 日)并行沿着两条轨道发布。

仓库那边的证据也指向同一个方向。sveltejs/kit开着一个version-3分支,3.0 里程碑截至今天显示已关闭 107 个 issue、还有 27 个未关闭。正式发布日期尚未公布 —— 所以本文的内容也应当被当作「next.8 时刻的快照」来读。既然是预发布版,从现在起还可能继续变化。

但把version-3分支的更新日志从 next.0 通读到 next.8,有一件事会变得很清楚:这个大版本里几乎没有新功能。取而代之的是清偿两年积累下来的废弃预告、拉高工具链的地基、收紧默认值。而社区期待中理应作为 SvelteKit 3 门面的那些东西 —— remote functions、组件内的await —— 在 v3 预发布版里依然是 experimental。理解这个格局,就理解了迁移判断的一半。

时间线 — 先看看 2.x 已经跑到了哪里

要读懂 v3,得先了解 2.x 后期的脉络。以下日期均以 npm 注册表上的发布时刻为准。

2024-12-16  kit 2.12   新增 $app/state(基于 rune —— $app/stores 的继任者)
2025-07-14  svelte 5.36  组件 await(experimental.async 标记)
2025-07-24  kit 2.26   $app/paths 新增 resolve()/asset()(取代旧的 base/assets)
2025-07-31  kit 2.27   remote functions(experimental 标记)
2026-01-22  svelte 5.48  ← 后来成为 kit v3 最低 Svelte 版本要求的那个发行版
2026-05-01  kit 2.59   新增 query.live(experimental)
2026-05-22  kit 2.61   query.live 改为异步可迭代对象,移除查询的 .run()(破坏性变更)
2026-06-02  kit 2.62   无需 svelte.config.js 即可向 Vite 插件传递配置
2026-06-04  kit 2.63   显式环境变量(experimental)
2026-06-05  kit 3.0.0-next.0  ← 预发布开始
2026-07-14  kit 3.0.0-next.8  ← 当前

有两点值得留意。第一,2.62 和 2.63 是 v3 发布前的「预告片」 —— 用7 月摘要的说法,把配置迁到vite.config和显式环境变量,二者都是作为「Kit 3 会这样做的预览」先落地到 2.x 里的。第二,正如 2.61 所展示的那样,带有 experimental 标签的功能即便在小版本发布里也在持续发生破坏性变更。移除.run()、修改requested(...)的签名,这类改动是以 semver 小版本的形式发布出来的 —— 一旦打开了这个标记,你就进入了 semver 保护不到的地带。

v3 拉高的地基 — 运行时与工具链的最低要求

以下是next.0 的更新日志钉死的最低要求。

  • Node 22 及以上(#12548)
  • TypeScript 6 及以上(#15930) —— npm 上已有 6.0.2、6.0.3 的稳定版,在此之上TypeScript 7.0 也已经 GA(7.0.2,2026-07-08)。顺带一提,svelte-check 4.7.0 已经把对 tsgo(原生 TS)的支持作为 experimental 收了进来。
  • Vite 8 —— 最初的要求只是 Vite 8(#15371),到 next.5 才收紧为vite@^8.0.12。照更新日志原话搬过来,是因为这是「第一个内置了稳定版 rolldown 1.0.0 的 Vite 8 发行版」(#16134)。用 npm 上的日期交叉核对:rolldown 1.0.0 是 2026-05-07 发布的,vite 8.0.12 是 2026-05-11 —— 相差四天,正好咬合在一起。也就是说,SvelteKit 3 只能跑在这个 Rust 打包器之上。
  • @sveltejs/vite-plugin-svelte 7(#15371)
  • Svelte 5.48.0 及以上 —— 这一点很重要。不是 Svelte 6。 5.48 是 2026 年 1 月发布的一个普通小版本。v3 并没有和 Svelte 的世代更替绑在一起。

更新日志给 Vite 8 要求列出的理由是「通过 Vite hook filter 实现更快的构建,以及使用 Vite environment API 的更强适配器」 —— 具体的构建时间数字目前没有任何公开数据,所以这里只记录这是项目自己的说法。

被删除的 API —— 清偿两年积累的废弃预告

以下是在 v3 中被移除或改名的东西。它们无一例外都是继任 API 早已在 2.x 里先落地的情况,所以几乎不存在「突然删除」这回事。

消失的东西继任者继任者落地的时间
整个$app/stores模块(#15499)$app/statekit 2.12(2024-12)
$app/paths里的baseassetsresolveRoute(#15507)resolve()asset()kit 2.26(2025-07)
invalidateAll(deprecated)(#16289)refreshAll(goto的选项里也适用)v3 next.8 新增
$app/environment改名为$app/env(别名保留,next.1)v3
$env/*四个模块显式环境变量($app/env/private$app/env/public)kit 2.63(experimental)
必须有svelte.config.js把配置传给 Vite 插件(#16007)kit 2.62 起可用
文件夹里的 param 文件单一的params.js/ts文件(#16189)v3
preloadStrategy选项恒为modulepreload + output.linkHeaderPreloadv3
CSRF 的checkOrigintrustedOrigins在 kit 2.x 里已经 deprecated
@sveltejs/kit/node/polyfills、给适配器用的createEntries无(移除)

有几点值得说明。

$app/stores的移除,是 rune 迁移画上的句号。Svelte 5 的 rune把 store 挤出局已经很久了,但 SvelteKit 的pagenavigatingupdated这几个 store,出于向后兼容一直被留着。继任者$app/state落地至今已经一年半,作为一次清偿,这个时机算是比较温和的。

invalidateAllrefreshAll 是一次词汇统一。读一读PR #16289就能看出意图 —— 在 remote functions 的世界里,刷新数据用的是query.refresh(),而这和 load 函数世界里「使无效」(invalidation)的说法已经分裂开来。refreshAll就是把这两者收拢到一个词下面的名字,顺带也把「让 load 函数总是重新执行」的选项一起整理了。需要留意的一点:refreshAll在 2.69.3 里并不存在。这是升级到 v3 时才要做的切换,不是今天就能做的事。

环境变量从模块魔法走向显式声明。文档的预告措辞很明确 —— 显式环境变量会成为 v3 的默认方式,而$env/*模块和$app/environment会被移除。新方式在src/env.ts里声明。

// src/env.ts —— 在 kit 2.63+ 上可以通过 experimental.explicitEnvironmentVariables 提前试用
import { defineEnvVars } from '@sveltejs/kit/hooks';

export const variables = defineEnvVars({
	API_KEY: {}, // 默认是 private —— 只能从 $app/env/private 导入
});

如果说过去$env/static/private是一个「靠导入位置来强制是否暴露」的巧妙机制,那么新方式则是把应用里存在的环境变量清单本身,连同类型一起,钉死在一个文件里。「光看代码看不出到底有哪些变量」这个问题消失了,但代价是每多一个变量,声明就要多一行。

悄悄改变的默认值 —— 安全方面居多

比起删除,这些改动更安静,但确实会改变行为。迁移里最耗时间的,通常就是这一类。

  • 外部重定向默认被禁止(#16198)。要redirect到外部 URL(以及javascript: URL),现在必须显式传入external选项。如果你有登录后按?next=参数重定向的代码 —— 这正是 open redirect 的常见落脚点 —— 在 v3 里原样保留就会破坏。破坏本身就是意图所在。
  • cookie 的默认path变成'/'(#15398)。此前是以当前路径为基准的,这也正是「设置了 cookie,换个页面却看不到」这类常见提问的根源。采用 cookie v1 后,cookie 名称也被限制为 ASCII(#13386)。
  • form action 失败时,会用fail()里携带的 HTTP 状态码作为真正的响应状态码(#16200)。以前这些信息是搭在成功的 200 上返回的,这一点会发生变化,所以如果你有依据状态码来动作的代理或监控,会受到影响。204 响应现在真的会不带 body 发出去。
  • handleError将能够影响响应状态码(#16162)。
  • goto在遇到无法解析为应用路由的 URL 时会 reject(#16164) —— 这让它和外部 URL 上早已如此的行为保持一致。
  • 导航过程中调用invalidate不再会中断导航(#16188)。

顺带一提,强制在 remote functions 的响应上加cache-control: private, no-store、让个性化的查询结果不会残留在共享缓存里的这个修复,其实不是 v3 才有的 —— 它已经在 2.65.2 里落地了。收紧安全相关默认值并不是 v3 独有的主题,而是最近这几个月一贯的方向。

依然是 experimental 的东西 —— v3 不是功能型大版本

这是本文里最重要的一节。

Remote functions 在 v3 里依然是 experimental。官方文档现在仍然写着「currently experimental… subject to change without notice」,并且要求kit.experimental.remoteFunctionscompilerOptions.experimental.async这两个标记同时打开。更能说明问题的是 v3 预发布版的方向 —— next.7 反而禁止了在不打开标记的情况下放置*.remote.ts/js文件(#16247,2026-07-07 合并)。如果稳定化已迫在眉睫,是不会出现这种改动的。从 2025 年 7 月以 2.27 发布至今将近一年,即便跨过了 v3 这个大版本,remote functions 依然没有 API 稳定性的承诺。

组件await也是同样的故事。 从 Svelte 5.36(2025-07-14)起,它就一直靠experimental.async标记才能使用,而文档明确写出了这个标记会在什么时候移除 —— "The experimental flag will be removed in Svelte 6."。而 Svelte 6 目前并不存在于 npm 上 —— 6.x 无论是正式版还是预发布版都从未发布过,svelte 的latest是 5.56.6(2026-07-16)。kit v3 的最低要求是 Svelte 5.48,这一点本身就概括了这个格局:SvelteKit 的大版本和 Svelte 的大版本,是两列各走各的火车。 编译器那边的 experimental 名单里,fork API(5.42)和 async SSR(5.39)也依然留在原地。

也有一次方向相反的「毕业」 —— OpenTelemetry 追踪在 next.7 里走出了 experimental 命名空间,成为正式 API(#16260)。

归纳一下,v3 的真实面貌是这样的:所有带话题性的功能都停留在 experimental 轨道上,同时搭载在 2.x 和 v3 里发布,而大版本号则被用来更换其下方的地基 —— 运行时、打包器、命名、默认值。「升到 v3,remote functions 就会稳定」这个期待,从目前的证据来看是站不住脚的。

与邻居的对照 —— 大版本在做的事情不一样

同一周里搅动 React 生态的新闻是React Compiler 的 Rust 移植,拿来对照挺有意思。React 正在为了消除手动 memoization 而从头搭建编译器基础设施 —— 而且还处在实验性的 WIP 阶段 —— 而 Svelte 从一开始编译器就是框架本身,没有这个阶段要走。取而代之的是,Svelte 这边的大版本被用来拉高打包器(rolldown)和运行时的地基。2026 年,这两个框架有一个共同点:把大版本级别的精力花在基础工程上,而不是「新功能大放送」,而且都不会在短期内大幅改变应用开发者的代码。

那么,现在该做什么

今天在 2.x 上就能提前做的事 —— 这些全都是对 v3 迁移的预付款。

  • $app/stores的导入迁移到$app/state。这是个用了一年半的 API,参考资料很充分。
  • $app/pathsbaseassets的字符串拼接改成resolve()asset()
  • 尝试把配置迁到vite.config的插件选项里(2.62+)。如果是新项目,sv CLI 0.16 已经是这样脚手架的。
  • 先升级到 Node 22、Vite 8、vite-plugin-svelte 7 试试 —— 这是不需要 v3 就能现在做的验证。
  • 摸清invalidateAll的使用位置。真正切换要等 v3,但知道用在哪儿,现在就能做。

不应该做的事。

  • 3.0.0-next.*用在生产环境。预发布版一路到 next.8,破坏性变更一直没停($app/stores的移除在 next.7,refreshAll是在 next.8 才出现的)。
  • 把 remote functions 当成稳定 API,在此之上立团队标准或公开库。没人能保证不会再发生一次像 2.61 移除.run()那样的事 —— 这正是 experimental 的定义。
  • 以「等 Svelte 6 出了再一起做」为由推迟 v3 的准备。正如上文所见,这两个大版本是分开的,等待的对象本来就不是同一个。

如果你是适配器或库的作者,要做的事情更多。createEntries没了,适配器将能够直接提供 Vite 插件(#16206),适配器体系也会围绕 Vite environment API 重新组织。相比应用代码,这一层生态更有可能是 v3 发布时真正的瓶颈所在。

结语

SvelteKit 3.0 预发布版的更新日志并不炫目。我认为这是个好信号。它不是那种要求你重新学习的大版本 —— 路由变了、数据加载模型变了那种 —— 而是一个履行废弃预告、拉高地基、收紧默认值的大版本。你不需要重新学 rune,也不需要重写 load 函数。

但期望值需要摆得非常准。remote functions 和组件await「转正」这件事,不会发生在 SvelteKit 3 上 —— 前者还没有时间表,后者按文档说是 Svelte 6 才会发生的事。把 v3 理解为「铺设那个未来所要立足的地基」(基于 rolldown 的 Vite 8、Node 22、清理干净的 API 表面)的一次发布,是和更新日志相吻合的读法。由于预发布仍在进行中,正式发布时本文的一些细节可能已经变化 —— 这是一份写在前提下的快照,前提是届时还会再核实一次。

参考资料

현재 단락 (1/86)

svelte.dev 博客上还没有出现过「介绍 SvelteKit 3」这样的文章。但 npm 注册表上的痕迹已经很清楚了 —— [`@sveltejs/kit`](https://www.npmjs...

작성 글자: 0원문 글자: 9,822작성 단락: 0/86