加载数据
在 +page.svelte
组件(及其包含的 +layout.svelte
组件)渲染之前,我们通常需要获取一些数据。这是通过定义 load
函数来完成的。
¥Before a +page.svelte
component (and its containing +layout.svelte
components) can be rendered, we often need to get some data. This is done by defining load
functions.
页面数据(Page data)
¥Page data
+page.svelte
文件可以有一个兄弟 +page.js
,它导出一个 load
函数,该函数的返回值可通过 data
prop 提供给页面:
¥A +page.svelte
file can have a sibling +page.js
that exports a load
function, the return value of which is available to the page via the data
prop:
/** @type {import('./$types').PageLoad} */
export function function load({ params }: {
params: any;
}): {
post: {
title: string;
content: string;
};
}
load({ params: any
params }) {
return {
post: {
title: string;
content: string;
}
post: {
title: string
title: `Title for ${params: any
params.slug} goes here`,
content: string
content: `Content for ${params: any
params.slug} goes here`
}
};
}
import type { type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad } from './$types';
export const const load: PageLoad
load: type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad = ({ params: Record<string, any>
The parameters of the current page - e.g. for a route like /blog/[slug]
, a { slug: string }
object
params }) => {
return {
post: {
title: string;
content: string;
}
post: {
title: string
title: `Title for ${params: Record<string, any>
The parameters of the current page - e.g. for a route like /blog/[slug]
, a { slug: string }
object
params.slug} goes here`,
content: string
content: `Content for ${params: Record<string, any>
The parameters of the current page - e.g. for a route like /blog/[slug]
, a { slug: string }
object
params.slug} goes here`
}
};
};
<script>
/** @type {import('./$types').PageProps} */
let { data } = $props();
</script>
<h1>{data.post.title}</h1>
<div>{@html data.post.content}</div>
<script lang="ts">
import type { PageProps } from './$types';
let { data }: PageProps = $props();
</script>
<h1>{data.post.title}</h1>
<div>{@html data.post.content}</div>
Legacy mode
在 2.16.0 版本之前,页面和布局的属性必须单独输入:
¥[!LEGACY] Before version 2.16.0, the props of a page and layout had to be typed individually:
+page/** @type {{ data: import('./$types').PageData }} */ let {
let data: any
data } =function $props(): any
$props();Declares the props that a component accepts. Example:
let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
import type {
import PageData
PageData } from './$types'; let {let data: PageData
data }: {data: PageData
data:import PageData
PageData } =function $props(): any
$props();Declares the props that a component accepts. Example:
let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
在 Svelte 4 中,你将使用
export let data
。¥In Svelte 4, you’d use
export let data
instead.
多亏了生成的 $types
模块,我们获得了完全的类型安全。
¥Thanks to the generated $types
module, we get full type safety.
+page.js
文件中的 load
函数在服务器和浏览器中运行(除非与 export const ssr = false
结合,在这种情况下它将 仅在浏览器中运行)。如果你的 load
函数应始终在服务器上运行(例如,因为它使用私有环境变量或访问数据库),那么它将改为进入 +page.server.js
。
¥A load
function in a +page.js
file runs both on the server and in the browser (unless combined with export const ssr = false
, in which case it will only run in the browser). If your load
function should always run on the server (because it uses private environment variables, for example, or accesses a database) then it would go in a +page.server.js
instead.
你的博客文章的 load
函数的更现实版本仅在服务器上运行并从数据库中提取数据,可能如下所示:
¥A more realistic version of your blog post’s load
function, that only runs on the server and pulls data from a database, might look like this:
import * as module "$lib/server/database"
db from '$lib/server/database';
/** @type {import('./$types').PageServerLoad} */
export async function function load(event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>): MaybePromise<void | Record<string, any>>
load({ params: Record<string, any>
The parameters of the current route - e.g. for a route like /blog/[slug]
, a { slug: string }
object
params }) {
return {
post: {
title: string;
content: string;
}
post: await module "$lib/server/database"
db.function getPost(slug: string): Promise<{
title: string;
content: string;
}>
getPost(params: Record<string, any>
The parameters of the current route - e.g. for a route like /blog/[slug]
, a { slug: string }
object
params.slug)
};
}
import * as module "$lib/server/database"
db from '$lib/server/database';
import type { type PageServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageServerLoad } from './$types';
export const const load: PageServerLoad
load: type PageServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageServerLoad = async ({ params: Record<string, any>
The parameters of the current route - e.g. for a route like /blog/[slug]
, a { slug: string }
object
params }) => {
return {
post: {
title: string;
content: string;
}
post: await module "$lib/server/database"
db.function getPost(slug: string): Promise<{
title: string;
content: string;
}>
getPost(params: Record<string, any>
The parameters of the current route - e.g. for a route like /blog/[slug]
, a { slug: string }
object
params.slug)
};
};
请注意,类型从 PageLoad
更改为 PageServerLoad
,因为服务器 load
函数可以访问其他参数。要了解何时使用 +page.js
以及何时使用 +page.server.js
,请参阅 通用与服务器。
¥Notice that the type changed from PageLoad
to PageServerLoad
, because server load
functions can access additional arguments. To understand when to use +page.js
and when to use +page.server.js
, see Universal vs server.
布局数据(Layout data)
¥Layout data
你的 +layout.svelte
文件还可以通过 +layout.js
或 +layout.server.js
加载数据。
¥Your +layout.svelte
files can also load data, via +layout.js
or +layout.server.js
.
import * as module "$lib/server/database"
db from '$lib/server/database';
/** @type {import('./$types').LayoutServerLoad} */
export async function function load(event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>): MaybePromise<void | Record<string, any>>
load() {
return {
posts: {
title: string;
slug: string;
}[]
posts: await module "$lib/server/database"
db.function getPostSummaries(): Promise<Array<{
title: string;
slug: string;
}>>
getPostSummaries()
};
}
import * as module "$lib/server/database"
db from '$lib/server/database';
import type { type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutServerLoad } from './$types';
export const const load: LayoutServerLoad
load: type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutServerLoad = async () => {
return {
posts: {
title: string;
slug: string;
}[]
posts: await module "$lib/server/database"
db.function getPostSummaries(): Promise<Array<{
title: string;
slug: string;
}>>
getPostSummaries()
};
};
<script>
/** @type {import('./$types').LayoutProps} */
let { data, children } = $props();
</script>
<main>
<!-- +page.svelte is `@render`ed here -->
{@render children()}
</main>
<aside>
<h2>More posts</h2>
<ul>
{#each data.posts as post}
<li>
<a href="/blog/{post.slug}">
{post.title}
</a>
</li>
{/each}
</ul>
</aside>
<script lang="ts">
import type { LayoutProps } from './$types';
let { data, children }: LayoutProps = $props();
</script>
<main>
<!-- +page.svelte is `@render`ed here -->
{@render children()}
</main>
<aside>
<h2>More posts</h2>
<ul>
{#each data.posts as post}
<li>
<a href="/blog/{post.slug}">
{post.title}
</a>
</li>
{/each}
</ul>
</aside>
Legacy mode
LayoutProps
是在 2.16.0 中添加的。在早期版本中,属性必须单独输入:¥[!LEGACY]
LayoutProps
was added in 2.16.0. In earlier versions, properties had to be typed individually:+layout/** @type {{ data: import('./$types').LayoutData, children: Snippet }} */ let {
let data: any
data,let children: any
children } =function $props(): any
$props();Declares the props that a component accepts. Example:
let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
import type {
import LayoutData
LayoutData } from './$types'; let {let data: LayoutData
data,let children: Snippet
children }: {data: LayoutData
data:import LayoutData
LayoutData,children: Snippet
children:type Snippet = /*unresolved*/ any
Snippet } =function $props(): any
$props();Declares the props that a component accepts. Example:
let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
布局 load
函数返回的数据可用于子 +layout.svelte
组件和 +page.svelte
组件以及它 ‘belongs’ 到的布局。
¥Data returned from layout load
functions is available to child +layout.svelte
components and the +page.svelte
component as well as the layout that it ‘belongs’ to.
<script>
import { page } from '$app/state';
/** @type {import('./$types').PageProps} */
let { data } = $props();
// we can access `data.posts` because it's returned from
// the parent layout `load` function
let index = $derived(data.posts.findIndex(post => post.slug === page.params.slug));
let next = $derived(data.posts[index + 1]);
</script>
<h1>{data.post.title}</h1>
<div>{@html data.post.content}</div>
{#if next}
<p>Next post: <a href="/blog/{next.slug}">{next.title}</a></p>
{/if}
<script lang="ts">
import { page } from '$app/state';
import type { PageProps } from './$types';
let { data }: PageProps = $props();
// we can access `data.posts` because it's returned from
// the parent layout `load` function
let index = $derived(data.posts.findIndex(post => post.slug === page.params.slug));
let next = $derived(data.posts[index + 1]);
</script>
<h1>{data.post.title}</h1>
<div>{@html data.post.content}</div>
{#if next}
<p>Next post: <a href="/blog/{next.slug}">{next.title}</a></p>
{/if}
如果多个
load
函数返回具有相同键的数据,则最后一个 ‘wins’ — 布局load
返回{ a: 1, b: 2 }
和页面load
返回{ b: 3, c: 4 }
的结果将是{ a: 1, b: 3, c: 4 }
。¥[!NOTE] If multiple
load
functions return data with the same key, the last one ‘wins’ — the result of a layoutload
returning{ a: 1, b: 2 }
and a pageload
returning{ b: 3, c: 4 }
would be{ a: 1, b: 3, c: 4 }
.
page.data
+page.svelte
组件及其上方的每个 +layout.svelte
组件都可以访问自己的数据以及来自其父级的所有数据。
¥The +page.svelte
component, and each +layout.svelte
component above it, has access to its own data plus all the data from its parents.
在某些情况下,我们可能需要相反的情况 - 父布局可能需要访问页面数据或子布局中的数据。例如,根布局可能想要访问从 +page.js
或 +page.server.js
中的 load
函数返回的 title
属性。这可以通过 page.data
完成:
¥In some cases, we might need the opposite — a parent layout might need to access page data or data from a child layout. For example, the root layout might want to access a title
property returned from a load
function in +page.js
or +page.server.js
. This can be done with page.data
:
<script>
import { page } from '$app/state';
</script>
<svelte:head>
<title>{page.data.title}</title>
</svelte:head>
<script lang="ts">
import { page } from '$app/state';
</script>
<svelte:head>
<title>{page.data.title}</title>
</svelte:head>
page.data
的类型信息由 App.PageData
提供。
¥Type information for page.data
is provided by App.PageData
.
Legacy mode
SvelteKit 2.12 中添加了
$app/state
。如果你使用的是早期版本或使用 Svelte 4,请改用$app/stores
。它提供了一个page
存储,具有你可以订阅的相同接口,例如$page.data.title
。¥[!LEGACY]
$app/state
was added in SvelteKit 2.12. If you’re using an earlier version or are using Svelte 4, use$app/stores
instead. It provides apage
store with the same interface that you can subscribe to, e.g.$page.data.title
.
通用与服务器(Universal vs server)
¥Universal vs server
正如我们所见,有两种类型的 load
函数:
¥As we’ve seen, there are two types of load
function:
+page.js
和+layout.js
文件导出在服务器和浏览器中运行的通用load
函数¥
+page.js
and+layout.js
files export universalload
functions that run both on the server and in the browser+page.server.js
和+layout.server.js
文件导出仅在服务器端运行的服务器load
函数¥
+page.server.js
and+layout.server.js
files export serverload
functions that only run server-side
从概念上讲,它们是同一件事,但需要注意一些重要的区别。
¥Conceptually, they’re the same thing, but there are some important differences to be aware of.
哪个加载函数何时运行?(When does which load function run?)
¥When does which load function run?
服务器 load
函数始终在服务器上运行。
¥Server load
functions always run on the server.
默认情况下,当用户首次访问你的页面时,通用 load
函数会在 SSR 期间在服务器上运行。然后它们将在水合期间再次运行,重用来自 获取请求 的任何响应。所有后续对通用 load
函数的调用都在浏览器中进行。你可以通过 页面选项 自定义行为。如果你禁用 服务器端渲染,你将获得一个 SPA,并且通用 load
函数始终在客户端上运行。
¥By default, universal load
functions run on the server during SSR when the user first visits your page. They will then run again during hydration, reusing any responses from fetch requests. All subsequent invocations of universal load
functions happen in the browser. You can customize the behavior through page options. If you disable server side rendering, you’ll get an SPA and universal load
functions always run on the client.
如果路由包含通用和服务器 load
函数,则服务器 load
将首先运行。
¥If a route contains both universal and server load
functions, the server load
runs first.
load
函数在运行时被调用,除非你 prerender 页面 — 在这种情况下,它会在构建时被调用。
¥A load
function is invoked at runtime, unless you prerender the page — in that case, it’s invoked at build time.
输入(Input)
¥Input
通用和服务器 load
函数都可以访问描述请求的属性(params
、route
和 url
)和各种函数(fetch
、setHeaders
、parent
、depends
和 untrack
)。这些将在以下部分中描述。
¥Both universal and server load
functions have access to properties describing the request (params
, route
and url
) and various functions (fetch
, setHeaders
, parent
, depends
and untrack
). These are described in the following sections.
服务器 load
函数使用 ServerLoadEvent
调用,它从 RequestEvent
继承了 clientAddress
、cookies
、locals
、platform
和 request
。
¥Server load
functions are called with a ServerLoadEvent
, which inherits clientAddress
, cookies
, locals
, platform
and request
from RequestEvent
.
通用 load
函数使用具有 data
属性的 LoadEvent
调用。如果 +page.js
和 +page.server.js
(或 +layout.js
和 +layout.server.js
)中都有 load
函数,则服务器 load
函数的返回值是通用 load
函数参数的 data
属性。
¥Universal load
functions are called with a LoadEvent
, which has a data
property. If you have load
functions in both +page.js
and +page.server.js
(or +layout.js
and +layout.server.js
), the return value of the server load
function is the data
property of the universal load
function’s argument.
输出(Output)
¥Output
通用 load
函数可以返回包含任何值的对象,包括自定义类和组件构造函数等。
¥A universal load
function can return an object containing any values, including things like custom classes and component constructors.
服务器 load
函数必须返回可以用 devalue 序列化的数据(任何可以表示为 JSON 以及 BigInt
、Date
、Map
、Set
和 RegExp
之类的东西,或重复/循环引用),以便可以通过网络传输。你的数据可以包含 promises,在这种情况下它将被流式传输到浏览器。
¥A server load
function must return data that can be serialized with devalue — anything that can be represented as JSON plus things like BigInt
, Date
, Map
, Set
and RegExp
, or repeated/cyclical references — so that it can be transported over the network. Your data can include promises, in which case it will be streamed to browsers.
何时使用哪个(When to use which)
¥When to use which
当你需要直接从数据库或文件系统访问数据,或者需要使用私有环境变量时,服务器 load
函数非常方便。
¥Server load
functions are convenient when you need to access data directly from a database or filesystem, or need to use private environment variables.
当你需要从外部 API 获取 fetch
数据并且不需要私有凭据时,通用 load
函数非常有用,因为 SvelteKit 可以直接从 API 获取数据,而不是通过你的服务器。当你需要返回无法序列化的内容(例如 Svelte 组件构造函数)时,它们也很有用。
¥Universal load
functions are useful when you need to fetch
data from an external API and don’t need private credentials, since SvelteKit can get the data directly from the API rather than going via your server. They are also useful when you need to return something that can’t be serialized, such as a Svelte component constructor.
在极少数情况下,你可能需要同时使用两者 - 例如,你可能需要返回使用服务器数据初始化的自定义类的实例。同时使用两者时,服务器 load
返回值不会直接传递给页面,而是传递给通用 load
函数(作为 data
属性):
¥In rare cases, you might need to use both together — for example, you might need to return an instance of a custom class that was initialised with data from your server. When using both, the server load
return value is not passed directly to the page, but to the universal load
function (as the data
property):
/** @type {import('./$types').PageServerLoad} */
export async function function load(): Promise<{
serverMessage: string;
}>
load() {
return {
serverMessage: string
serverMessage: 'hello from server load function'
};
}
import type { type PageServerLoad = (event: Kit.ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageServerLoad = (event: Kit.ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageServerLoad } from './$types';
export const const load: PageServerLoad
load: type PageServerLoad = (event: Kit.ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageServerLoad = (event: Kit.ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageServerLoad = async () => {
return {
serverMessage: string
serverMessage: 'hello from server load function'
};
};
/** @type {import('./$types').PageLoad} */
export async function function load({ data }: {
data: any;
}): Promise<{
serverMessage: any;
universalMessage: string;
}>
load({ data: any
data }) {
return {
serverMessage: any
serverMessage: data: any
data.serverMessage,
universalMessage: string
universalMessage: 'hello from universal load function'
};
}
import type { type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad } from './$types';
export const const load: PageLoad
load: type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad = async ({ data: Record<string, any> | null
Contains the data returned by the route’s server load
function (in +layout.server.js
or +page.server.js
), if any.
data }) => {
return {
serverMessage: any
serverMessage: data: Record<string, any> | null
Contains the data returned by the route’s server load
function (in +layout.server.js
or +page.server.js
), if any.
data.serverMessage,
universalMessage: string
universalMessage: 'hello from universal load function'
};
};
使用 URL 数据(Using URL data)
¥Using URL data
通常,load
函数以某种方式依赖于 URL。为此,load
函数为你提供了 url
、route
和 params
。
¥Often the load
function depends on the URL in one way or another. For this, the load
function provides you with url
, route
and params
.
url
URL
的实例,包含 origin
、hostname
、pathname
和 searchParams
等属性(包含解析后的查询字符串作为 URLSearchParams
对象)。url.hash
在 load
期间无法访问,因为它在服务器上不可用。
¥An instance of URL
, containing properties like the origin
, hostname
, pathname
and searchParams
(which contains the parsed query string as a URLSearchParams
object). url.hash
cannot be accessed during load
, since it is unavailable on the server.
在某些环境中,这是从服务器端渲染期间的请求标头派生的。例如,如果你使用的是 adapter-node,则可能需要配置适配器以确保 URL 正确。
¥[!NOTE] In some environments this is derived from request headers during server-side rendering. If you’re using adapter-node, for example, you may need to configure the adapter in order for the URL to be correct.
route
包含当前路由目录的名称,相对于 src/routes
:
¥Contains the name of the current route directory, relative to src/routes
:
/** @type {import('./$types').PageLoad} */
export function function load({ route }: {
route: any;
}): void
load({ route: any
route }) {
var console: Console
The console
module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
- A
Console
class with methods such as console.log()
, console.error()
and console.warn()
that can be used to write to any Node.js stream.
- A global
console
instance configured to write to process.stdout
and
process.stderr
. The global console
can be used without calling require('console')
.
Warning: The global console object’s methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the note on process I/O
for
more information.
Example using the global console
:
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
Example using the Console
class:
const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
Prints to stdout
with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to printf(3)
(the arguments are all passed to util.format()
).
const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout
See util.format()
for more information.
log(route: any
route.id); // '/a/[b]/[...c]'
}
import type { type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad } from './$types';
export const const load: PageLoad
load: type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad = ({ route: {
id: string | null;
}
Info about the current route
route }) => {
var console: Console
The console
module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
- A
Console
class with methods such as console.log()
, console.error()
and console.warn()
that can be used to write to any Node.js stream.
- A global
console
instance configured to write to process.stdout
and
process.stderr
. The global console
can be used without calling require('console')
.
Warning: The global console object’s methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the note on process I/O
for
more information.
Example using the global console
:
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
Example using the Console
class:
const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
Prints to stdout
with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to printf(3)
(the arguments are all passed to util.format()
).
const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout
See util.format()
for more information.
log(route: {
id: string | null;
}
Info about the current route
route.id: string | null
The ID of the current route - e.g. for src/routes/blog/[slug]
, it would be /blog/[slug]
id); // '/a/[b]/[...c]'
};
params
params
源自 url.pathname
和 route.id
。
¥params
is derived from url.pathname
and route.id
.
假设 route.id
为 /a/[b]/[...c]
,url.pathname
为 /a/x/y/z
,params
对象将如下所示:
¥Given a route.id
of /a/[b]/[...c]
and a url.pathname
of /a/x/y/z
, the params
object would look like this:
{
"b": "x",
"c": "y/z"
}
发出获取请求(Making fetch requests)
¥Making fetch requests
要从外部 API 或 +server.js
处理程序获取数据,你可以使用提供的 fetch
函数,该函数的行为与 原生 fetch
Web API 相同,但有一些附加功能:
¥To get data from an external API or a +server.js
handler, you can use the provided fetch
function, which behaves identically to the native fetch
web API with a few additional features:
它可用于在服务器上发出凭证请求,因为它继承了页面请求的
cookie
和authorization
标头。¥It can be used to make credentialed requests on the server, as it inherits the
cookie
andauthorization
headers for the page request.它可以在服务器上发出相对请求(通常,
fetch
在服务器上下文中使用时需要具有来源的 URL)。¥It can make relative requests on the server (ordinarily,
fetch
requires a URL with an origin when used in a server context).内部请求(例如,对于
+server.js
路由)在服务器上运行时直接转到处理程序函数,而无需 HTTP 调用的开销。¥Internal requests (e.g. for
+server.js
routes) go directly to the handler function when running on the server, without the overhead of an HTTP call.在服务器端渲染过程中,响应将通过挂接到
Response
对象的text
、json
和arrayBuffer
方法中被捕获并内联到渲染的 HTML 中。请注意,除非通过filterSerializedResponseHeaders
明确包含,否则不会序列化标头。¥During server-side rendering, the response will be captured and inlined into the rendered HTML by hooking into the
text
,json
andarrayBuffer
methods of theResponse
object. Note that headers will not be serialized, unless explicitly included viafilterSerializedResponseHeaders
.在 hydration 期间,将从 HTML 中读取响应,以保证一致性并防止额外的网络请求 - 如果你在使用浏览器
fetch
而不是load
fetch
时在浏览器控制台中收到警告,这就是原因。¥During hydration, the response will be read from the HTML, guaranteeing consistency and preventing an additional network request - if you received a warning in your browser console when using the browser
fetch
instead of theload
fetch
, this is why.
/** @type {import('./$types').PageLoad} */
export async function function load({ fetch, params }: {
fetch: any;
params: any;
}): Promise<{
item: any;
}>
load({ fetch: any
fetch, params: any
params }) {
const const res: any
res = await fetch: any
fetch(`/api/items/${params: any
params.id}`);
const const item: any
item = await const res: any
res.json();
return { item: any
item };
}
import type { type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad } from './$types';
export const const load: PageLoad
load: type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad = async ({ fetch: {
(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
(input: string | URL | globalThis.Request, init?: RequestInit): Promise<Response>;
}
fetch
is equivalent to the native fetch
web API, with a few additional features:
- It can be used to make credentialed requests on the server, as it inherits the
cookie
and authorization
headers for the page request.
- It can make relative requests on the server (ordinarily,
fetch
requires a URL with an origin when used in a server context).
- Internal requests (e.g. for
+server.js
routes) go directly to the handler function when running on the server, without the overhead of an HTTP call.
- During server-side rendering, the response will be captured and inlined into the rendered HTML by hooking into the
text
and json
methods of the Response
object. Note that headers will not be serialized, unless explicitly included via filterSerializedResponseHeaders
- During hydration, the response will be read from the HTML, guaranteeing consistency and preventing an additional network request.
You can learn more about making credentialed requests with cookies here
fetch, params: Record<string, any>
The parameters of the current page - e.g. for a route like /blog/[slug]
, a { slug: string }
object
params }) => {
const const res: Response
res = await fetch: (input: string | URL | globalThis.Request, init?: RequestInit) => Promise<Response> (+1 overload)
fetch(`/api/items/${params: Record<string, any>
The parameters of the current page - e.g. for a route like /blog/[slug]
, a { slug: string }
object
params.id}`);
const const item: any
item = await const res: Response
res.Body.json(): Promise<any>
json();
return { item: any
item };
};
Cookies
服务器 load
函数可以获取和设置 cookies
。
¥A server load
function can get and set cookies
.
import * as module "$lib/server/database"
db from '$lib/server/database';
/** @type {import('./$types').LayoutServerLoad} */
export async function function load(event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>): MaybePromise<void | Record<string, any>>
load({ cookies: Cookies
Get or set cookies related to the current request
cookies }) {
const const sessionid: string | undefined
sessionid = cookies: Cookies
Get or set cookies related to the current request
cookies.Cookies.get(name: string, opts?: CookieParseOptions): string | undefined
Gets a cookie that was previously set with cookies.set
, or from the request headers.
get('sessionid');
return {
user: {
name: string;
avatar: string;
}
user: await module "$lib/server/database"
db.function getUser(sessionid: string | undefined): Promise<{
name: string;
avatar: string;
}>
getUser(const sessionid: string | undefined
sessionid)
};
}
import * as module "$lib/server/database"
db from '$lib/server/database';
import type { type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutServerLoad } from './$types';
export const const load: LayoutServerLoad
load: type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutServerLoad = async ({ cookies: Cookies
Get or set cookies related to the current request
cookies }) => {
const const sessionid: string | undefined
sessionid = cookies: Cookies
Get or set cookies related to the current request
cookies.Cookies.get(name: string, opts?: CookieParseOptions): string | undefined
Gets a cookie that was previously set with cookies.set
, or from the request headers.
get('sessionid');
return {
user: {
name: string;
avatar: string;
}
user: await module "$lib/server/database"
db.function getUser(sessionid: string | undefined): Promise<{
name: string;
avatar: string;
}>
getUser(const sessionid: string | undefined
sessionid)
};
};
只有当目标主机与 SvelteKit 应用或其更具体的子域相同时,Cookie 才会通过提供的 fetch
函数传递。
¥Cookies will only be passed through the provided fetch
function if the target host is the same as the SvelteKit application or a more specific subdomain of it.
例如,如果 SvelteKit 正在为 my.domain.com 提供服务:
¥For example, if SvelteKit is serving my.domain.com:
domain.com 将不会收到 cookie
¥domain.com WILL NOT receive cookies
其他属性:
¥my.domain.com WILL receive cookies
api.domain.com 将不会接收 cookie
¥api.domain.com WILL NOT receive cookies
成功!
¥sub.my.domain.com WILL receive cookies
设置 credentials: 'include'
时不会传递其他 cookie,因为 SvelteKit 不知道哪个 cookie 属于哪个域(浏览器不会传递此信息),因此转发任何一个都不安全。使用 handleFetch 钩子 来解决它。
¥Other cookies will not be passed when credentials: 'include'
is set, because SvelteKit does not know which domain which cookie belongs to (the browser does not pass this information along), so it’s not safe to forward any of them. Use the handleFetch hook to work around it.
标题(Headers)
¥Headers
服务器和通用 load
函数都可以访问 setHeaders
函数,当在服务器上运行时,它可以设置响应的标头。(在浏览器中运行时,setHeaders
无效。)如果你希望缓存页面,这将非常有用,例如:
¥Both server and universal load
functions have access to a setHeaders
function that, when running on the server, can set headers for the response. (When running in the browser, setHeaders
has no effect.) This is useful if you want the page to be cached, for example:
/** @type {import('./$types').PageLoad} */
export async function function load({ fetch, setHeaders }: {
fetch: any;
setHeaders: any;
}): Promise<any>
load({ fetch: any
fetch, setHeaders: any
setHeaders }) {
const const url: "https://cms.example.com/products.json"
url = `https://cms.example.com/products.json`;
const const response: any
response = await fetch: any
fetch(const url: "https://cms.example.com/products.json"
url);
// Headers are only set during SSR, caching the page's HTML
// for the same length of time as the underlying data.
setHeaders: any
setHeaders({
age: any
age: const response: any
response.headers.get('age'),
'cache-control': const response: any
response.headers.get('cache-control')
});
return const response: any
response.json();
}
import type { type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad } from './$types';
export const const load: PageLoad
load: type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad = async ({ fetch: {
(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
(input: string | URL | globalThis.Request, init?: RequestInit): Promise<Response>;
}
fetch
is equivalent to the native fetch
web API, with a few additional features:
- It can be used to make credentialed requests on the server, as it inherits the
cookie
and authorization
headers for the page request.
- It can make relative requests on the server (ordinarily,
fetch
requires a URL with an origin when used in a server context).
- Internal requests (e.g. for
+server.js
routes) go directly to the handler function when running on the server, without the overhead of an HTTP call.
- During server-side rendering, the response will be captured and inlined into the rendered HTML by hooking into the
text
and json
methods of the Response
object. Note that headers will not be serialized, unless explicitly included via filterSerializedResponseHeaders
- During hydration, the response will be read from the HTML, guaranteeing consistency and preventing an additional network request.
You can learn more about making credentialed requests with cookies here
fetch, setHeaders: (headers: Record<string, string>) => void
If you need to set headers for the response, you can do so using the this method. This is useful if you want the page to be cached, for example:
src/routes/blog/+pageexport async function load({ fetch, setHeaders }) {
const url = `https://cms.example.com/articles.json`;
const response = await fetch(url);
setHeaders({
age: response.headers.get('age'),
'cache-control': response.headers.get('cache-control')
});
return response.json();
}
Setting the same header multiple times (even in separate load
functions) is an error — you can only set a given header once.
You cannot add a set-cookie
header with setHeaders
— use the cookies
API in a server-only load
function instead.
setHeaders
has no effect when a load
function runs in the browser.
setHeaders }) => {
const const url: "https://cms.example.com/products.json"
url = `https://cms.example.com/products.json`;
const const response: Response
response = await fetch: (input: string | URL | globalThis.Request, init?: RequestInit) => Promise<Response> (+1 overload)
fetch(const url: "https://cms.example.com/products.json"
url);
// Headers are only set during SSR, caching the page's HTML
// for the same length of time as the underlying data.
setHeaders: (headers: Record<string, string>) => void
If you need to set headers for the response, you can do so using the this method. This is useful if you want the page to be cached, for example:
src/routes/blog/+pageexport async function load({ fetch, setHeaders }) {
const url = `https://cms.example.com/articles.json`;
const response = await fetch(url);
setHeaders({
age: response.headers.get('age'),
'cache-control': response.headers.get('cache-control')
});
return response.json();
}
Setting the same header multiple times (even in separate load
functions) is an error — you can only set a given header once.
You cannot add a set-cookie
header with setHeaders
— use the cookies
API in a server-only load
function instead.
setHeaders
has no effect when a load
function runs in the browser.
setHeaders({
age: string | null
age: const response: Response
response.Response.headers: Headers
headers.Headers.get(name: string): string | null
get('age'),
'cache-control': const response: Response
response.Response.headers: Headers
headers.Headers.get(name: string): string | null
get('cache-control')
});
return const response: Response
response.Body.json(): Promise<any>
json();
};
多次设置相同的标头(即使在单独的 load
函数中)是错误的。你只能使用 setHeaders
函数设置一次给定的标题。你不能使用 setHeaders
添加 set-cookie
标头 — 改用 cookies.set(name, value, options)
。
¥Setting the same header multiple times (even in separate load
functions) is an error. You can only set a given header once using the setHeaders
function. You cannot add a set-cookie
header with setHeaders
— use cookies.set(name, value, options)
instead.
使用父级数据(Using parent data)
¥Using parent data
有时,load
函数从父 load
函数访问数据很有用,这可以通过 await parent()
完成:
¥Occasionally it’s useful for a load
function to access data from a parent load
function, which can be done with await parent()
:
/** @type {import('./$types').LayoutLoad} */
export function function load(): {
a: number;
}
load() {
return { a: number
a: 1 };
}
import type { type LayoutLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type LayoutLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutLoad } from './$types';
export const const load: LayoutLoad
load: type LayoutLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type LayoutLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutLoad = () => {
return { a: number
a: 1 };
};
/** @type {import('./$types').LayoutLoad} */
export async function function load({ parent }: {
parent: any;
}): Promise<{
b: any;
}>
load({ parent: any
parent }) {
const { const a: any
a } = await parent: any
parent();
return { b: any
b: const a: any
a + 1 };
}
import type { type LayoutLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type LayoutLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutLoad } from './$types';
export const const load: LayoutLoad
load: type LayoutLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type LayoutLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutLoad = async ({ parent: () => Promise<Record<string, any>>
await parent()
returns data from parent +layout.js
load
functions.
Implicitly, a missing +layout.js
is treated as a ({ data }) => data
function, meaning that it will return and forward data from parent +layout.server.js
files.
Be careful not to introduce accidental waterfalls when using await parent()
. If for example you only want to merge parent data into the returned output, call it after fetching your other data.
parent }) => {
const { const a: any
a } = await parent: () => Promise<Record<string, any>>
await parent()
returns data from parent +layout.js
load
functions.
Implicitly, a missing +layout.js
is treated as a ({ data }) => data
function, meaning that it will return and forward data from parent +layout.server.js
files.
Be careful not to introduce accidental waterfalls when using await parent()
. If for example you only want to merge parent data into the returned output, call it after fetching your other data.
parent();
return { b: any
b: const a: any
a + 1 };
};
/** @type {import('./$types').PageLoad} */
export async function function load({ parent }: {
parent: any;
}): Promise<{
c: any;
}>
load({ parent: any
parent }) {
const { const a: any
a, const b: any
b } = await parent: any
parent();
return { c: any
c: const a: any
a + const b: any
b };
}
import type { type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad } from './$types';
export const const load: PageLoad
load: type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad = async ({ parent: () => Promise<Record<string, any>>
await parent()
returns data from parent +layout.js
load
functions.
Implicitly, a missing +layout.js
is treated as a ({ data }) => data
function, meaning that it will return and forward data from parent +layout.server.js
files.
Be careful not to introduce accidental waterfalls when using await parent()
. If for example you only want to merge parent data into the returned output, call it after fetching your other data.
parent }) => {
const { const a: any
a, const b: any
b } = await parent: () => Promise<Record<string, any>>
await parent()
returns data from parent +layout.js
load
functions.
Implicitly, a missing +layout.js
is treated as a ({ data }) => data
function, meaning that it will return and forward data from parent +layout.server.js
files.
Be careful not to introduce accidental waterfalls when using await parent()
. If for example you only want to merge parent data into the returned output, call it after fetching your other data.
parent();
return { c: any
c: const a: any
a + const b: any
b };
};
<script>
/** @type {import('./$types').PageProps} */
let { data } = $props();
</script>
<!-- renders `1 + 2 = 3` -->
<p>{data.a} + {data.b} = {data.c}</p>
<script lang="ts">
import type { PageProps } from './$types';
let { data }: PageProps = $props();
</script>
<!-- renders `1 + 2 = 3` -->
<p>{data.a} + {data.b} = {data.c}</p>
请注意,
+page.js
中的load
函数从两个布局load
函数接收合并的数据,而不仅仅是直接父级。¥[!NOTE] Notice that the
load
function in+page.js
receives the merged data from both layoutload
functions, not just the immediate parent.
在 +page.server.js
和 +layout.server.js
中,parent
从父 +layout.server.js
文件返回数据。
¥Inside +page.server.js
and +layout.server.js
, parent
returns data from parent +layout.server.js
files.
在 +page.js
或 +layout.js
中,它将从父 +layout.js
文件返回数据。但是,缺少的 +layout.js
被视为 ({ data }) => data
函数,这意味着它还将从 +layout.js
文件的非 ‘shadowed’ 的父 +layout.server.js
文件返回数据
¥In +page.js
or +layout.js
it will return data from parent +layout.js
files. However, a missing +layout.js
is treated as a ({ data }) => data
function, meaning that it will also return data from parent +layout.server.js
files that are not ‘shadowed’ by a +layout.js
file
使用 await parent()
时,请注意不要引入瀑布。例如,这里 getData(params)
不依赖于调用 parent()
的结果,因此我们应该先调用它以避免延迟渲染。
¥Take care not to introduce waterfalls when using await parent()
. Here, for example, getData(params)
does not depend on the result of calling parent()
, so we should call it first to avoid a delayed render.
/** @type {import('./$types').PageLoad} */
export async function function load(event: LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>): MaybePromise<void | Record<string, any>>
load({ params: Record<string, any>
The parameters of the current page - e.g. for a route like /blog/[slug]
, a { slug: string }
object
params, parent: () => Promise<Record<string, any>>
await parent()
returns data from parent +layout.js
load
functions.
Implicitly, a missing +layout.js
is treated as a ({ data }) => data
function, meaning that it will return and forward data from parent +layout.server.js
files.
Be careful not to introduce accidental waterfalls when using await parent()
. If for example you only want to merge parent data into the returned output, call it after fetching your other data.
parent }) {
const parentData = await parent();
const const data: {
meta: any;
}
data = await function getData(params: Record<string, string>): Promise<{
meta: any;
}>
getData(params: Record<string, any>
The parameters of the current page - e.g. for a route like /blog/[slug]
, a { slug: string }
object
params);
const const parentData: Record<string, any>
parentData = await parent: () => Promise<Record<string, any>>
await parent()
returns data from parent +layout.js
load
functions.
Implicitly, a missing +layout.js
is treated as a ({ data }) => data
function, meaning that it will return and forward data from parent +layout.server.js
files.
Be careful not to introduce accidental waterfalls when using await parent()
. If for example you only want to merge parent data into the returned output, call it after fetching your other data.
parent();
return {
...const data: {
meta: any;
}
data,
meta: any
meta: { ...const parentData: Record<string, any>
parentData.meta, ...const data: {
meta: any;
}
data.meta: any
meta }
};
}
import type { type PageLoad = (event: LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad } from './$types';
export const const load: PageLoad
load: type PageLoad = (event: LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad = async ({ params: Record<string, any>
The parameters of the current page - e.g. for a route like /blog/[slug]
, a { slug: string }
object
params, parent: () => Promise<Record<string, any>>
await parent()
returns data from parent +layout.js
load
functions.
Implicitly, a missing +layout.js
is treated as a ({ data }) => data
function, meaning that it will return and forward data from parent +layout.server.js
files.
Be careful not to introduce accidental waterfalls when using await parent()
. If for example you only want to merge parent data into the returned output, call it after fetching your other data.
parent }) => {
const parentData = await parent();
const const data: {
meta: any;
}
data = await function getData(params: Record<string, string>): Promise<{
meta: any;
}>
getData(params: Record<string, any>
The parameters of the current page - e.g. for a route like /blog/[slug]
, a { slug: string }
object
params);
const const parentData: Record<string, any>
parentData = await parent: () => Promise<Record<string, any>>
await parent()
returns data from parent +layout.js
load
functions.
Implicitly, a missing +layout.js
is treated as a ({ data }) => data
function, meaning that it will return and forward data from parent +layout.server.js
files.
Be careful not to introduce accidental waterfalls when using await parent()
. If for example you only want to merge parent data into the returned output, call it after fetching your other data.
parent();
return {
...const data: {
meta: any;
}
data,
meta: any
meta: { ...const parentData: Record<string, any>
parentData.meta, ...const data: {
meta: any;
}
data.meta: any
meta }
};
};
错误(Errors)
¥Errors
如果在 load
期间抛出错误,将渲染最近的 +error.svelte
。对于 expected 错误,使用 @sveltejs/kit
中的 error
助手指定 HTTP 状态代码和可选消息:
¥If an error is thrown during load
, the nearest +error.svelte
will be rendered. For expected errors, use the error
helper from @sveltejs/kit
to specify the HTTP status code and an optional message:
import { function error(status: number, body: App.Error): never (+1 overload)
Throws an error with a HTTP status code and an optional message.
When called during request handling, this will cause SvelteKit to
return an error response without invoking handleError
.
Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it.
error } from '@sveltejs/kit';
/** @type {import('./$types').LayoutServerLoad} */
export function function load(event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>): MaybePromise<void | Record<string, any>>
load({ locals: App.Locals
Contains custom data that was added to the request within the server handle hook
.
locals }) {
if (!locals: App.Locals
Contains custom data that was added to the request within the server handle hook
.
locals.App.Locals.user?: {
name: string;
isAdmin: boolean;
} | undefined
user) {
function error(status: number, body?: {
message: string;
} extends App.Error ? App.Error | string | undefined : never): never (+1 overload)
Throws an error with a HTTP status code and an optional message.
When called during request handling, this will cause SvelteKit to
return an error response without invoking handleError
.
Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it.
error(401, 'not logged in');
}
if (!locals: App.Locals
Contains custom data that was added to the request within the server handle hook
.
locals.App.Locals.user?: {
name: string;
isAdmin: boolean;
}
user.isAdmin: boolean
isAdmin) {
function error(status: number, body?: {
message: string;
} extends App.Error ? App.Error | string | undefined : never): never (+1 overload)
Throws an error with a HTTP status code and an optional message.
When called during request handling, this will cause SvelteKit to
return an error response without invoking handleError
.
Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it.
error(403, 'not an admin');
}
}
import { function error(status: number, body: App.Error): never (+1 overload)
Throws an error with a HTTP status code and an optional message.
When called during request handling, this will cause SvelteKit to
return an error response without invoking handleError
.
Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it.
error } from '@sveltejs/kit';
import type { type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutServerLoad } from './$types';
export const const load: LayoutServerLoad
load: type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutServerLoad = ({ locals: App.Locals
Contains custom data that was added to the request within the server handle hook
.
locals }) => {
if (!locals: App.Locals
Contains custom data that was added to the request within the server handle hook
.
locals.App.Locals.user?: {
name: string;
isAdmin: boolean;
} | undefined
user) {
function error(status: number, body?: {
message: string;
} extends App.Error ? App.Error | string | undefined : never): never (+1 overload)
Throws an error with a HTTP status code and an optional message.
When called during request handling, this will cause SvelteKit to
return an error response without invoking handleError
.
Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it.
error(401, 'not logged in');
}
if (!locals: App.Locals
Contains custom data that was added to the request within the server handle hook
.
locals.App.Locals.user?: {
name: string;
isAdmin: boolean;
}
user.isAdmin: boolean
isAdmin) {
function error(status: number, body?: {
message: string;
} extends App.Error ? App.Error | string | undefined : never): never (+1 overload)
Throws an error with a HTTP status code and an optional message.
When called during request handling, this will cause SvelteKit to
return an error response without invoking handleError
.
Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it.
error(403, 'not an admin');
}
};
调用 error(...)
将引发异常,从而可以轻松地从辅助函数内部停止执行。
¥Calling error(...)
will throw an exception, making it easy to stop execution from inside helper functions.
如果抛出 unexpected 错误,SvelteKit 将调用 handleError
并将其视为 500 内部错误。
¥If an unexpected error is thrown, SvelteKit will invoke handleError
and treat it as a 500 Internal Error.
在 SvelteKit 1.x 中 你必须自己
throw
错误¥[!NOTE] In SvelteKit 1.x you had to
throw
the error yourself
重定向(Redirects)
¥Redirects
要重定向用户,请使用 @sveltejs/kit
中的 redirect
助手来指定应将他们重定向到的位置以及 3xx
状态代码。与 error(...)
一样,调用 redirect(...)
将引发异常,从而可以轻松地从辅助函数内部停止执行。
¥To redirect users, use the redirect
helper from @sveltejs/kit
to specify the location to which they should be redirected alongside a 3xx
status code. Like error(...)
, calling redirect(...)
will throw an exception, making it easy to stop execution from inside helper functions.
import { function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): never
Redirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you’re not catching the thrown redirect, which would prevent SvelteKit from handling it.
redirect } from '@sveltejs/kit';
/** @type {import('./$types').LayoutServerLoad} */
export function function load(event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>): MaybePromise<void | Record<string, any>>
load({ locals: App.Locals
Contains custom data that was added to the request within the server handle hook
.
locals }) {
if (!locals: App.Locals
Contains custom data that was added to the request within the server handle hook
.
locals.App.Locals.user?: {
name: string;
} | undefined
user) {
function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): never
Redirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you’re not catching the thrown redirect, which would prevent SvelteKit from handling it.
redirect(307, '/login');
}
}
import { function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): never
Redirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you’re not catching the thrown redirect, which would prevent SvelteKit from handling it.
redirect } from '@sveltejs/kit';
import type { type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutServerLoad } from './$types';
export const const load: LayoutServerLoad
load: type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutServerLoad = ({ locals: App.Locals
Contains custom data that was added to the request within the server handle hook
.
locals }) => {
if (!locals: App.Locals
Contains custom data that was added to the request within the server handle hook
.
locals.App.Locals.user?: {
name: string;
} | undefined
user) {
function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): never
Redirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you’re not catching the thrown redirect, which would prevent SvelteKit from handling it.
redirect(307, '/login');
}
};
不要在
try {...}
块内使用redirect()
,因为重定向将立即触发 catch 语句。¥[!NOTE] Don’t use
redirect()
inside atry {...}
block, as the redirect will immediately trigger the catch statement.
在浏览器中,你还可以使用 $app.navigation
中的 goto
以编程方式在 load
函数之外导航。
¥In the browser, you can also navigate programmatically outside of a load
function using goto
from $app.navigation
.
在 SvelteKit 1.x 中 你必须自己
throw
redirect
¥[!NOTE] In SvelteKit 1.x you had to
throw
theredirect
yourself
使用 promise 进行流式传输(Streaming with promises)
¥Streaming with promises
使用服务器 load
时,promise 将在解析时流式传输到浏览器。如果你拥有缓慢、非必要的数据,这将非常有用,因为你可以在所有数据可用之前开始渲染页面:
¥When using a server load
, promises will be streamed to the browser as they resolve. This is useful if you have slow, non-essential data, since you can start rendering the page before all the data is available:
/** @type {import('./$types').PageServerLoad} */
export async function function load(event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>): MaybePromise<void | Record<string, any>>
load({ params: Record<string, any>
The parameters of the current route - e.g. for a route like /blog/[slug]
, a { slug: string }
object
params }) {
return {
// make sure the `await` happens at the end, otherwise we
// can't start loading comments until we've loaded the post
comments: Promise<{
content: string;
}>
comments: const loadComments: (slug: string) => Promise<{
content: string;
}>
loadComments(params: Record<string, any>
The parameters of the current route - e.g. for a route like /blog/[slug]
, a { slug: string }
object
params.slug),
post: {
title: string;
content: string;
}
post: await const loadPost: (slug: string) => Promise<{
title: string;
content: string;
}>
loadPost(params: Record<string, any>
The parameters of the current route - e.g. for a route like /blog/[slug]
, a { slug: string }
object
params.slug)
};
}
import type { type PageServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageServerLoad } from './$types';
export const const load: PageServerLoad
load: type PageServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageServerLoad = async ({ params: Record<string, any>
The parameters of the current route - e.g. for a route like /blog/[slug]
, a { slug: string }
object
params }) => {
return {
// make sure the `await` happens at the end, otherwise we
// can't start loading comments until we've loaded the post
comments: Promise<{
content: string;
}>
comments: const loadComments: (slug: string) => Promise<{
content: string;
}>
loadComments(params: Record<string, any>
The parameters of the current route - e.g. for a route like /blog/[slug]
, a { slug: string }
object
params.slug),
post: {
title: string;
content: string;
}
post: await const loadPost: (slug: string) => Promise<{
title: string;
content: string;
}>
loadPost(params: Record<string, any>
The parameters of the current route - e.g. for a route like /blog/[slug]
, a { slug: string }
object
params.slug)
};
};
这对于创建骨架加载状态很有用,例如:
¥This is useful for creating skeleton loading states, for example:
<script>
/** @type {import('./$types').PageProps} */
let { data } = $props();
</script>
<h1>{data.post.title}</h1>
<div>{@html data.post.content}</div>
{#await data.comments}
Loading comments...
{:then comments}
{#each comments as comment}
<p>{comment.content}</p>
{/each}
{:catch error}
<p>error loading comments: {error.message}</p>
{/await}
<script lang="ts">
import type { PageProps } from './$types';
let { data }: PageProps = $props();
</script>
<h1>{data.post.title}</h1>
<div>{@html data.post.content}</div>
{#await data.comments}
Loading comments...
{:then comments}
{#each comments as comment}
<p>{comment.content}</p>
{/each}
{:catch error}
<p>error loading comments: {error.message}</p>
{/await}
当流式传输数据时,请小心正确处理 promise 拒绝。更具体地说,如果延迟加载的 promise 在渲染开始之前失败(此时它会被捕获)并且没有以某种方式处理错误,则服务器可能会因 “未处理的 promise 拒绝” 错误而崩溃。当在 load
函数中直接使用 SvelteKit 的 fetch
时,SvelteKit 将为你处理这种情况。对于其他 promise,将 noop-catch
附加到 promise 以将其标记为已处理就足够了。
¥When streaming data, be careful to handle promise rejections correctly. More specifically, the server could crash with an “unhandled promise rejection” error if a lazy-loaded promise fails before rendering starts (at which point it’s caught) and isn’t handling the error in some way. When using SvelteKit’s fetch
directly in the load
function, SvelteKit will handle this case for you. For other promises, it is enough to attach a noop-catch
to the promise to mark it as handled.
/** @type {import('./$types').PageServerLoad} */
export function function load({ fetch }: {
fetch: any;
}): {
ok_manual: Promise<never>;
ok_fetch: any;
dangerous_unhandled: Promise<never>;
}
load({ fetch: any
fetch }) {
const const ok_manual: Promise<never>
ok_manual = var Promise: PromiseConstructor
Represents the completion of an asynchronous operation
Promise.PromiseConstructor.reject<never>(reason?: any): Promise<never>
Creates a new rejected promise for the provided reason.
reject();
const ok_manual: Promise<never>
ok_manual.Promise<never>.catch<void>(onrejected?: ((reason: any) => void | PromiseLike<void>) | null | undefined): Promise<void>
Attaches a callback for only the rejection of the Promise.
catch(() => {});
return {
ok_manual: Promise<never>
ok_manual,
ok_fetch: any
ok_fetch: fetch: any
fetch('/fetch/that/could/fail'),
dangerous_unhandled: Promise<never>
dangerous_unhandled: var Promise: PromiseConstructor
Represents the completion of an asynchronous operation
Promise.PromiseConstructor.reject<never>(reason?: any): Promise<never>
Creates a new rejected promise for the provided reason.
reject()
};
}
import type { type PageServerLoad = (event: Kit.ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageServerLoad = (event: Kit.ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageServerLoad } from './$types';
export const const load: PageServerLoad
load: type PageServerLoad = (event: Kit.ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageServerLoad = (event: Kit.ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageServerLoad = ({ fetch: {
(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
(input: string | URL | globalThis.Request, init?: RequestInit): Promise<Response>;
}
fetch
is equivalent to the native fetch
web API, with a few additional features:
- It can be used to make credentialed requests on the server, as it inherits the
cookie
and authorization
headers for the page request.
- It can make relative requests on the server (ordinarily,
fetch
requires a URL with an origin when used in a server context).
- Internal requests (e.g. for
+server.js
routes) go directly to the handler function when running on the server, without the overhead of an HTTP call.
- During server-side rendering, the response will be captured and inlined into the rendered HTML by hooking into the
text
and json
methods of the Response
object. Note that headers will not be serialized, unless explicitly included via filterSerializedResponseHeaders
- During hydration, the response will be read from the HTML, guaranteeing consistency and preventing an additional network request.
You can learn more about making credentialed requests with cookies here
fetch }) => {
const const ok_manual: Promise<never>
ok_manual = var Promise: PromiseConstructor
Represents the completion of an asynchronous operation
Promise.PromiseConstructor.reject<never>(reason?: any): Promise<never>
Creates a new rejected promise for the provided reason.
reject();
const ok_manual: Promise<never>
ok_manual.Promise<never>.catch<void>(onrejected?: ((reason: any) => void | PromiseLike<void>) | null | undefined): Promise<void>
Attaches a callback for only the rejection of the Promise.
catch(() => {});
return {
ok_manual: Promise<never>
ok_manual,
ok_fetch: Promise<Response>
ok_fetch: fetch: (input: string | URL | globalThis.Request, init?: RequestInit) => Promise<Response> (+1 overload)
fetch('/fetch/that/could/fail'),
dangerous_unhandled: Promise<never>
dangerous_unhandled: var Promise: PromiseConstructor
Represents the completion of an asynchronous operation
Promise.PromiseConstructor.reject<never>(reason?: any): Promise<never>
Creates a new rejected promise for the provided reason.
reject()
};
};
在 AWS Lambda 或 Firebase 等不支持流式传输的平台上,响应将被缓冲。这意味着页面只有在所有 promise 都解决后才会渲染。如果你使用的是代理(例如 NGINX),请确保它不会缓冲来自代理服务器的响应。
¥[!NOTE] On platforms that do not support streaming, such as AWS Lambda or Firebase, responses will be buffered. This means the page will only render once all promises resolve. If you are using a proxy (e.g. NGINX), make sure it does not buffer responses from the proxied server.
流数据仅在启用 JavaScript 时才有效。如果页面是服务器渲染的,你应该避免从通用
load
函数返回 promise,因为这些 promise 不是流式传输的 - 相反,当函数在浏览器中重新运行时会重新创建 promise。¥[!NOTE] Streaming data will only work when JavaScript is enabled. You should avoid returning promises from a universal
load
function if the page is server rendered, as these are not streamed — instead, the promise is recreated when the function reruns in the browser.
一旦响应开始流式传输,响应的标头和状态代码就无法更改,因此你无法在流式传输的 promise 内
setHeaders
或抛出重定向。¥[!NOTE] The headers and status code of a response cannot be changed once the response has started streaming, therefore you cannot
setHeaders
or throw redirects inside a streamed promise.
在 SvelteKit 1.x 中 顶层 promise 被自动等待,只有嵌套 promise 被流式传输。
¥[!NOTE] In SvelteKit 1.x top-level promises were automatically awaited, only nested promises were streamed.
并行加载(Parallel loading)
¥Parallel loading
当渲染(或导航到)页面时,SvelteKit 会同时运行所有 load
函数,避免大量请求。在客户端导航期间,调用多个服务器 load
函数的结果被分组为单个响应。一旦所有 load
函数都返回,页面就会被渲染。
¥When rendering (or navigating to) a page, SvelteKit runs all load
functions concurrently, avoiding a waterfall of requests. During client-side navigation, the result of calling multiple server load
functions are grouped into a single response. Once all load
functions have returned, the page is rendered.
重新运行加载函数(Rerunning load functions)
¥Rerunning load functions
SvelteKit 跟踪每个 load
函数的依赖,以避免在导航期间不必要地重新运行它。
¥SvelteKit tracks the dependencies of each load
function to avoid rerunning it unnecessarily during navigation.
例如,给定一对这样的 load
函数...
¥For example, given a pair of load
functions like these...
import * as module "$lib/server/database"
db from '$lib/server/database';
/** @type {import('./$types').PageServerLoad} */
export async function function load(event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>): MaybePromise<void | Record<string, any>>
load({ params: Record<string, any>
The parameters of the current route - e.g. for a route like /blog/[slug]
, a { slug: string }
object
params }) {
return {
post: {
title: string;
content: string;
}
post: await module "$lib/server/database"
db.function getPost(slug: string): Promise<{
title: string;
content: string;
}>
getPost(params: Record<string, any>
The parameters of the current route - e.g. for a route like /blog/[slug]
, a { slug: string }
object
params.slug)
};
}
import * as module "$lib/server/database"
db from '$lib/server/database';
import type { type PageServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageServerLoad } from './$types';
export const const load: PageServerLoad
load: type PageServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageServerLoad = async ({ params: Record<string, any>
The parameters of the current route - e.g. for a route like /blog/[slug]
, a { slug: string }
object
params }) => {
return {
post: {
title: string;
content: string;
}
post: await module "$lib/server/database"
db.function getPost(slug: string): Promise<{
title: string;
content: string;
}>
getPost(params: Record<string, any>
The parameters of the current route - e.g. for a route like /blog/[slug]
, a { slug: string }
object
params.slug)
};
};
import * as module "$lib/server/database"
db from '$lib/server/database';
/** @type {import('./$types').LayoutServerLoad} */
export async function function load(event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>): MaybePromise<void | Record<string, any>>
load() {
return {
posts: {
title: string;
slug: string;
}[]
posts: await module "$lib/server/database"
db.function getPostSummaries(): Promise<Array<{
title: string;
slug: string;
}>>
getPostSummaries()
};
}
import * as module "$lib/server/database"
db from '$lib/server/database';
import type { type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutServerLoad } from './$types';
export const const load: LayoutServerLoad
load: type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutServerLoad = async () => {
return {
posts: {
title: string;
slug: string;
}[]
posts: await module "$lib/server/database"
db.function getPostSummaries(): Promise<Array<{
title: string;
slug: string;
}>>
getPostSummaries()
};
};
...如果我们从 /blog/trying-the-raw-meat-diet
导航到 /blog/i-regret-my-choices
,+page.server.js
中的那个将重新运行,因为 params.slug
已更改。+layout.server.js
中的那个不会,因为数据仍然有效。换句话说,我们不会第二次调用 db.getPostSummaries()
。
¥...the one in +page.server.js
will rerun if we navigate from /blog/trying-the-raw-meat-diet
to /blog/i-regret-my-choices
because params.slug
has changed. The one in +layout.server.js
will not, because the data is still valid. In other words, we won’t call db.getPostSummaries()
a second time.
如果父 load
函数重新运行,调用 await parent()
的 load
函数也会重新运行。
¥A load
function that calls await parent()
will also rerun if a parent load
function is rerun.
load
函数返回后,依赖跟踪不适用 - 例如,在嵌套的 promise 中访问 params.x
不会导致函数在 params.x
更改时重新运行。(别担心,如果你不小心这样做了,你会在开发中收到警告。)相反,在 load
函数的主体中访问参数。
¥Dependency tracking does not apply after the load
function has returned — for example, accessing params.x
inside a nested promise will not cause the function to rerun when params.x
changes. (Don’t worry, you’ll get a warning in development if you accidentally do this.) Instead, access the parameter in the main body of your load
function.
搜索参数独立于其余 URL 进行跟踪。例如,在 load
函数内访问 event.url.searchParams.get("x")
将使 load
函数在从 ?x=1
导航到 ?x=2
时重新运行,但从 ?x=1&y=1
导航到 ?x=1&y=2
时不会重新运行。
¥Search parameters are tracked independently from the rest of the url. For example, accessing event.url.searchParams.get("x")
inside a load
function will make that load
function re-run when navigating from ?x=1
to ?x=2
, but not when navigating from ?x=1&y=1
to ?x=1&y=2
.
取消跟踪依赖(Untracking dependencies)
¥Untracking dependencies
在极少数情况下,你可能希望从依赖跟踪机制中排除某些内容。你可以使用提供的 untrack
函数执行此操作:
¥In rare cases, you may wish to exclude something from the dependency tracking mechanism. You can do this with the provided untrack
function:
/** @type {import('./$types').PageLoad} */
export async function function load({ untrack, url }: {
untrack: any;
url: any;
}): Promise<{
message: string;
} | undefined>
load({ untrack: any
untrack, url: any
url }) {
// Untrack url.pathname so that path changes don't trigger a rerun
if (untrack: any
untrack(() => url: any
url.pathname === '/')) {
return { message: string
message: 'Welcome!' };
}
}
import type { type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad } from './$types';
export const const load: PageLoad
load: type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad = async ({ untrack: <T>(fn: () => T) => T
Use this function to opt out of dependency tracking for everything that is synchronously called within the callback. Example:
src/routes/+page.serverexport async function load({ untrack, url }) {
// Untrack url.pathname so that path changes don't trigger a rerun
if (untrack(() => url.pathname === '/')) {
return { message: 'Welcome!' };
}
}
untrack, url: URL
The URL of the current page
url }) => {
// Untrack url.pathname so that path changes don't trigger a rerun
if (untrack: <boolean>(fn: () => boolean) => boolean
Use this function to opt out of dependency tracking for everything that is synchronously called within the callback. Example:
src/routes/+page.serverexport async function load({ untrack, url }) {
// Untrack url.pathname so that path changes don't trigger a rerun
if (untrack(() => url.pathname === '/')) {
return { message: 'Welcome!' };
}
}
untrack(() => url: URL
The URL of the current page
url.URL.pathname: string
pathname === '/')) {
return { message: string
message: 'Welcome!' };
}
};
手动失效(Manual invalidation)
¥Manual invalidation
你还可以使用 invalidate(url)
重新运行适用于当前页面的 load
函数,这会重新运行依赖于 url
的所有 load
函数,以及 invalidateAll()
,这会重新运行每个 load
函数。服务器加载函数永远不会自动依赖于获取的 url
,以避免将密钥泄露给客户端。
¥You can also rerun load
functions that apply to the current page using invalidate(url)
, which reruns all load
functions that depend on url
, and invalidateAll()
, which reruns every load
function. Server load functions will never automatically depend on a fetched url
to avoid leaking secrets to the client.
如果 load
函数调用 fetch(url)
或 depends(url)
,则它依赖于 url
。请注意,url
可以是以 [a-z]:
开头的自定义标识符:
¥A load
function depends on url
if it calls fetch(url)
or depends(url)
. Note that url
can be a custom identifier that starts with [a-z]:
:
/** @type {import('./$types').PageLoad} */
export async function function load({ fetch, depends }: {
fetch: any;
depends: any;
}): Promise<{
number: any;
}>
load({ fetch: any
fetch, depends: any
depends }) {
// load reruns when `invalidate('https://api.example.com/random-number')` is called...
const const response: any
response = await fetch: any
fetch('https://api.example.com/random-number');
// ...or when `invalidate('app:random')` is called
depends: any
depends('app:random');
return {
number: any
number: await const response: any
response.json()
};
}
import type { type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad } from './$types';
export const const load: PageLoad
load: type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad = async ({ fetch: {
(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
(input: string | URL | globalThis.Request, init?: RequestInit): Promise<Response>;
}
fetch
is equivalent to the native fetch
web API, with a few additional features:
- It can be used to make credentialed requests on the server, as it inherits the
cookie
and authorization
headers for the page request.
- It can make relative requests on the server (ordinarily,
fetch
requires a URL with an origin when used in a server context).
- Internal requests (e.g. for
+server.js
routes) go directly to the handler function when running on the server, without the overhead of an HTTP call.
- During server-side rendering, the response will be captured and inlined into the rendered HTML by hooking into the
text
and json
methods of the Response
object. Note that headers will not be serialized, unless explicitly included via filterSerializedResponseHeaders
- During hydration, the response will be read from the HTML, guaranteeing consistency and preventing an additional network request.
You can learn more about making credentialed requests with cookies here
fetch, depends: (...deps: Array<`${string}:${string}`>) => void
This function declares that the load
function has a dependency on one or more URLs or custom identifiers, which can subsequently be used with invalidate()
to cause load
to rerun.
Most of the time you won’t need this, as fetch
calls depends
on your behalf — it’s only necessary if you’re using a custom API client that bypasses fetch
.
URLs can be absolute or relative to the page being loaded, and must be encoded.
Custom identifiers have to be prefixed with one or more lowercase letters followed by a colon to conform to the URI specification.
The following example shows how to use depends
to register a dependency on a custom identifier, which is invalidate
d after a button click, making the load
function rerun.
src/routes/+pagelet count = 0;
export async function load({ depends }) {
depends('increase:count');
return { count: count++ };
}
src/routes/+page<script>
import { invalidate } from '$app/navigation';
let { data } = $props();
const increase = async () => {
await invalidate('increase:count');
}
</script>
<p>{data.count}<p>
<button on:click={increase}>Increase Count</button>
depends }) => {
// load reruns when `invalidate('https://api.example.com/random-number')` is called...
const const response: Response
response = await fetch: (input: string | URL | globalThis.Request, init?: RequestInit) => Promise<Response> (+1 overload)
fetch('https://api.example.com/random-number');
// ...or when `invalidate('app:random')` is called
depends: (...deps: Array<`${string}:${string}`>) => void
This function declares that the load
function has a dependency on one or more URLs or custom identifiers, which can subsequently be used with invalidate()
to cause load
to rerun.
Most of the time you won’t need this, as fetch
calls depends
on your behalf — it’s only necessary if you’re using a custom API client that bypasses fetch
.
URLs can be absolute or relative to the page being loaded, and must be encoded.
Custom identifiers have to be prefixed with one or more lowercase letters followed by a colon to conform to the URI specification.
The following example shows how to use depends
to register a dependency on a custom identifier, which is invalidate
d after a button click, making the load
function rerun.
src/routes/+pagelet count = 0;
export async function load({ depends }) {
depends('increase:count');
return { count: count++ };
}
src/routes/+page<script>
import { invalidate } from '$app/navigation';
let { data } = $props();
const increase = async () => {
await invalidate('increase:count');
}
</script>
<p>{data.count}<p>
<button on:click={increase}>Increase Count</button>
depends('app:random');
return {
number: any
number: await const response: Response
response.Body.json(): Promise<any>
json()
};
};
<script>
import { invalidate, invalidateAll } from '$app/navigation';
/** @type {import('./$types').PageProps} */
let { data } = $props();
function rerunLoadFunction() {
// any of these will cause the `load` function to rerun
invalidate('app:random');
invalidate('https://api.example.com/random-number');
invalidate(url => url.href.includes('random-number'));
invalidateAll();
}
</script>
<p>random number: {data.number}</p>
<button onclick={rerunLoadFunction}>Update random number</button>
<script lang="ts">
import { invalidate, invalidateAll } from '$app/navigation';
import type { PageProps } from './$types';
let { data }: PageProps = $props();
function rerunLoadFunction() {
// any of these will cause the `load` function to rerun
invalidate('app:random');
invalidate('https://api.example.com/random-number');
invalidate(url => url.href.includes('random-number'));
invalidateAll();
}
</script>
<p>random number: {data.number}</p>
<button onclick={rerunLoadFunction}>Update random number</button>
加载函数何时重新运行?(When do load functions rerun?)
¥When do load functions rerun?
总而言之,load
函数将在以下情况下重新运行:
¥To summarize, a load
function will rerun in the following situations:
它引用
params
的属性,其值已更改¥It references a property of
params
whose value has changed它引用
url
的属性(例如url.pathname
或url.search
),其值已更改。request.url
中的属性未被跟踪¥It references a property of
url
(such asurl.pathname
orurl.search
) whose value has changed. Properties inrequest.url
are not tracked它调用
url.searchParams.get(...)
、url.searchParams.getAll(...)
或url.searchParams.has(...)
,并且相关参数会发生变化。访问url.searchParams
的其他属性将具有与访问url.search
相同的效果。¥It calls
url.searchParams.get(...)
,url.searchParams.getAll(...)
orurl.searchParams.has(...)
and the parameter in question changes. Accessing other properties ofurl.searchParams
will have the same effect as accessingurl.search
.它调用
await parent()
并重新运行父load
函数¥It calls
await parent()
and a parentload
function reran子
load
函数调用await parent()
并重新运行,父函数是服务器加载函数¥A child
load
function callsawait parent()
and is rerunning, and the parent is a server load function它通过
fetch
(仅通用加载)或depends
声明对特定 URL 的依赖,并且该 URL 被invalidate(url)
标记为无效¥It declared a dependency on a specific URL via
fetch
(universal load only) ordepends
, and that URL was marked invalid withinvalidate(url)
所有活动的
load
函数都强制使用invalidateAll()
重新运行¥All active
load
functions were forcibly rerun withinvalidateAll()
params
和 url
可以响应 <a href="..">
链接点击、<form>
交互、goto
调用或 redirect
而改变。
¥params
and url
can change in response to a <a href="..">
link click, a <form>
interaction, a goto
invocation, or a redirect
.
请注意,重新运行 load
函数将更新相应 +layout.svelte
或 +page.svelte
内的 data
prop;不会导致重新创建组件。因此,内部状态得以保留。如果这不是你想要的,你可以在 afterNavigate
回调中重置你需要重置的任何内容,和/或将你的组件封装在 {#key ...}
块中。
¥Note that rerunning a load
function will update the data
prop inside the corresponding +layout.svelte
or +page.svelte
; it does not cause the component to be recreated. As a result, internal state is preserved. If this isn’t what you want, you can reset whatever you need to reset inside an afterNavigate
callback, and/or wrap your component in a {#key ...}
block.
身份验证的含义(Implications for authentication)
¥Implications for authentication
加载数据的几个功能对身份验证检查具有重要影响:
¥A couple features of loading data have important implications for auth checks:
Layout
load
函数不会在每个请求上运行,例如在子路由之间的客户端导航期间。(何时执行加载函数重新运行?)¥Layout
load
functions do not run on every request, such as during client side navigation between child routes. (When do load functions rerun?)除非调用
await parent()
,否则布局和页面load
函数会同时运行。如果布局load
抛出,页面load
函数将运行,但客户端不会收到返回的数据。¥Layout and page
load
functions run concurrently unlessawait parent()
is called. If a layoutload
throws, the pageload
function runs, but the client will not receive the returned data.
有几种可能的策略可以确保在受保护的代码之前进行身份验证检查。
¥There are a few possible strategies to ensure an auth check occurs before protected code.
为了防止数据瀑布并保留布局 load
缓存:
¥To prevent data waterfalls and preserve layout load
caches:
在运行任何
load
函数之前,使用 hooks 保护多条路由¥Use hooks to protect multiple routes before any
load
functions run在
+page.server.js
load
函数中直接使用身份验证保护器进行特定路由保护¥Use auth guards directly in
+page.server.js
load
functions for route specific protection
在 +layout.server.js
中放置身份验证保护需要所有子页面在受保护的代码之前调用 await parent()
。除非每个子页面都依赖于从 await parent()
返回的数据,否则其他选项的性能会更高。
¥Putting an auth guard in +layout.server.js
requires all child pages to call await parent()
before protected code. Unless every child page depends on returned data from await parent()
, the other options will be more performant.
进一步阅读(Further reading)
¥Further reading