常見問題
其他資源
請參閱 Svelte 常見問題 和 vite-plugin-svelte
常見問題,以取得來自這些程式庫的問題解答。
我可以使用 SvelteKit 製作什麼?
SvelteKit 可用於建立大多數類型的應用程式。SvelteKit 開箱即支援許多功能,包括:
- 使用 load 函式和 API 路由 的動態頁面內容。
- 使用 伺服器端渲染 (SSR) 的 SEO 友善的動態內容。
- 使用 SSR 和 表單動作 的使用者友善的漸進式增強互動頁面。
- 使用 預先渲染 的靜態頁面。
SvelteKit 也可以透過 轉接器 部署到各種託管架構。在使用 SSR 的情況下(或在不預先渲染的情況下新增伺服器端邏輯),這些函式將會調整為目標後端。一些範例包括:
- 使用 Node.js 後端 的自託管動態網路應用程式。
- 使用後端載入器和部署為遠端函式的 API 的無伺服器網路應用程式。請參閱 零配置部署,以了解熱門的部署選項。
- 靜態預先渲染網站,例如託管在 CDN 或靜態主機上的部落格或多頁網站。靜態產生的網站會在沒有後端的情況下出貨。
- 具有用於 API 驅動的動態內容的客戶端路由和渲染的 單頁應用程式 (SPA)。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
欄位可能不向下相容,因為它會阻止深層匯入。- 除非設定了
"type": "module"
,否則 ESM 檔案應以.mjs
結尾,在這種情況下,CommonJS 檔案應以.cjs
結尾。 - 如果沒有
exports
,則應該定義main
。它應該是 CommonJS 或 ESM 檔案,並遵守前一點。如果定義了module
欄位,則它應該參照 ESM 檔案。 - Svelte 元件應以未編譯的
.svelte
檔案散佈,且套件中的任何 JS 都應僅寫為 ESM。自訂腳本和樣式語言(例如 TypeScript 和 SCSS)應分別預處理為 vanilla JS 和 CSS。我們建議使用svelte-package
來封裝 Svelte 程式庫,這將為您執行此操作。
當程式庫散佈 ESM 版本時,它們在瀏覽器中與 Vite 搭配使用效果最佳,特別是如果它們是 Svelte 元件程式庫的相依性。您可能希望建議程式庫作者提供 ESM 版本。但是,CommonJS (CJS) 相依性也應該有效,因為依預設,vite-plugin-svelte
會要求 Vite 使用 esbuild
將它們預先捆綁,以將它們轉換為 ESM。
如果您仍然遇到問題,我們建議搜尋 Vite 問題追蹤器 和相關程式庫的問題追蹤器。有時,可以透過調整 optimizeDeps
或 ssr
配置值來解決問題,儘管我們建議這僅作為短期解決方法,而不是修正相關程式庫。
如何在 SvelteKit 中使用視圖轉換 API?
雖然 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 部落格上的 「解鎖視圖轉換」。
如何在 SvelteKit 中使用 X?
請確定您已閱讀 關於整合的文件章節。如果您仍然遇到問題,以下列出常見問題的解決方案。
如何設定資料庫?
將查詢資料庫的程式碼放入 伺服器路由 中 - 請勿在 .svelte 檔案中查詢資料庫。您可以建立一個 db.js
或類似的檔案,立即設定連線,並使客戶端在整個應用程式中作為單例可存取。您可以在 hooks.server.js
中執行任何一次性設定程式碼,並將您的資料庫輔助程式匯入任何需要它們的端點。
如何使用依賴文件或視窗的僅限客戶端程式庫?
如果您需要存取 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 out,其中 onMount
將自動被 no-op 取代
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
非常有用。
另一種方法是設定 Proxy 來繞過 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 的最佳方式。