跳至主要内容

常见问题

其他资源

请参阅Svelte 常见问题解答vite-plugin-svelte 常见问题解答,以获取有关这些库衍生问题的答案。

我可以用 SvelteKit 制作什么?

SvelteKit 可用于创建大多数类型的应用程序。SvelteKit 开箱即用地支持许多功能,包括

SvelteKit 还可以通过适配器 部署到各种托管架构。在使用 SSR(或在没有预渲染的情况下添加服务器端逻辑)的情况下,这些函数将适应目标后端。一些示例包括

  • 具有Node.js 后端 的自托管动态 Web 应用程序。
  • 将后端加载程序和 API 部署为远程函数的无服务器 Web 应用程序。有关流行的部署选项,请参阅零配置部署
  • 静态预渲染网站,例如托管在 CDN 或静态主机上的博客或多页网站。静态生成的网站无需后端即可交付。
  • 单页应用程序 (SPA),具有客户端路由和渲染功能,用于 API 驱动的动态内容。SPA 无需后端即可交付,并且不会进行服务器端渲染。当将 SvelteKit 与用 PHP、.Net、Java、C、Golang、Rust 等编写的应用程序捆绑在一起时,通常会选择此选项。
  • 以上内容的混合;某些路由可以是静态的,而某些路由可以使用后端函数来获取动态信息。这可以通过包含选择退出 SSR 选项的页面选项 进行配置。

为了支持 SSR,需要一个 JS 后端——例如 Node.js 或基于 Deno 的服务器、无服务器函数或边缘函数。

还可以编写自定义适配器或利用社区适配器将 SvelteKit 部署到更多平台,例如专门的服务器环境、浏览器扩展或原生应用程序。有关更多示例和集成,请参阅集成

如何在我的应用程序中包含来自 package.json 的详细信息?

您不能直接需要 JSON 文件,因为 SvelteKit 预期svelte.config.js 是一个 ES 模块。如果您想在应用程序中包含应用程序的版本号或来自package.json 的其他信息,您可以像这样加载 JSON

svelte.config
import { 
function readFileSync(path: PathOrFileDescriptor, options?: {
    encoding?: null | undefined;
    flag?: string | undefined;
} | null): Buffer (+2 overloads)

Returns the contents of the path.

For detailed information, see the documentation of the asynchronous version of this API: {@link readFile } .

If the encoding option is specified then this function returns a string. Otherwise it returns a buffer.

Similar to {@link readFile } , when the path is a directory, the behavior of fs.readFileSync() is platform-specific.

import { readFileSync } from 'node:fs';

// macOS, Linux, and Windows
readFileSync('<directory>');
// => [Error: EISDIR: illegal operation on a directory, read <directory>]

//  FreeBSD
readFileSync('<directory>'); // => <data>
@sincev0.1.8
@parampath filename or file descriptor
readFileSync
} from 'node:fs';
import { function fileURLToPath(url: string | URL, options?: FileUrlToPathOptions): string

This function ensures the correct decodings of percent-encoded characters as well as ensuring a cross-platform valid absolute path string.

import { fileURLToPath } from 'node:url';

const __filename = fileURLToPath(import.meta.url);

new URL('file:///C:/path/').pathname;      // Incorrect: /C:/path/
fileURLToPath('file:///C:/path/');// Correct:   C:\path\ (Windows)

new URL('file://nas/foo.txt').pathname;    // Incorrect: /foo.txt
fileURLToPath('file://nas/foo.txt');       // Correct:   \\nas\foo.txt (Windows)

new URL('file:///你好.txt').pathname;      // Incorrect: /%E4%BD%A0%E5%A5%BD.txt
fileURLToPath('file:///你好.txt');// Correct:   /你好.txt (POSIX)

new URL('file:///hello world').pathname;   // Incorrect: /hello%20world
fileURLToPath('file:///hello world');      // Correct:   /hello world (POSIX)
@sincev10.12.0
@paramurl The file URL string or URL object to convert to a path.
@returnThe fully-resolved platform-specific Node.js file path.
fileURLToPath
} from 'node:url';
const const path: stringpath = function fileURLToPath(url: string | URL, options?: FileUrlToPathOptions): string

This function ensures the correct decodings of percent-encoded characters as well as ensuring a cross-platform valid absolute path string.

import { fileURLToPath } from 'node:url';

const __filename = fileURLToPath(import.meta.url);

new URL('file:///C:/path/').pathname;      // Incorrect: /C:/path/
fileURLToPath('file:///C:/path/');// Correct:   C:\path\ (Windows)

new URL('file://nas/foo.txt').pathname;    // Incorrect: /foo.txt
fileURLToPath('file://nas/foo.txt');       // Correct:   \\nas\foo.txt (Windows)

new URL('file:///你好.txt').pathname;      // Incorrect: /%E4%BD%A0%E5%A5%BD.txt
fileURLToPath('file:///你好.txt');// Correct:   /你好.txt (POSIX)

new URL('file:///hello world').pathname;   // Incorrect: /hello%20world
fileURLToPath('file:///hello world');      // Correct:   /hello world (POSIX)
@sincev10.12.0
@paramurl The file URL string or URL object to convert to a path.
@returnThe fully-resolved platform-specific Node.js file path.
fileURLToPath
(new
new URL(input: string | {
    toString: () => string;
}, base?: string | URL): URL

Browser-compatible URL class, implemented by following the WHATWG URL Standard. Examples of parsed URLs may be found in the Standard itself. The URL class is also available on the global object.

In accordance with browser conventions, all properties of URL objects are implemented as getters and setters on the class prototype, rather than as data properties on the object itself. Thus, unlike legacy urlObjects, using the delete keyword on any properties of URL objects (e.g. delete myURL.protocol, delete myURL.pathname, etc) has no effect but will still return true.

@sincev7.0.0, v6.13.0
URL
('package.json', import.meta.ImportMeta.url: string

The absolute file: URL of the module.

url
));
const const pkg: anypkg = var JSON: JSON

An intrinsic object that provides functions to convert JavaScript values to and from the JavaScript Object Notation (JSON) format.

JSON
.JSON.parse(text: string, reviver?: (this: any, key: string, value: any) => any): any

Converts a JavaScript Object Notation (JSON) string into an object.

@paramtext A valid JSON string.
@paramreviver A function that transforms the results. This function is called for each member of the object. If a member contains nested objects, the nested objects are transformed before the parent object is.
parse
(
function readFileSync(path: PathOrFileDescriptor, options: {
    encoding: BufferEncoding;
    flag?: string | undefined;
} | BufferEncoding): string (+2 overloads)

Synchronously reads the entire contents of a file.

@parampath A path to a file. If a URL is provided, it must use the file: protocol. If a file descriptor is provided, the underlying file will not be closed automatically.
@paramoptions Either the encoding for the result, or an object that contains the encoding and an optional flag. If a flag is not provided, it defaults to 'r'.
readFileSync
(const path: stringpath, 'utf8'));

如何修复我在尝试包含包时遇到的错误?

大多数与包含库相关的问题是由于打包不正确造成的。您可以通过将其输入publint 网站来检查库的打包是否与 Node.js 兼容。

以下是在检查库是否正确打包时需要牢记的一些事项

  • exports 优先于其他入口点字段,例如mainmodule。添加exports 字段可能不向后兼容,因为它会阻止深度导入。
  • ESM 文件应以.mjs 结尾,除非在任何情况下都设置了"type": "module",否则 CommonJS 文件应以.cjs 结尾。
  • 如果未定义exports,则应定义main。它应该是一个 CommonJS 或 ESM 文件,并遵守前面的要点。如果定义了module 字段,它应该引用一个 ESM 文件。
  • Svelte 组件应作为未编译的.svelte 文件分发,并且包中的任何 JS 都应仅编写为 ESM。自定义脚本和样式语言(如 TypeScript 和 SCSS)应分别预处理为普通 JS 和 CSS。我们建议使用svelte-package 打包 Svelte 库,它将为您执行此操作。

当库分发 ESM 版本时,库在浏览器中与 Vite 配合使用效果最佳,尤其是在它们是 Svelte 组件库的依赖项时。您可能希望建议库作者提供 ESM 版本。但是,CommonJS (CJS) 依赖项也应该可以工作,因为默认情况下,vite-plugin-svelte 将要求 Vite 预捆绑它们 使用esbuild 将其转换为 ESM。

如果您仍然遇到问题,我们建议搜索Vite 问题跟踪器和相关库的问题跟踪器。有时可以通过调整optimizeDepsssr 配置值来解决问题,尽管我们建议将其仅作为短期解决方法,以支持修复相关库。

如何将视图转换 API 与 SvelteKit 一起使用?

虽然 SvelteKit 没有与视图转换 的任何特定集成,但您可以在onNavigate 中调用document.startViewTransition 以在每次客户端导航时触发视图转换。

import { function onNavigate(callback: (navigation: import("@sveltejs/kit").OnNavigate) => MaybePromise<void | (() => void)>): void

A lifecycle function that runs the supplied callback immediately before we navigate to a new URL except during full-page navigations.

If you return a Promise, SvelteKit will wait for it to resolve before completing the navigation. This allows you to — for example — use document.startViewTransition. Avoid promises that are slow to resolve, since navigation will appear stalled to the user.

If a function (or a Promise that resolves to a function) is returned from the callback, it will be called once the DOM has updated.

onNavigate must be called during a component initialization. It remains active as long as the component is mounted.

onNavigate
} from '$app/navigation';
function onNavigate(callback: (navigation: import("@sveltejs/kit").OnNavigate) => MaybePromise<void | (() => void)>): void

A lifecycle function that runs the supplied callback immediately before we navigate to a new URL except during full-page navigations.

If you return a Promise, SvelteKit will wait for it to resolve before completing the navigation. This allows you to — for example — use document.startViewTransition. Avoid promises that are slow to resolve, since navigation will appear stalled to the user.

If a function (or a Promise that resolves to a function) is returned from the callback, it will be called once the DOM has updated.

onNavigate must be called during a component initialization. It remains active as long as the component is mounted.

onNavigate
((navigation: OnNavigatenavigation) => {
if (!var document: Documentdocument.startViewTransition) return; return new
var Promise: PromiseConstructor
new <void | (() => void)>(executor: (resolve: (value: void | (() => void) | PromiseLike<void | (() => void)>) => void, reject: (reason?: any) => void) => void) => Promise<void | (() => void)>

Creates a new Promise.

@paramexecutor A callback used to initialize the promise. This callback is passed two arguments: a resolve callback used to resolve the promise with a value or the result of another promise, and a reject callback used to reject the promise with a provided reason or error.
Promise
((resolve: (value: void | (() => void) | PromiseLike<void | (() => void)>) => voidresolve) => {
var document: Documentdocument.startViewTransition(async () => { resolve: (value: void | (() => void) | PromiseLike<void | (() => void)>) => voidresolve(); await navigation: OnNavigatenavigation.Navigation.complete: Promise<void>

A promise that resolves once the navigation is complete, and rejects if the navigation fails or is aborted. In the case of a willUnload navigation, the promise will never resolve

complete
;
}); }); });

有关更多信息,请参阅 Svelte 博客上的“解锁视图转换”

如何将 X 与 SvelteKit 一起使用?

确保您已阅读有关集成的文档部分。如果您仍然遇到问题,下面列出了常见问题的解决方案。

如何设置数据库?

将查询数据库的代码放在服务器路由 中 - 不要在 .svelte 文件中查询数据库。您可以创建一个db.js 或类似的文件,立即设置连接并在整个应用程序中使客户端作为单例可访问。您可以在hooks.server.js 中执行任何一次性设置代码,并将数据库帮助程序导入到任何需要它们的端点中。

如何使用依赖于 document 或 window 的仅客户端库?

如果您需要访问documentwindow 变量或以其他方式需要仅在客户端运行的代码,则可以将其包装在browser 检查中

import { const browser: boolean

true if the app is running in the browser.

browser
} from '$app/environment';
if (const browser: boolean

true if the app is running in the browser.

browser
) {
// client-only code here }

如果您希望在组件首次渲染到 DOM 后运行代码,您也可以在onMount 中运行代码

import { function onMount<T>(fn: () => NotFunction<T> | Promise<NotFunction<T>> | (() => any)): void

The onMount function schedules a callback to run as soon as the component has been mounted to the DOM. It must be called during the component’s initialisation (but doesn’t need to live inside the component; it can be called from an external module).

If a function is returned synchronously from onMount, it will be called when the component is unmounted.

onMount does not run inside server-side components.

onMount
} from 'svelte';
onMount<void>(fn: () => void | (() => any) | Promise<void>): void

The onMount function schedules a callback to run as soon as the component has been mounted to the DOM. It must be called during the component’s initialisation (but doesn’t need to live inside the component; it can be called from an external module).

If a function is returned synchronously from onMount, it will be called when the component is unmounted.

onMount does not run inside server-side components.

onMount
(async () => {
const { const method: anymethod } = await import('some-browser-only-library'); const method: anymethod('hello world'); });

如果您要使用的库是无副作用的,您也可以静态导入它,它将在服务器端构建中被 tree-shaken 出去,其中onMount 将自动替换为无操作

import { function onMount<T>(fn: () => NotFunction<T> | Promise<NotFunction<T>> | (() => any)): void

The onMount function schedules a callback to run as soon as the component has been mounted to the DOM. It must be called during the component’s initialisation (but doesn’t need to live inside the component; it can be called from an external module).

If a function is returned synchronously from onMount, it will be called when the component is unmounted.

onMount does not run inside server-side components.

onMount
} from 'svelte';
import { module "some-browser-only-library"method } from 'some-browser-only-library'; onMount<void>(fn: () => void | (() => any) | Promise<void>): void

The onMount function schedules a callback to run as soon as the component has been mounted to the DOM. It must be called during the component’s initialisation (but doesn’t need to live inside the component; it can be called from an external module).

If a function is returned synchronously from onMount, it will be called when the component is unmounted.

onMount does not run inside server-side components.

onMount
(() => {
module "some-browser-only-library"method('hello world'); });

最后,您也可以考虑使用{#await}

索引
<script>
	import { browser } from '$app/environment';

	const ComponentConstructor = browser ?
		import('some-browser-only-library').then((module) => module.Component) :
		new Promise(() => {});
</script>

{#await ComponentConstructor}
	<p>Loading...</p>
{:then component}
	<svelte:component this={component} />
{:catch error}
	<p>Something went wrong: {error.message}</p>
{/await}

如何使用不同的后端 API 服务器?

您可以使用event.fetch 从外部 API 服务器请求数据,但请注意,您需要处理CORS,这将导致一些复杂情况,例如通常需要对请求进行预检,从而导致更高的延迟。由于需要额外的 DNS 查找、TLS 设置等,对单独子域的请求也可能会增加延迟。如果您希望使用此方法,您可能会发现handleFetch 有用。

另一种方法是设置代理以绕过 CORS 问题。在生产环境中,您将重写类似于/api 的路径到 API 服务器;对于本地开发,请使用 Vite 的server.proxy 选项。

如何在生产环境中设置重写将取决于您的部署平台。如果重写不可用,您可以选择添加一个API 路由

src/routes/api/[...path]/+server
/** @type {import('./$types').RequestHandler} */
export function 
function GET({ params, url }: {
    params: any;
    url: any;
}): Promise<Response>
@type{import('./$types').RequestHandler}
GET
({ params: anyparams, url: anyurl }) {
return function fetch(input: string | URL | globalThis.Request, init?: RequestInit): Promise<Response> (+1 overload)fetch(`https://my-api-server.com/${params: anyparams.path + url: anyurl.search}`); }
import type { 
type RequestHandler = (event: Kit.RequestEvent<Record<string, any>, string | null>) => MaybePromise<Response>
type RequestHandler = (event: Kit.RequestEvent<Record<string, any>, string | null>) => MaybePromise<Response>
RequestHandler
} from './$types';
export const const GET: RequestHandlerGET:
type RequestHandler = (event: Kit.RequestEvent<Record<string, any>, string | null>) => MaybePromise<Response>
type RequestHandler = (event: Kit.RequestEvent<Record<string, any>, string | null>) => MaybePromise<Response>
RequestHandler
= ({ params: Record<string, any>

The parameters of the current route - e.g. for a route like /blog/[slug], a { slug: string } object

params
, url: URL

The requested URL.

url
}) => {
return function fetch(input: string | URL | globalThis.Request, init?: RequestInit): Promise<Response> (+1 overload)fetch(`https://my-api-server.com/${params: Record<string, any>

The parameters of the current route - e.g. for a route like /blog/[slug], a { slug: string } object

params
.path + url: URL

The requested URL.

url
.URL.search: stringsearch}`);
};

(请注意,您可能还需要代理POST / PATCH 等请求,并转发request.headers,具体取决于您的需求。)

如何使用中间件?

adapter-node 构建了一个中间件,您可以将其与您自己的服务器一起用于生产模式。在开发环境中,您可以通过使用 Vite 插件将中间件添加到 Vite。例如

import { module "@sveltejs/kit/vite"sveltekit } from '@sveltejs/kit/vite';

/** @type {import('vite').Plugin} */
const const myPlugin: Plugin<any>
@type{import('vite').Plugin}
myPlugin
= {
OutputPlugin.name: stringname: 'log-request-middleware', Plugin<any>.configureServer?: ObjectHook<ServerHook> | undefined

Configure the vite server. The hook receives the {@link ViteDevServer }

instance. This can also be used to store a reference to the server for use in other hooks.

The hooks will be called before internal middlewares are applied. A hook can return a post hook that will be called after internal middlewares are applied. Hook can be async functions and will be called in series.

configureServer
(server: ViteDevServerserver) {
server: ViteDevServerserver.ViteDevServer.middlewares: Connect.Server

A connect app instance.

  • Can be used to attach custom middlewares to the dev server.
  • Can also be used as the handler function of a custom http server or as a middleware in any connect-style Node.js frameworks

https://github.com/senchalabs/connect#use-middleware

middlewares
.Connect.Server.use(fn: Connect.NextHandleFunction): Connect.Server (+3 overloads)

Utilize the given middleware handle to the given route, defaulting to /. This “route” is the mount-point for the middleware, when given a value other than / the middleware is only effective when that segment is present in the request’s pathname.

For example if we were to mount a function at /admin, it would be invoked on /admin, and /admin/settings, however it would not be invoked for /, or /posts.

use
((req: Connect.IncomingMessagereq, res: ServerResponse<IncomingMessage>res, next: Connect.NextFunctionnext) => {
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
@seesource
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.

@sincev0.1.100
log
(`Got request ${req: Connect.IncomingMessagereq.IncomingMessage.url?: string | undefined

Only valid for request obtained from {@link Server } .

Request URL string. This contains only the URL that is present in the actual HTTP request. Take the following request:

GET /status?name=ryan HTTP/1.1
Accept: text/plain

To parse the URL into its parts:

new URL(`http://${process.env.HOST ?? 'localhost'}${request.url}`);

When request.url is '/status?name=ryan' and process.env.HOST is undefined:

$ node
> new URL(`http://${process.env.HOST ?? 'localhost'}${request.url}`);
URL {
  href: 'https://127.0.0.1/status?name=ryan',
  origin: 'https://127.0.0.1',
  protocol: 'http:',
  username: '',
  password: '',
  host: 'localhost',
  hostname: 'localhost',
  port: '',
  pathname: '/status',
  search: '?name=ryan',
  searchParams: URLSearchParams { 'name' => 'ryan' },
  hash: ''
}

Ensure that you set process.env.HOST to the server’s host name, or consider replacing this part entirely. If using req.headers.host, ensure proper validation is used, as clients may specify a custom Host header.

@sincev0.1.90
url
}`);
next: (err?: any) => voidnext(); }); } }; /** @type {import('vite').UserConfig} */ const const config: UserConfig
@type{import('vite').UserConfig}
config
= {
UserConfig.plugins?: PluginOption[] | undefined

Array of vite plugins to use.

plugins
: [const myPlugin: Plugin<any>
@type{import('vite').Plugin}
myPlugin
, module "@sveltejs/kit/vite"sveltekit()]
}; export default const config: UserConfig
@type{import('vite').UserConfig}
config
;

有关更多详细信息,包括如何控制排序,请参阅Vite 的configureServer 文档

它是否支持 Yarn 2?

有点。Plug’n'Play 功能(也称为“pnp”)已损坏(它偏离了 Node 模块解析算法,并且尚不支持原生 JavaScript 模块,SvelteKit 以及越来越多的软件包 使用)。您可以在.yarnrc.yml 文件中使用nodeLinker: 'node-modules' 来禁用 pnp,但这可能更容易,只需使用 npm 或pnpm,它同样快速高效,但没有兼容性问题。

如何与 Yarn 3 一起使用?

目前,最新版 Yarn(版本 3)中的 ESM 支持被认为是实验性的。

以下方法似乎有效,但您的结果可能会有所不同。

首先创建一个新的应用程序

yarn create svelte myapp
cd myapp

并启用 Yarn Berry

yarn set version berry
yarn install

Yarn 3 全局缓存

Yarn Berry 的一个更有趣的特性是能够为包拥有一个单一的全局缓存,而不是在磁盘上为每个项目拥有多个副本。但是,将 enableGlobalCache 设置为 true 会导致构建失败,因此建议在 .yarnrc.yml 文件中添加以下内容

nodeLinker: node-modules

这将导致包被下载到本地 node_modules 目录中,但避免了上述问题,并且是目前使用 Yarn 版本 3 的最佳选择。

在 GitHub 上编辑此页面

上一页 下一页