常见问题
其他资源
请参阅Svelte 常见问题解答和vite-plugin-svelte
常见问题解答,以获取有关这些库衍生问题的答案。
我可以用 SvelteKit 制作什么?
SvelteKit 可用于创建大多数类型的应用程序。SvelteKit 开箱即用地支持许多功能,包括
- 使用load 函数和API 路由 的动态页面内容。
- 使用服务器端渲染 (SSR) 的 SEO 友好型动态内容。
- 使用 SSR 和表单操作 的用户友好的渐进增强型交互式页面。
- 使用预渲染 的静态页面。
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
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>
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)
fileURLToPath } from 'node:url';
const const path: string
path = 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)
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 urlObject
s,
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
.
URL('package.json', import.meta.ImportMeta.url: string
The absolute file:
URL of the module.
url));
const const pkg: any
pkg = 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.
parse(function readFileSync(path: PathOrFileDescriptor, options: {
encoding: BufferEncoding;
flag?: string | undefined;
} | BufferEncoding): string (+2 overloads)
Synchronously reads the entire contents of a file.
readFileSync(const path: string
path, 'utf8'));
如何修复我在尝试包含包时遇到的错误?
大多数与包含库相关的问题是由于打包不正确造成的。您可以通过将其输入publint 网站来检查库的打包是否与 Node.js 兼容。
以下是在检查库是否正确打包时需要牢记的一些事项
exports
优先于其他入口点字段,例如main
和module
。添加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 问题跟踪器和相关库的问题跟踪器。有时可以通过调整optimizeDeps
或ssr
配置值来解决问题,尽管我们建议将其仅作为短期解决方法,以支持修复相关库。
如何将视图转换 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: OnNavigate
navigation) => {
if (!var document: Document
document.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.
Promise((resolve: (value: void | (() => void) | PromiseLike<void | (() => void)>) => void
resolve) => {
var document: Document
document.startViewTransition(async () => {
resolve: (value: void | (() => void) | PromiseLike<void | (() => void)>) => void
resolve();
await navigation: OnNavigate
navigation.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 的仅客户端库?
如果您需要访问document
或window
变量或以其他方式需要仅在客户端运行的代码,则可以将其包装在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: any
method } = await import('some-browser-only-library');
const method: any
method('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 路由
/** @type {import('./$types').RequestHandler} */
export function function GET({ params, url }: {
params: any;
url: any;
}): Promise<Response>
GET({ params: any
params, url: any
url }) {
return function fetch(input: string | URL | globalThis.Request, init?: RequestInit): Promise<Response> (+1 overload)
fetch(`https://my-api-server.com/${params: any
params.path + url: any
url.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: RequestHandler
GET: 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: string
search}`);
};
(请注意,您可能还需要代理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>
myPlugin = {
OutputPlugin.name: string
name: '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: ViteDevServer
server) {
server: ViteDevServer
server.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
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.IncomingMessage
req, res: ServerResponse<IncomingMessage>
res, next: Connect.NextFunction
next) => {
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(`Got request ${req: Connect.IncomingMessage
req.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.
url}`);
next: (err?: any) => void
next();
});
}
};
/** @type {import('vite').UserConfig} */
const const config: UserConfig
config = {
UserConfig.plugins?: PluginOption[] | undefined
Array of vite plugins to use.
plugins: [const myPlugin: Plugin<any>
myPlugin, module "@sveltejs/kit/vite"
sveltekit()]
};
export default const config: 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 的最佳选择。