跳至主要內容

常見問題

其他資源

請參閱 Svelte 常見問題vite-plugin-svelte 常見問題,以取得來自這些程式庫的問題解答。

我可以使用 SvelteKit 製作什麼?

SvelteKit 可用於建立大多數類型的應用程式。SvelteKit 開箱即支援許多功能,包括:

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:

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 欄位可能不向下相容,因為它會阻止深層匯入。
  • 除非設定了 "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 問題追蹤器 和相關程式庫的問題追蹤器。有時,可以透過調整 optimizeDepsssr 配置值來解決問題,儘管我們建議這僅作為短期解決方法,而不是修正相關程式庫。

如何在 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: 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 部落格上的 「解鎖視圖轉換」

如何在 SvelteKit 中使用 X?

請確定您已閱讀 關於整合的文件章節。如果您仍然遇到問題,以下列出常見問題的解決方案。

如何設定資料庫?

將查詢資料庫的程式碼放入 伺服器路由 中 - 請勿在 .svelte 檔案中查詢資料庫。您可以建立一個 db.js 或類似的檔案,立即設定連線,並使客戶端在整個應用程式中作為單例可存取。您可以在 hooks.server.js 中執行任何一次性設定程式碼,並將您的資料庫輔助程式匯入任何需要它們的端點。

如何使用依賴文件或視窗的僅限客戶端程式庫?

如果您需要存取 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 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 路由

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 上編輯此頁面

上一頁 下一頁