升级从 SvelteKit 版本 1 到版本 2 应该大部分是无缝的。有一些需要注意的重大更改,列在这里。您可以使用 `npx sv migrate sveltekit-2` 自动迁移其中的一些更改。 强烈建议在升级到 2.0 版本之前先升级到最新的 1.x 版本,以便您能够利用有针对性的弃用警告。我们还建议首先[更新到 Svelte 4](../svelte/v4-migration-guide):SvelteKit 1.x 的后续版本支持它,而 SvelteKit 2.0 则要求必须使用它。 ## `redirect` 和 `error` 已不再由您抛出 之前,您必须自己 `抛出` 由 `error(...)` 和 `redirect(...)` 返回的值。在 SvelteKit 2 中,这种情况不再存在——调用函数就足够了。 ```js import { error } from '@sveltejs/kit' // ... ---throw error(500, 'something went wrong');--- +++error(500, 'something went wrong');+++ ``` `سوفت-مهاجرت`将为您自动执行这些更改。 如果错误或重定向在`try {...}`块内部抛出(提示:不要这样做!),您可以使用从`@sveltejs/kit`导入的`isHttpError`和`isRedirect`来区分它们与意外错误。 ## 路径设置 cookie 时是必需的 当接收到未指定 `path` 的 `Set-Cookie` 标头时,浏览器会将 cookie 路径设置为所涉及资源的父路径。这种行为并不特别有用或直观,并且经常导致错误,因为开发者原本期望 cookie 应用于整个域名。 截至 SvelteKit 2.0,调用`cookies.set(...)`、`cookies.delete(...)`或`cookies.serialize(...)`时,您需要设置一个`path`,以便没有歧义。大多数情况下,您可能想使用`path: '/'`,但您可以将其设置为任何您喜欢的路径,包括相对路径——`''`表示'当前路径',`'.'`表示'当前目录'。 ```js /** @type {import('./$types').PageServerLoad} */ export function load({ cookies }) { cookies.set(name, value, +++{ path: '/' }+++); return { response } } ``` `سلتو-مigrate` 将添加注释以突出需要调整的位置。 ## 顶级承诺不再等待 在 SvelteKit 版本 1 中,如果从`load`函数返回的对象的顶级属性是 promises,它们会自动等待。随着[流式传输的引入,这种行为变得有些尴尬,因为它迫使你将流式数据嵌套在一层之内。](/blog/streaming-snapshots-sveltekit) 截至版本 2,SvelteKit 不再区分顶层和非顶层承诺。要恢复阻塞行为,请使用`await`(在适当的情况下,使用`Promise.all`以防止瀑布效果): ```js // @filename: ambient.d.ts declare const url: string; // @filename: index.js // ---cut--- // If you have a single promise /** @type {import('./$types').PageServerLoad} */ export +++async+++ function load({ fetch }) { const response = +++await+++ fetch(url).then(r => r.json()); return { response } } ``` ```js // @filename: ambient.d.ts declare const url1: string; declare const url2: string; // @filename: index.js // ---cut--- // If you have multiple promises /** @type {import('./$types').PageServerLoad} */ export +++async+++ function load({ fetch }) { --- const a = fetch(url1).then(r => r.json());--- --- const b = fetch(url2).then(r => r.json());--- +++ const [a, b] = await Promise.all([ fetch(url1).then(r => r.json()), fetch(url2).then(r => r.json()), ]);+++ return { a, b }; } ``` ## goto(...) 变更 `goto(...)` 不再接受外部 URL。要导航到外部 URL,请使用 `window.location.href = url`。现在 `state` 对象决定 `$page.state`,并且如果已声明,必须遵循 `App.PageState` 接口。有关更多详细信息,请参阅 [浅路由](shallow-routing)。 ## 路径现在默认为相对路径 在 SvelteKit 1 中,您的`app.html`中的`%sveltekit.assets%`在服务器端渲染时默认被替换为相对路径(即`.`或`..`或`../..`等,具体取决于渲染的路径),除非显式地将`paths.relative`配置选项设置为`false`。同样,从`$app/paths`导入的`base`和`assets`也是如此,但仅当显式将`paths.relative`选项设置为`true`时。 此不一致性已在版本 2 中修复。路径要么始终是相对的,要么始终是绝对的,具体取决于[`paths.relative`](configuration#paths)的值。默认为`true`,因为这会产生更便携的应用程序:如果`base`不是应用程序期望的(例如在[互联网档案馆](https://archive.org/)查看时)或构建时未知(例如部署到[IPFS](https://ipfs.tech/)等),则出现问题的可能性更小。 ## 服务器抓取不再可追踪 之前可以从服务器上的`fetch`es 跟踪 URL 以重新运行加载函数。这可能导致潜在的安全风险(私人 URL 泄露),因此它位于`dangerZone.trackServerFetches`设置之后,该设置现已移除。 ## `preloadCode` 参数必须以 `base` 前缀 SvelteKit 公开了两个函数,[`preloadCode`]($app-navigation#preloadCode) 和 [`preloadData`]($app-navigation#preloadData),用于以编程方式加载与特定路径关联的代码和数据。在版本 1 中,存在一个微妙的不一致——传递给`preloadCode`的路径不需要(如果已设置)以`base`路径作为前缀,而传递给`preloadData`的路径则需要。 这是在 SvelteKit 2 中修复的——在两种情况下,如果已设置,路径应该以`base`为前缀。 此外,`preloadCode` 现在接受单个参数,而不是 *n* 个参数。 ## `resolvePath` 已被移除 SvelteKit 1 包含了一个名为 `resolvePath` 的函数,该函数允许您将路由 ID(如 `/blog/[slug]`)和一组参数(如 `{ slug: 'hello' }`)解析为路径名。不幸的是,返回值没有包括 `base` 路径,限制了其在 `base` 已设置的情况下的实用性。 因此,SvelteKit 2 将 `resolvePath` 替换为(名称稍好一些的)函数 `resolveRoute`,该函数从 `$app/paths` 导入,并考虑了 `base`。 ```js ---import { resolvePath } from '@sveltejs/kit'; import { base } from '$app/paths';--- +++import { resolveRoute } from '$app/paths';+++ ---const path = base + resolvePath('/blog/[slug]', { slug });--- +++const path = resolveRoute('/blog/[slug]', { slug });+++ ``` `سلتو-مigrate` 将为您执行方法替换,尽管如果您稍后用 `base` 预先添加结果,您需要自己将其删除。 ## 改进的错误处理 错误在 SvelteKit 1 中处理不一致。一些错误会触发`handleError`钩子,但没有好的方法来辨别它们的状态(例如,区分 404 和 500 的唯一方法是通过查看`event.route.id`是否为`null`),而其他错误(如对没有操作的页面进行`POST`请求的 405 错误)根本不会触发`handleError`,但应该会。在后一种情况下,结果`$page.error`将与指定的`App.Error`[(](types#Error)如果指定的话[)](types#Error)类型不符。 SvelteKit 2 通过调用 `handleError` 钩子并使用两个新属性:`status` 和 `message` 来清理。对于从您的代码(或由您的代码调用的库代码)抛出的错误,状态将是 `500`,消息将是 `内部错误`。而 `error.message` 可能包含不应向用户暴露的敏感信息,`message` 则是安全的。 ## 动态环境变量在预渲染期间无法使用 The `$env/dynamic/public` 和 `$env/dynamic/private` 模块提供对 *运行时* 环境变量的访问,与 `$env/static/public` 和 `$env/static/private` 提供的 *构建时* 环境变量相反。 在 SvelteKit 1 的预渲染期间,它们是相同的。因此,使用 '动态' 环境变量的预渲染页面实际上是在“烘焙”构建时间值,这是不正确的。更糟糕的是,如果用户在导航到动态渲染的页面之前恰好访问了预渲染的页面,`$env/dynamic/public` 将在浏览器中使用这些过时的值进行填充。 由于这个原因,在 SvelteKit 2 的预渲染过程中无法读取动态环境变量 — 您应该使用 `静态` 模块。如果用户访问预渲染的页面,SvelteKit 将从服务器(默认情况下从名为`/_app/env.js`的模块)请求最新的`$env/dynamic/public`值,而不是从服务器渲染的 HTML 中读取它们。 ## `表单` 和 `数据` 已从 `使用:增强` 回调中移除 如果您提供了一个回调到[`使用:增强`](form-actions#Progressive-enhancement-use:enhance),它将用一个包含各种有用属性的对象被调用。 在 SvelteKit 1 中,这些属性包括`form`和`data`。这些属性在一段时间前已被弃用,转而使用`formElement`和`formData`,并在 SvelteKit 2 中完全删除。 ## 表单中包含文件输入时必须使用 `multipart/form-data` 如果一个表单包含一个``但没有任何`enctype="multipart/form-data"`属性,非 JS 提交将省略文件。SvelteKit 2 在遇到这样的表单进行`use:enhance`提交时将抛出错误,以确保在没有 JavaScript 的情况下您的表单能够正确工作。 ## 生成的`tsconfig.json`更严格 之前,生成的`tsconfig.json`在您的`tsconfig.json`包含`paths`或`baseUrl`时,仍在尽力生成一个相对有效的配置。在 SvelteKit 2 中,验证更加严格,当您在`tsconfig.json`中使用`paths`或`baseUrl`时,将会发出警告。这些设置用于生成路径别名,您应该使用`svelte.config.js`中的`alias`配置选项,以创建相应的别名,并为打包器创建相应的别名。 ## `getRequest`不再抛出错误 The `@sveltejs/kit/node` 模块导出用于 Node 环境的辅助函数,包括 `getRequest`,它将 Node [`ClientRequest`](https://nodejs.org/api/http.html#class-httpclientrequest) 转换为标准的 [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) 对象。 在 SvelteKit 1 中,`getRequest` 如果 `Content-Length` 头部超出指定大小限制时可能会抛出异常。在 SvelteKit 2 中,错误将不会立即抛出,而是在读取请求体(如果有)时才会抛出。这有助于更好地进行诊断和编写更简单的代码。 ## `vitепPгeprеss`不再从`@sveltejs/kit/vite`导出 由于 `@sveltejs/vite-plugin-svelte` 现在是一个 peer dependency,SvelteKit 2 不再导出 `vitePreprocess`。您应直接从 `@sveltejs/vite-plugin-svelte` 导入它。 ## 更新依赖项要求 SvelteKit 2 需要 Node `18.13` 或更高版本,以及以下最低依赖版本: * `斯威夫特@4` * `vit@5` * `typescript@5` * `@sveltejs/vite-plugin-svelte@3` (现在作为 SvelteKit 的 `peerDependency` 是必需的 — 之前它是直接依赖的) * `@sveltejs/adapter-cloudflare@3` (如果您使用这些适配器) * `@sveltejs/adapter-cloudflare-workers@2` * `@sveltejs/adapter-netlify@3` * `@sveltejs/adapter-node@2` * `@sveltejs/adapter-static@3` * `@sveltejs/adapter-vercel@4` `سلتو-مigrate` 将为您更新 `package.json`。 作为 TypeScript 升级的一部分,生成的`tsconfig.json`(你的`tsconfig.json`从中扩展而来)现在使用`"moduleResolution": "bundler"`(TypeScript 团队推荐,因为它可以正确解析具有 package.json 中`exports`映射的包中的类型)和`verbatimModuleSyntax`(它替换了现有的`importsNotUsedAsValues`和`preserveValueImports`标志——如果你在`tsconfig.json`中有这些,请删除它们。`svelte-migrate`会为你完成这项工作)。 ## SvelteKit 2.12: $app/stores 已弃用 SvelteKit 2.12 引入了基于 `$app/state` 的 [Svelte 5 runes API](/docs/svelte/what-are-runes)。`$app/state` 提供了与 `$app/stores` 相同的一切,但在使用方式和位置上提供了更大的灵活性。最重要的是,`page` 对象现在更加精细,例如,对 `page.state` 的更新不会使 `page.data` 无效,反之亦然。 因此,`$app/stores` 已弃用,并将在 SvelteKit 3 中被移除。如果您尚未升级,我们建议[升级到 Svelte 5](/docs/svelte/v5-migration-guide),然后迁移离开 `$app/stores`。大多数替代方案应该相当简单:将 `$app/stores` 的导入替换为 `$app/state`,并从使用位置删除 `$` 前缀。 ```svelte ---{$page.data}--- +++{page.data}+++ ``` 使用`npx sv migrate app-state`自动迁移大部分在`$app/stores`中使用的`.svelte`组件。