```
# Service workers
Service Worker は、アプリ内部でネットワークリクエストを処理するプロキシサーバーとして機能します。これによりアプリをオフラインで動作させることが可能になります。もしオフラインサポートが不要な場合(または構築するアプリの種類によって現実的に実装できない場合)でも、ビルドした JS と CSS を事前にキャッシュしてナビゲーションを高速化するために Service Worker を使用する価値はあります。
In SvelteKit, if you have a `src/service-worker.js` file (or `src/service-worker/index.js`) it will be bundled and automatically registered.
service worker を独自のロジックで登録する必要がある場合や、その他のソリューションを使う場合は、[自動登録を無効化](configuration#serviceWorker) することができます。デフォルトの登録方法は次のようなものです:
```js
if ('serviceWorker' in navigator) {
addEventListener('load', function () {
navigator.serviceWorker.register('./path/to/service-worker.js');
});
}
```
## service worker の内部では
service worker の内部では、[`$service-worker` モジュール]($service-worker) にアクセスでき、これによって全ての静的なアセット、ビルドファイル、プリレンダリングページへのパスが提供されます。また、アプリのバージョン文字列 (一意なキャッシュ名を作成するのに使用できます) と、デプロイメントの `base` パスが提供されます。Vite の設定に `define` (グローバル変数の置換に使用) を指定している場合、それはサーバー/クライアントのビルドだけでなく、service worker にも適用されます。
次の例では、ビルドされたアプリと `static` にあるファイルをすぐに(eagerly)キャッシュし、その他全てのリクエストはそれらの発生時にキャッシュします。これにより、各ページは一度アクセスするとオフラインで動作するようになります。
```js
/// file: src/service-worker.js
// Disables access to DOM typings like `HTMLElement` which are not available
// inside a service worker and instantiates the correct globals
///
///
///
// Ensures that the `$service-worker` import has proper type definitions
///
// Only necessary if you have an import from `$env/static/public`
///
import { build, files, version } from '$service-worker';
// This gives `self` the correct types
const self = /** @type {ServiceWorkerGlobalScope} */ (/** @type {unknown} */ (globalThis.self));
// Create a unique cache name for this deployment
const CACHE = `cache-${version}`;
const ASSETS = [
...build, // the app itself
...files // everything in `static`
];
self.addEventListener('install', (event) => {
// Create a new cache and add all files to it
async function addFilesToCache() {
const cache = await caches.open(CACHE);
await cache.addAll(ASSETS);
}
event.waitUntil(addFilesToCache());
});
self.addEventListener('activate', (event) => {
// Remove previous cached data from disk
async function deleteOldCaches() {
for (const key of await caches.keys()) {
if (key !== CACHE) await caches.delete(key);
}
}
event.waitUntil(deleteOldCaches());
});
self.addEventListener('fetch', (event) => {
// ignore POST requests etc
if (event.request.method !== 'GET') return;
async function respond() {
const url = new URL(event.request.url);
const cache = await caches.open(CACHE);
// `build`/`files` can always be served from the cache
if (ASSETS.includes(url.pathname)) {
const response = await cache.match(url.pathname);
if (response) {
return response;
}
}
// for everything else, try the network first, but
// fall back to the cache if we're offline
try {
const response = await fetch(event.request);
// if we're offline, fetch can return a value that is not a Response
// instead of throwing - and we can't pass this non-Response to respondWith
if (!(response instanceof Response)) {
throw new Error('invalid response from fetch');
}
if (response.status === 200 && !response.headers.get('cache-control')?.includes('no-store')) {
cache.put(event.request, response.clone());
}
return response;
} catch (err) {
const response = await cache.match(event.request);
if (response) {
return response;
}
// if there's no cache, then just error out
// as there is nothing we can do to respond to this request
throw err;
}
}
event.respondWith(respond());
});
```
> [!NOTE] キャッシュにはご注意ください! 場合によっては、オフラインでは利用できないデータよりも古くなったデータのほうが悪いことがあります。ブラウザはキャッシュが一杯になると空にするため、ビデオファイルのような大きなアセットをキャッシュする場合にもご注意ください。
## 開発中は(During development)
service worker はプロダクション向けにはバンドルされますが、開発中はバンドルされません。そのため、[modules in service workers](https://web.dev/es-modules-in-sw) をサポートするブラウザのみ、開発時にもそれを使用することができます。service worker を手動で登録する場合、開発時に `{ type: 'module' }` オプションを渡す必要があります:
```js
import { dev } from '$app/environment';
navigator.serviceWorker.register('/service-worker.js', {
type: dev ? 'module' : 'classic'
});
```
> [!NOTE] `build` と `prerendered` は開発中は空配列です
## その他のソリューション
SvelteKit の service worker 実装は、簡単に動作するように設計されており、ほとんどのユーザーにとって良いソリューションでしょう。しかし、SvelteKit 以外の多くの PWA アプリケーションは [Workbox](https://web.dev/learn/pwa/workbox) というライブラリを活用しています。Workbox に慣れている方は [Vite PWA plugin](https://vite-pwa-org.netlify.app/frameworks/sveltekit.html) の方が好まれるかもしれません。
## References
For more general information on service workers, we recommend [the MDN web docs](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers).
# Server-only modules
良き友人のように、SvelteKit はあなたの秘密を守ります。バックエンドとフロントエンドが同じリポジトリにある場合、機密データをフロントエンドのコードに誤ってインポートしてしまうことが簡単に起こってしまいます (例えば、API キーを持つ環境変数など)。SvelteKit はこれを完全に防ぐ方法を提供します: サーバー専用のモジュール(server-only modules)です
## Private environment variables
[`$env/static/private`]($env-static-private) モジュールと [`$env/dynamic/private`]($env-dynamic-private) モジュールは、[`hooks.server.js`](hooks#Server-hooks) や [`+page.server.js`](routing#page-page.server.js) のようなサーバー上でのみ実行されるモジュールにのみインポートすることが可能です。
## Server-only utilities
The [`$app/server`]($app-server) module, which contains a [`read`]($app-server#read) function for reading assets from the filesystem, can likewise only be imported by code that runs on the server.
## Your modules
モジュールをサーバー専用にするには2通りの方法があります:
- ファイル名に `.server` を付けます。例: `secrets.server.js`
- モジュールを `$lib/server` に置きます。例: `$lib/server/secrets.js`
## How it works
パブリックに公開されるコード (public-facing code) にサーバー専用のコードを (直接的かまたは間接的かにかかわらず) インポートすると…
```js
// @errors: 7005
/// file: $lib/server/secrets.js
export const atlantisCoordinates = [/* redacted */];
```
```js
// @errors: 2307 7006 7005
/// file: src/routes/utils.js
export { atlantisCoordinates } from '$lib/server/secrets.js';
export const add = (a, b) => a + b;
```
```html
/// file: src/routes/+page.svelte
```
…SvelteKit はエラーとなります:
```
Cannot import $lib/server/secrets.ts into code that runs in the browser, as this could leak sensitive information.
src/routes/+page.svelte imports
src/routes/utils.js imports
$lib/server/secrets.ts
If you're only using the import as a type, change it to `import type`.
```
パブリックに公開されるコード `src/routes/+page.svelte` は、`add` を使用しているのみで、シークレットの `atlantisCoordinates` を使用していませんが、ブラウザがダウンロードする JavaScript にシークレットなコードが残ってしまう可能性があり、このインポートチェーンは安全ではないと考えられます。
この機能は動的なインポート(dynamic imports)でも動作し、``await import(`./${foo}.js`)`` のような補完されたインポートに対しても有効です。
> [!NOTE] Vitest のようなユニットテストフレームワークはサーバー専用のコードと公開されるコードを区別しません。そのため、テストの実行中、つまり `process.env.TEST === 'true'` となっているときは、不正なインポートの検出は無効化されます。
## その他の参考資料
- [Tutorial: Environment variables](/tutorial/kit/env-static-private)
# Snapshots
例えばサイドバーのスクロールポジションや、`
` 要素の中身などの、一時的な DOM の状態(state)は、あるページから別のページに移動するときに破棄されます。
例えば、ユーザーがフォームに入力し、それを送信する前に別のページに移動してからまた戻ってきた場合や、ページをリフレッシュした場合、フォームに入力されていた値は失われます。入力内容を保持しておくことが重要な場合、DOM の状態を _スナップショット(snapshot)_ として記録することができ、ユーザーが戻ってきたときに復元することができます。
これを行うには、`+page.svelte` や `+layout.svelte` で、`capture` メソッドと `restore` メソッドを持つ `snapshot` オブジェクトをエクスポートします:
```svelte
```
このページから離れるとき、ページが更新される直前に `capture` 関数が呼ばれ、戻り値がブラウザの history スタックの現在のエントリーに関連付けられます。もしこのページに戻ってきた場合、ページが更新されるとすぐに保存された値とともに `restore` 関数が呼ばれます。
データは `sessionStorage` に永続化できるように、JSON としてシリアライズ可能でなければなりません。これにより、ページがリロードされたときや、ユーザーが別のサイトから戻ってきたときにも、状態を復元することができます。
> [!NOTE] 大きすぎるオブジェクトを `capture` から返さないようにしてください。一度 capture されたオブジェクトは、そのセッションの間はメモリ上に保持されるので、極端な場合には、大きすぎて `sessionStorage` に永続化できない可能性があります。
# Shallow routing
As you navigate around a SvelteKit app, you create _history entries_. Clicking the back and forward buttons traverses through this list of entries, re-running any `load` functions and replacing page components as necessary.
Sometimes, it's useful to create history entries _without_ navigating. For example, you might want to show a modal dialog that the user can dismiss by navigating back. This is particularly valuable on mobile devices, where swipe gestures are often more natural than interacting directly with the UI. In these cases, a modal that is _not_ associated with a history entry can be a source of frustration, as a user may swipe backwards in an attempt to dismiss it and find themselves on the wrong page.
SvelteKit makes this possible with the [`pushState`]($app-navigation#pushState) and [`replaceState`]($app-navigation#replaceState) functions, which allow you to associate state with a history entry without navigating. For example, to implement a history-driven modal:
```svelte
{#if page.state.showModal}
history.back()} />
{/if}
```
The modal can be dismissed by navigating back (unsetting `page.state.showModal`) or by interacting with it in a way that causes the `close` callback to run, which will navigate back programmatically.
## API
The first argument to `pushState` is the URL, relative to the current URL. To stay on the current URL, use `''`.
The second argument is the new page state, which can be accessed via the [page object]($app-state#page) as `page.state`. You can make page state type-safe by declaring an [`App.PageState`](types#PageState) interface (usually in `src/app.d.ts`).
To set page state without creating a new history entry, use `replaceState` instead of `pushState`.
> [!LEGACY]
> `page.state` from `$app/state` was added in SvelteKit 2.12. If you're using an earlier version or are using Svelte 4, use `$page.state` from `$app/stores` instead.
## Loading data for a route
When shallow routing, you may want to render another `+page.svelte` inside the current page. For example, clicking on a photo thumbnail could pop up the detail view without navigating to the photo page.
For this to work, you need to load the data that the `+page.svelte` expects. A convenient way to do this is to use [`preloadData`]($app-navigation#preloadData) inside the `click` handler of an `` element. If the element (or a parent) uses [`data-sveltekit-preload-data`](link-options#data-sveltekit-preload-data), the data will have already been requested, and `preloadData` will reuse that request.
```svelte
{#each data.thumbnails as thumbnail}
{
if (innerWidth < 640 // bail if the screen is too small
|| e.shiftKey // or the link is opened in a new window
|| e.metaKey || e.ctrlKey // or a new tab (mac: metaKey, win/linux: ctrlKey)
// should also consider clicking with a mouse scroll wheel
) return;
// prevent navigation
e.preventDefault();
const { href } = e.currentTarget;
// run `load` functions (or rather, get the result of the `load` functions
// that are already running because of `data-sveltekit-preload-data`)
const result = await preloadData(href);
if (result.type === 'loaded' && result.status === 200) {
pushState(href, { selected: result.data });
} else {
// something bad happened! try navigating
goto(href);
}
}}
>
{/each}
{#if page.state.selected}
history.back()}>
{/if}
```
## Caveats
During server-side rendering, `page.state` is always an empty object. The same is true for the first page the user lands on — if the user reloads the page (or returns from another document), state will _not_ be applied until they navigate.
Shallow routing is a feature that requires JavaScript to work. Be mindful when using it and try to think of sensible fallback behavior in case JavaScript isn't available.
# Observability
Available since 2.31
Sometimes, you may need to observe how your application is behaving in order to improve performance or find the root cause of a pesky bug. To help with this, SvelteKit can emit server-side [OpenTelemetry](https://opentelemetry.io) spans for the following:
- The [`handle`](hooks#Server-hooks-handle) hook and `handle` functions running in a [`sequence`](@sveltejs-kit-hooks#sequence) (these will show up as children of each other and the root `handle` hook)
- Server [`load`](load) functions and universal `load` functions when they're run on the server
- [Form actions](form-actions)
- [Remote functions](remote-functions)
Just telling SvelteKit to emit spans won't get you far, though — you need to actually collect them somewhere to be able to view them. SvelteKit provides `src/instrumentation.server.ts` as a place to write your tracing setup and instrumentation code. It's guaranteed to be run prior to your application code being imported, providing your deployment platform supports it and your adapter is aware of it.
Both of these features are currently experimental, meaning they are likely to contain bugs and are subject to change without notice. You must opt in by adding the `kit.experimental.tracing.server` and `kit.experimental.instrumentation.server` option in your `svelte.config.js`:
```js
/// file: svelte.config.js
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
experimental: {
+++tracing: {
server: true
},
instrumentation: {
server: true
}+++
}
}
};
export default config;
```
> [!NOTE] Tracing — and more significantly, observability instrumentation — can have a nontrivial overhead. Before you go all-in on tracing, consider whether or not you really need it, or if it might be more appropriate to turn it on in development and preview environments only.
## Augmenting the built-in tracing
SvelteKit provides access to the `root` span and the `current` span on the request event. The root span is the one associated with your root `handle` function, and the current span could be associated with `handle`, `load`, a form action, or a remote function, depending on the context. You can annotate these spans with any attributes you wish to record:
```js
/// file: $lib/authenticate.ts
// @filename: ambient.d.ts
declare module '$lib/auth-core' {
export function getAuthenticatedUser(): Promise<{ id: string }>
}
// @filename: index.js
// ---cut---
import { getRequestEvent } from '$app/server';
import { getAuthenticatedUser } from '$lib/auth-core';
async function authenticate() {
const user = await getAuthenticatedUser();
const event = getRequestEvent();
event.tracing.root.setAttribute('userId', user.id);
}
```
## Development quickstart
To view your first trace, you'll need to set up a local collector. We'll use [Jaeger](https://www.jaegertracing.io/docs/getting-started/) in this example, as they provide an easy-to-use quickstart command. Once your collector is running locally:
- Turn on the experimental flags mentioned earlier in your `svelte.config.js` file
- Use your package manager to install the dependencies you'll need:
```sh
npm i @opentelemetry/sdk-node @opentelemetry/auto-instrumentations-node @opentelemetry/exporter-trace-otlp-proto import-in-the-middle
```
- Create `src/instrumentation.server.js` with the following:
```js
// @errors: 2307
/// file: src/instrumentation.server.js
import { NodeSDK } from '@opentelemetry/sdk-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';
import { createAddHookMessageChannel } from 'import-in-the-middle';
import { register } from 'node:module';
const { registerOptions } = createAddHookMessageChannel();
register('import-in-the-middle/hook.mjs', import.meta.url, registerOptions);
const sdk = new NodeSDK({
serviceName: 'test-sveltekit-tracing',
traceExporter: new OTLPTraceExporter(),
instrumentations: [getNodeAutoInstrumentations()]
});
sdk.start();
```
Now, server-side requests will begin generating traces, which you can view in Jaeger's web console at [localhost:16686](http://localhost:16686).
## `@opentelemetry/api`
SvelteKit uses `@opentelemetry/api` to generate its spans. This is declared as an optional peer dependency so that users not needing traces see no impact on install size or runtime performance. In most cases, if you're configuring your application to collect SvelteKit's spans, you'll end up installing a library like `@opentelemetry/sdk-node` or `@vercel/otel`, which in turn depend on `@opentelemetry/api`, which will satisfy SvelteKit's dependency as well. If you see an error from SvelteKit telling you it can't find `@opentelemetry/api`, it may just be because you haven't set up your trace collection yet. If you _have_ done that and are still seeing the error, you can install `@opentelemetry/api` yourself.
# Packaging
SvelteKit では、アプリを構築するだけでなく、`@sveltejs/package` パッケージを使用してコンポーネントライブラリを構築することもできます (`npx sv create` にはこれを設定するためのオプションがあります)。
アプリを作成するとき、`src/routes` のコンテンツが公開される部分となります。[`src/lib`]($lib) にはアプリの内部ライブラリが含まれます。
コンポーネントライブラリは SvelteKit アプリと同じ構造ですが、`src/lib` が公開される部分である点が異なります。パッケージの公開にはプロジェクトの最上位(root)の `package.json` が使用されます。`src/routes` を、ライブラリに付属するドキュメントやデモサイト、または開発中に使用するサンドボックスにすることもあるでしょう。
`@sveltejs/package` の `svelte-package` コマンドを実行すると、`src/lib` の中身を取り込み、以下を含む `dist` ([設定で変更](#Options)できます) ディレクトリを生成します:
- `src/lib` にある全てのファイル。Svelte コンポーネントはプリプロセスされ、TypeScript ファイルは JavaScript にトランスパイルされます。
- Svelte、JavaScript、TypeScript ファイル向けに生成される型定義 (`d.ts` ファイル)。このために、`typescript >= 4.0.0` をインストールする必要があります。型定義はその実装と同じ場所に配置され、手書きの `d.ts` ファイルはそのままコピーされます。[生成を無効](#Options)にすることもできますが、それはおすすめできません。あなたのライブラリを使用する人は TypeScript を使用しているかもしれません。その場合、この型定義ファイルが必要になります。
> [!NOTE] `@sveltejs/package` バージョン1は `package.json` を生成していましたが、この仕様は変更され、現在はプロジェクトの `package.json` を使用しそれが正しいか検証するようになりました。もしまだバージョン1を使用している場合は、[この PR](https://github.com/sveltejs/kit/pull/8922) にある移行手順(Migration instructions)をご覧ください。
## package.json の構造
公開するライブラリをビルドするのであれば、`package.json` の内容がとても重要になります。これを通して、パッケージのエントリーポイントや、どのファイルを npm に公開するか、そしてあなたのライブラリの依存関係を設定することができます。それでは、重要なフィールドをひとつずつ見ていきましょう。
### name
これはパッケージの名前です。他の人はこの名前を使用してインストールすることになります。そして `https://npmjs.com/package/` のように表示されるようになります。
```json
{
"name": "your-library"
}
```
詳細については[こちら](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#name)をお読みください。
### license
すべてのパッケージにはライセンスフィールドがあるべきです。なぜなら、人々はこれによってどのように使用することが許可されているのか知ることができるからです。配布や保証なしの再利用に関してとても寛容で、非常にポピュラーなライセンスとして、`MIT` があります。
```json
{
"license": "MIT"
}
```
詳細については[こちら](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#license)をお読みください。`LICENSE` ファイルもパッケージに含めるとよいでしょう。
### files
ここではどのファイルを npm にアップロードするかを設定します。出力先フォルダ (デフォルトは `dist`) も含める必要があります。`package.json` と `README` と `LICENSE` は常に含まれるようになっているため、指定する必要はありません。
```json
{
"files": ["dist"]
}
```
不要なファイル (例えば単体テストや、`src/routes` からのみインポートされているモジュールなど) を除外するには、`.npmignore` ファイルにそれらを追加します。これによってより小さいパッケージとなり、インストールも速くなります。
詳細については[こちら](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#files)をお読みください。
### exports
`"exports"` フィールドにはパッケージのエントリーポイントを含めます。`npx sv create` を使用して新しいライブラリプロジェクトをセットアップした場合、単一の export として、パッケージの最上位(root)が設定されています:
```json
{
"exports": {
".": {
"types": "./dist/index.d.ts",
"svelte": "./dist/index.js"
}
}
}
```
これにより、あなたのパッケージにはエントリーポイントが1つだけで、それは最上位(root)で、(以下のように)すべてここを通してインポートされるべきである、ということをバンドラーやツール類に伝えます:
```js
// @errors: 2307
import { Something } from 'your-library';
```
`types` と `svelte` キーは [export conditions](https://nodejs.org/api/packages.html#conditional-exports) です。これはツール類に、`your-library` インポートを検索する際にどのファイルをインポートするかを伝えるものです:
- TypeScript は `types` condition を見て、型定義ファイルを検索します。型定義を公開しない場合は、この condition を省略します。
- Svelte を認識するツール類は `svelte` condition を見て、これが Svelte コンポーネントライブラリであることを認識します。Svelte コンポーネントをエクスポートせず、Svelte 以外のプロジェクトでも使用できるライブラリ (例えば Svelte store ライブラリ) を公開する場合、この condition を `default` に置き換えることができます。
> [!NOTE] 以前のバージョンの `@sveltejs/package` は `package.json` export も追加していましたが、現在は違います。すべてのツール類が明示的にエクスポートされていない `package.json` を扱うことができるようになったからです。
`exports` を好みに合わせて調整し、より多くのエントリーポイントを提供することができます。例えば、コンポーネントを再エクスポートする `src/lib/index.js` ファイルの代わりに、`src/lib/Foo.svelte` コンポーネントを直接公開したい場合、以下のような export map を作成できます…
```json
{
"exports": {
"./Foo.svelte": {
"types": "./dist/Foo.svelte.d.ts",
"svelte": "./dist/Foo.svelte"
}
}
}
```
…そしてライブラリの使用者はコンポーネントをこのようにインポートできます:
```js
// @filename: ambient.d.ts
declare module 'your-library/Foo.svelte';
// @filename: index.js
// ---cut---
import Foo from 'your-library/Foo.svelte';
```
> [!NOTE] 型定義を提供している場合、これを行う際にさらなる注意が必要となることにお気をつけください。注意事項については[こちら](#TypeScript)をお読みください。
一般的に、exports map の各キーはユーザーがあなたのパッケージからなにかインポートするときに使用すべきパスであり、その値はインポートされるファイルへのパスか、またはそのファイルパスを含む export condition の map です。
`exports` の詳細については[こちら](https://nodejs.org/docs/latest-v18.x/api/packages.html#package-entry-points)をお読みください。
### svelte
これはツール類に Svelte コンポーネントライブラリを認識できるようにするレガシーなフィールドです。`svelte` [export condition](#Anatomy-of-a-package.json-exports) を使用している場合は必要ありませんが、まだ export condition を認識しない古いツールとの後方互換性のために残しておくとよいでしょう。あなたの最上位(root)のエントリーポイントを指しているはずです。
```json
{
"svelte": "./dist/index.js"
}
```
### sideEffects
The `sideEffects` field in `package.json` is used by bundlers to determine if a module may contain code that has side effects. A module is considered to have side effects if it makes changes that are observable from other scripts outside the module when it's imported. For example, side effects include modifying global variables or the prototype of built-in JavaScript objects. Because a side effect could potentially affect the behavior of other parts of the application, these files/modules will be included in the final bundle regardless of whether their exports are used in the application. It is a best practice to avoid side effects in your code.
Setting the `sideEffects` field in `package.json` can help the bundler to be more aggressive in eliminating unused exports from the final bundle, a process known as tree-shaking. This results in smaller and more efficient bundles. Different bundlers handle `sideEffects` in various manners. While not necessary for Vite, we recommend that libraries state that all CSS files have side effects so that your library will be [compatible with webpack](https://webpack.js.org/guides/tree-shaking/#mark-the-file-as-side-effect-free). This is the configuration that comes with newly created projects:
```json
/// file: package.json
{
"sideEffects": ["**/*.css"]
}
```
> [!NOTE] If the scripts in your library have side effects, ensure that you update the `sideEffects` field. All scripts are marked as side effect free by default in newly created projects. If a file with side effects is incorrectly marked as having no side effects, it can result in broken functionality.
If your package has files with side effects, you can specify them in an array:
```json
/// file: package.json
{
"sideEffects": [
"**/*.css",
"./dist/sideEffectfulFile.js"
]
}
```
This will treat only the specified files as having side effects.
## TypeScript
あなたが TypeScript を使用していないとしても、あなたのライブラリの型定義を公開したほうがよいでしょう。あなたのライブラリを使用する人が、適切なインテリセンスを得られるようになるからです。`@sveltejs/package` は型生成のプロセスをほとんど隠ぺい(opaque)してくれます。デフォルトでは、ライブラリをパッケージングする際、JavaScript、TypeScript、Svelte ファイル向けに型定義を自動生成します。あなたは [exports](#Anatomy-of-a-package.json-exports) map の `types` condition が正しいファイルを指しているか確認するだけです。`npx sv create` でライブラリプロジェクトを初期化すると、root export に `types` condition が設定されます。
しかし、root export 以外のもの、例えば `your-library/foo` インポートを提供する場合などは、型定義を提供する上でさらなる注意が必要です。残念ながら、TypeScript はデフォルトでは `{ "./foo": { "types": "./dist/foo.d.ts", ... }}` のような export に対して `types` condition を解決しません。代わりに、ライブラリの root からの相対で `foo.d.ts` を探します (つまり、`your-library/dist/foo.d.ts` ではなく `your-library/foo.d.ts` です)。これを修正する方法として、選択肢が2つあります:
1つ目の選択肢は、あなたのライブラリを使用する人に対し、`tsconfig.json` (または `jsconfig.json`) の `moduleResolution` オプション に `bundler` (TypeScript 5 から利用可能で、将来的にもベストかつ推奨のオプション) か `node16` か `nodenext` を設定してもらうように要求することです。これによって TypeScript が実際に exports map を見て正しく型を解決してくれるようになります。
2つ目の選択肢は、TypeScript の `typesVersions` 機能を使用(乱用)して、型を紐付けます。これは、TypeScript が TypeScript のバージョンによって異なる型定義をチェックするために使用している `package.json` 内のフィールドで、このためにパスマッピング機能があります。このパスマッピング機能を利用して、やりたいことを実現できます。上述の `foo` export の場合、対応する `typesVersions` はこのようになります:
```json
{
"exports": {
"./foo": {
"types": "./dist/foo.d.ts",
"svelte": "./dist/foo.js"
}
},
"typesVersions": {
">4.0": {
"foo": ["./dist/foo.d.ts"]
}
}
}
```
`>4.0` は、TypeScript のバージョンが 4 より大きい場合、内側の map をチェックするよう TypeScript に伝えるものです (実際には常に true となるべきものです)。内側の map は TypeScript に `your-library/foo` に対する型付けが `./dist/foo.d.ts` にあることを伝えるためのもので、実質 `exports` condition を置き換えています。また、ワイルドカードとして `*` を自由に使用できるので、同じことを繰り返すことなくたくさんの型定義を一度で使用可能にすることができます。もし `typesVersions` を選択した場合、(`"index.d.ts": [..]` と定義されている) root import を含む全ての型のインポートを、これを通して宣言しなければならないことにご注意ください。
この機能についてより詳しい情報は[こちら](https://www.typescriptlang.org/docs/handbook/declaration-files/publishing.html#version-selection-with-typesversions)でお読み頂けます。
## ベストプラクティス
他の SvelteKit プロジェクトからのみ使用されることを想定しているのでなければ、`$app/environment` などの SvelteKit 固有のモジュールをあなたのパッケージで使用するのは避けたほうがよいでしょう。例えば、`import { browser } from '$app/environment'` を使用するのではなく、`import { BROWSER } from 'esm-env'` ([esm-env ドキュメント参照](https://github.com/benmccann/esm-env)) を使用します。また、`$app/state` や `$app/navigation` などに直接頼るのではなく、現在の URL や navigation action をプロパティとして渡すこともできます。より一般的な方法でアプリを書くことによって、テストや UI デモなどのツールのセットアップも簡単になります。
[エイリアス](configuration#alias) は `svelte.config.js` (`vite.config.js` や `tsconfig.json` ではなく) を経由して追加するようにしてください。`svelte-package` で処理されるからです。.
パッケージに加えた変更がバグフィックスなのか、新機能なのか、それとも破壊的変更(breaking change)なのかをよく考えて、それに応じてパッケージのバージョンを更新する必要があります。もし既存のライブラリから `exports` やその中の `export` condition のパスを削除した場合、breaking change とみなされることにご注意ください。
```json
{
"exports": {
".": {
"types": "./dist/index.d.ts",
// changing `svelte` to `default` is a breaking change:
--- "svelte": "./dist/index.js"---
+++ "default": "./dist/index.js"+++
},
// removing this is a breaking change:
--- "./foo": {
"types": "./dist/foo.d.ts",
"svelte": "./dist/foo.js",
"default": "./dist/foo.js"
},---
// adding this is ok:
+++ "./bar": {
"types": "./dist/bar.d.ts",
"svelte": "./dist/bar.js",
"default": "./dist/bar.js"
}+++
}
}
```
## Source maps
You can create so-called declaration maps (`d.ts.map` files) by setting `"declarationMap": true` in your `tsconfig.json`. This will allow editors such as VS Code to go to the original `.ts` or `.svelte` file when using features like _Go to Definition_. This means you also need to publish your source files alongside your dist folder in a way that the relative path inside the declaration files leads to a file on disk. Assuming that you have all your library code inside `src/lib` as suggested by Svelte's CLI, this is as simple as adding `src/lib` to `files` in your `package.json`:
```json
{
"files": [
"dist",
"!dist/**/*.test.*",
"!dist/**/*.spec.*",
+++"src/lib",
"!src/lib/**/*.test.*",
"!src/lib/**/*.spec.*"+++
]
}
```
## Options
`svelte-package` は以下のオプションを受け付けます:
- `-w`/`--watch` — `src/lib` にあるファイルの変更を関ししてパッケージを再ビルドします
- `-i`/`--input` — パッケージの全てのファイルを含む入力ディレクトリ。デフォルトは `src/lib` です
- `-o`/`--output` — 処理されたファイルが書き込まれる出力ディレクトリ。`package.json` の `exports` はここにあるファイルを指さなければならず、`files` の配列にはこのフォルダを含めなければいけません。デフォルトは `dist` です
- `-p`/`--preserve-output` — パッケージング前に出力ディレクトリの削除を止めるかどうか。デフォルトは `false` で、この場合は出力ディレクトリが最初に空にされます
- `-t`/`--types` — 型定義 (`d.ts` ファイル) を作成するかどうか。エコシステムのライブラリの品質を向上させるため、作成することを強く推奨します。デフォルトは `true` です
- `--tsconfig` - tsconfig または jsconfig へのパス。指定されない場合は、ワークスペースのパスで次の上位の tsconfig/jsconfig を検索します。
## 公開(Publishing)
生成されたパッケージを公開するには:
```sh
npm publish
```
## 注意事項
すべての相対ファイルインポートは、Node の ESM アルゴリズムに従って、フルで指定する必要があります。つまり、`src/lib/something/index.js` のようなファイルには、ファイル名と拡張子を含めなければなりません。
```js
// @errors: 2307
import { something } from './something+++/index.js+++';
```
TypeScript を使用している場合、同じように `.ts` ファイルをインポートする必要がありますが、`.js` ファイルの末尾を使用する必要があります、`.ts` ファイルの末尾ではありません (これは TypeScript の設計上の決定によるもので、私たちの管轄外です)。`tsconfig.json` または `jsconfig.json` に `"moduleResolution": "NodeNext"` を設定すると、これに対処できます。
Svelte ファイル (プロプロセスされる) と TypeScript ファイル (JavaScript にトランスパイルされる) を覗いて、全てのファイルはそのままコピーされます。
# Auth
Auth refers to authentication and authorization, which are common needs when building a web application. Authentication means verifying that the user is who they say they are based on their provided credentials. Authorization means determining which actions they are allowed to take.
## Sessions vs tokens
After the user has provided their credentials such as a username and password, we want to allow them to use the application without needing to provide their credentials again for future requests. Users are commonly authenticated on subsequent requests with either a session identifier or signed token such as a JSON Web Token (JWT).
Session IDs are most commonly stored in a database. They can be immediately revoked, but require a database query to be made on each request.
In contrast, JWT generally are not checked against a datastore, which means they cannot be immediately revoked. The advantage of this method is improved latency and reduced load on your datastore.
## Integration points
Auth [cookies](@sveltejs-kit#Cookies) can be checked inside [server hooks](hooks#Server-hooks). If a user is found matching the provided credentials, the user information can be stored in [`locals`](hooks#Server-hooks-locals).
## Libraries
The [Svelte CLI](/docs/cli) gives the option to [set up Better Auth](https://svelte.dev/docs/cli/better-auth) with a new project or add it to an existing project.
## Guides
If you'd like to implement your own auth system, [the Lucia auth guide](https://lucia-auth.com/) provides a reference for session-based web app auth with SvelteKit examples.
# Performance
Out of the box, SvelteKit does a lot of work to make your applications as performant as possible:
- Code-splitting, so that only the code you need for the current page is loaded
- Asset preloading, so that 'waterfalls' (of files requesting other files) are prevented
- File hashing, so that your assets can be cached forever
- Request coalescing, so that data fetched from separate server `load` functions is grouped into a single HTTP request
- Parallel loading, so that separate universal `load` functions fetch data simultaneously
- Data inlining, so that requests made with `fetch` during server rendering can be replayed in the browser without issuing a new request
- Conservative invalidation, so that `load` functions are only re-run when necessary
- Prerendering (configurable on a per-route basis, if necessary) so that pages without dynamic data can be served instantaneously
- Link preloading, so that data and code requirements for a client-side navigation are eagerly anticipated
Nevertheless, we can't (yet) eliminate all sources of slowness. To eke out maximum performance, you should be mindful of the following tips.
## Diagnosing issues
Google's [PageSpeed Insights](https://pagespeed.web.dev/) and (for more advanced analysis) [WebPageTest](https://www.webpagetest.org/) are excellent ways to understand the performance characteristics of a site that is already deployed to the internet.
Your browser also includes useful developer tools for analysing your site, whether deployed or running locally:
* Chrome - [Lighthouse](https://developer.chrome.com/docs/lighthouse/overview#devtools), [Network](https://developer.chrome.com/docs/devtools/network), and [Performance](https://developer.chrome.com/docs/devtools/performance) devtools
* Edge - [Lighthouse](https://learn.microsoft.com/en-us/microsoft-edge/devtools-guide-chromium/lighthouse/lighthouse-tool), [Network](https://learn.microsoft.com/en-us/microsoft-edge/devtools-guide-chromium/network/), and [Performance](https://learn.microsoft.com/en-us/microsoft-edge/devtools-guide-chromium/evaluate-performance/) devtools
* Firefox - [Network](https://firefox-source-docs.mozilla.org/devtools-user/network_monitor/) and [Performance](https://hacks.mozilla.org/2022/03/performance-tool-in-firefox-devtools-reloaded/) devtools
* Safari - [enhancing the performance of your webpage](https://developer.apple.com/library/archive/documentation/NetworkingInternetWeb/Conceptual/Web_Inspector_Tutorial/EnhancingyourWebpagesPerformance/EnhancingyourWebpagesPerformance.html)
Note that your site running locally in `dev` mode will exhibit different behaviour than your production app, so you should do performance testing in [preview](building-your-app#Preview-your-app) mode after building.
### Instrumenting
If you see in the network tab of your browser that an API call is taking a long time and you'd like to understand why, you may consider instrumenting your backend with a tool like [OpenTelemetry](https://opentelemetry.io/) or [Server-Timing headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Server-Timing).
## Optimizing assets
### Images
Reducing the size of image files is often one of the most impactful changes you can make to a site's performance. Svelte provides the `@sveltejs/enhanced-img` package, detailed on the [images](images) page, for making this easier. Additionally, Lighthouse is useful for identifying the worst offenders.
### Videos
Video files can be very large, so extra care should be taken to ensure that they're optimized:
- Compress videos with tools such as [Handbrake](https://handbrake.fr/). Consider converting the videos to web-friendly formats such as `.webm` or `.mp4`.
- You can [lazy-load videos](https://web.dev/articles/lazy-loading-video) located below the fold with `preload="none"` (though note that this will slow down playback when the user _does_ initiate it).
- Strip the audio track out of muted videos using a tool like [FFmpeg](https://ffmpeg.org/).
### Fonts
SvelteKit automatically preloads critical `.js` and `.css` files when the user visits a page, but it does _not_ preload fonts by default, since this may cause unnecessary files (such as font weights that are referenced by your CSS but not actually used on the current page) to be downloaded. Having said that, preloading fonts correctly can make a big difference to how fast your site feels. In your [`handle`](hooks#Server-hooks-handle) hook, you can call `resolve` with a `preload` filter that includes your fonts.
You can reduce the size of font files by [subsetting](https://web.dev/learn/performance/optimize-web-fonts#subset_your_web_fonts) your fonts.
## Reducing code size
### Svelte version
We recommend running the latest version of Svelte. Svelte 5 is smaller and faster than Svelte 4, which is smaller and faster than Svelte 3.
### Packages
[`rollup-plugin-visualizer`](https://www.npmjs.com/package/rollup-plugin-visualizer) can be helpful for identifying which packages are contributing the most to the size of your site. You may also find opportunities to remove code by manually inspecting the build output (use `build: { minify: false }` in your [Vite config](https://vitejs.dev/config/build-options.html#build-minify) to make the output readable, but remember to undo that before deploying your app), or via the network tab of your browser's devtools.
### External scripts
Try to minimize the number of third-party scripts running in the browser. For example, instead of using JavaScript-based analytics consider using server-side implementations, such as those offered by many platforms with SvelteKit adapters including [Cloudflare](https://www.cloudflare.com/web-analytics/), [Netlify](https://docs.netlify.com/monitor-sites/site-analytics/), and [Vercel](https://vercel.com/docs/analytics).
To run third party scripts in a web worker (which avoids blocking the main thread), use [Partytown's SvelteKit integration](https://partytown.builder.io/sveltekit).
### Selective loading
Code imported with static `import` declarations will be automatically bundled with the rest of your page. If there is a piece of code you need only when some condition is met, use the dynamic `import(...)` form to selectively lazy-load the component.
## Navigation
### Preloading
You can speed up client-side navigations by eagerly preloading the necessary code and data, using [link options](link-options). This is configured by default on the `` element when you create a new SvelteKit app.
### Non-essential data
For slow-loading data that isn't needed immediately, the object returned from your `load` function can contain promises rather than the data itself. For server `load` functions, this will cause the data to [stream](load#Streaming-with-promises) in after the navigation (or initial page load).
### Preventing waterfalls
One of the biggest performance killers is what is referred to as a _waterfall_, which is a series of requests that is made sequentially. This can happen on the server or in the browser, but is especially costly when dealing with data that has to travel further or across slower networks, such as a mobile user making a call to a distant server.
In the browser, waterfalls can occur when your HTML kicks off request chains such as requesting JS which requests CSS which requests a background image and web font. SvelteKit will largely solve this class of problems for you by adding [`modulepreload`](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel/modulepreload) tags or headers, but you should view [the network tab in your devtools](#Diagnosing-issues) to check whether additional resources need to be preloaded.
- Pay special attention to this if you use [web fonts](#Optimizing-assets-Fonts) since they need to be handled manually.
- Enabling [single page app (SPA) mode](single-page-apps) will cause such waterfalls. With SPA mode, an empty page is generated, which fetches JavaScript, which ultimately loads and renders the page. This results in extra network round trips before a single pixel can be displayed.
Waterfalls can also occur on calls to the backend whether made from the browser or server. E.g. if a universal `load` function makes an API call to fetch the current user, then uses the details from that response to fetch a list of saved items, and then uses _that_ response to fetch the details for each item, the browser will end up making multiple sequential requests. This is deadly for performance, especially for users that are physically located far from your backend.
- Avoid this issue by using [server `load` functions](load#Universal-vs-server) to make requests to backend services that are dependencies from the server rather than from the browser. Note, however, that server `load` functions are also not immune to waterfalls (though they are much less costly since they rarely involve round trips with high latency). For example, if you query a database to get the current user and then use that data to make a second query for a list of saved items, it will typically be more performant to issue a single query with a database join.
## Hosting
Your frontend should be located in the same data center as your backend to minimize latency. For sites with no central backend, many SvelteKit adapters support deploying to the _edge_, which means handling each user's requests from a nearby server. This can reduce load times significantly. Some adapters even support [configuring deployment on a per-route basis](page-options#config). You should also consider serving images from a CDN (which are typically edge networks) — the hosts for many SvelteKit adapters will do this automatically.
Ensure your host uses HTTP/2 or newer. Vite's code splitting creates numerous small files for improved cacheability, which results in excellent performance, but this does assume that your files can be loaded in parallel with HTTP/2.
## Further reading
For the most part, building a performant SvelteKit app is the same as building any performant web app. You should be able to apply information from general performance resources such as [Core Web Vitals](https://web.dev/explore/learn-core-web-vitals) to any web experience you build.
# Icons
## CSS
アイコンの利用において、優れた手法のひとつが CSS を用いて定義する方法です。Iconifyは [多くの人気アイコンセット](https://icon-sets.iconify.design/) をサポートしており、[CSSで組み込むことができます](https://iconify.design/docs/usage/css/)。この方法は、Iconifyの [Tailwind CSS プラグイン](https://iconify.design/docs/usage/css/tailwind/) や [UnoCSS プラグイン](https://iconify.design/docs/usage/css/unocss/) を活用することで、人気のCSSフレームワークと組み合わせて使うことも可能です。Svelteコンポーネントベースのライブラリとは異なり、各アイコンを `.svelte` ファイルにインポートする必要がありません。
## Svelte
[Svelte用のアイコンライブラリ](/packages#icons) は数多くあります。アイコンライブラリを選択する際は、アイコンごとに `.svelte` ファイルを提供するものは避けることをお勧めします。これらのライブラリは数千の `.svelte` ファイルを持つ可能性があり、[Viteの依存関係最適化](https://vite.dev/guide/dep-pre-bundling.html) を大幅に遅くしてしまいます。これは [`vite-plugin-svelte`のFAQで説明されている](https://github.com/sveltejs/vite-plugin-svelte/blob/main/docs/faq.md#what-is-going-on-with-vite-and-pre-bundling-dependencies) ように、アイコンを umbrella import と subpath import の両方で読み込んでしまうことで、パフォーマンスの問題が顕著になる可能性があるためです。
# Images
Images can have a big impact on your app's performance. For best results, you should optimize them by doing the following:
- generate optimal formats like `.avif` and `.webp`
- create different sizes for different screens
- ensure that assets can be cached effectively
Doing this manually is tedious. There are a variety of techniques you can use, depending on your needs and preferences.
## Vite's built-in handling
[Vite will automatically process imported assets](https://vitejs.dev/guide/assets.html) for improved performance. This includes assets referenced via the CSS `url()` function. Hashes will be added to the filenames so that they can be cached, and assets smaller than `assetsInlineLimit` will be inlined. Vite's asset handling is most often used for images, but is also useful for video, audio, etc.
```svelte
```
## @sveltejs/enhanced-img
`@sveltejs/enhanced-img` is a plugin offered on top of Vite's built-in asset handling. It provides plug and play image processing that serves smaller file formats like `avif` or `webp`, automatically sets the intrinsic `width` and `height` of the image to avoid layout shift, creates images of multiple sizes for various devices, and strips EXIF data for privacy. It will work in any Vite-based project including, but not limited to, SvelteKit projects.
> [!NOTE] As a build plugin, `@sveltejs/enhanced-img` can only optimize files located on your machine during the build process. If you have an image located elsewhere (such as a path served from your database, CMS, or backend), please read about [loading images dynamically from a CDN](#Loading-images-dynamically-from-a-CDN).
### Setup
Install:
```sh
npm i -D @sveltejs/enhanced-img
```
Adjust `vite.config.js`:
```js
import { sveltekit } from '@sveltejs/kit/vite';
+++import { enhancedImages } from '@sveltejs/enhanced-img';+++
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [
+++enhancedImages(), // must come before the SvelteKit plugin+++
sveltekit()
]
});
```
Building will take longer on the first build due to the computational expense of transforming images. However, the build output will be cached in `./node_modules/.cache/imagetools` so that subsequent builds will be fast.
### Basic usage
Use in your `.svelte` components by using `` rather than ` ` and referencing the image file with a [Vite asset import](https://vitejs.dev/guide/assets.html#static-asset-handling) path:
```svelte
```
At build time, your `` tag will be replaced with an ` ` wrapped by a `` providing multiple image types and sizes. It's only possible to downscale images without losing quality, which means that you should provide the highest resolution image that you need — smaller versions will be generated for the various device types that may request an image.
You should provide your image at 2x resolution for HiDPI displays (a.k.a. retina displays). `` will automatically take care of serving smaller versions to smaller devices.
> [!NOTE] if you wish to use a [tag name CSS selector](https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Styling_basics/Basic_selectors#type_selectors) in your `
```
### `srcset` and `sizes`
If you have a large image, such as a hero image taking the width of the design, you should specify `sizes` so that smaller versions are requested on smaller devices. E.g. if you have a 1280px image you may want to specify something like:
```svelte
```
If `sizes` is specified, `` will generate small images for smaller devices and populate the `srcset` attribute.
The smallest picture generated automatically will have a width of 540px. If you'd like smaller images or would otherwise like to specify custom widths, you can do that with the `w` query parameter:
```svelte
```
If `sizes` is not provided, then a HiDPI/Retina image and a standard resolution image will be generated. The image you provide should be 2x the resolution you wish to display so that the browser can display that image on devices with a high [device pixel ratio](https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio).
### Per-image transforms
By default, enhanced images will be transformed to more efficient formats. However, you may wish to apply other transforms such as a blur, quality, flatten, or rotate operation. You can run per-image transforms by appending a query string:
```svelte
```
[See the imagetools repo for the full list of directives](https://github.com/JonasKruckenberg/imagetools/blob/main/docs/directives.md).
## Loading images dynamically from a CDN
In some cases, the images may not be accessible at build time — e.g. they may live inside a content management system or elsewhere.
Using a content delivery network (CDN) can allow you to optimize these images dynamically, and provides more flexibility with regards to sizes, but it may involve some setup overhead and usage costs. Depending on caching strategy, the browser may not be able to use a cached copy of the asset until a [304 response](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/304) is received from the CDN. Building HTML to target CDNs allows using an ` ` tag since the CDN can serve the appropriate format based on the `User-Agent` header, whereas build-time optimizations must produce `` tags with multiple sources. Finally, some CDNs may generate images lazily, which could have a negative performance impact for sites with low traffic and frequently changing images.
CDNs can generally be used without any need for a library. However, there are a number of libraries with Svelte support that make it easier. [`@unpic/svelte`](https://unpic.pics/img/svelte/) is a CDN-agnostic library with support for a large number of providers. You may also find that specific CDNs like [Cloudinary](https://svelte.cloudinary.dev/) have Svelte support. Finally, some content management systems (CMS) which support Svelte (such as [Contentful](https://www.contentful.com/sveltekit-starter-guide/), [Storyblok](https://www.storyblok.com/docs/guides/svelte), and [Contentstack](https://www.contentstack.com/docs/developers/sample-apps/build-a-starter-website-with-sveltekit-and-contentstack)) have built-in support for image handling.
## Best practices
- For each image type, use the appropriate solution from those discussed above. You can mix and match all three solutions in one project. For example, you may use Vite's built-in handling to provide images for ` ` tags, display images on your homepage with `@sveltejs/enhanced-img`, and display user-submitted content with a dynamic approach.
- Consider serving all images via CDN regardless of the image optimization types you use. CDNs reduce latency by distributing copies of static assets globally.
- Your original images should have a good quality/resolution and should have 2x the width it will be displayed at to serve HiDPI devices. Image processing can size images down to save bandwidth when serving smaller screens, but it would be a waste of bandwidth to invent pixels to size images up.
- For images which are much larger than the width of a mobile device (roughly 400px), such as a hero image taking the width of the page design, specify `sizes` so that smaller images can be served on smaller devices.
- For important images, such as the [largest contentful paint (LCP)](https://web.dev/articles/lcp) image, set `fetchpriority="high"` and avoid `loading="lazy"` to prioritize loading as early as possible.
- Give the image a container or styling so that it is constrained and does not jump around while the page is loading affecting your [cumulative layout shift (CLS)](https://web.dev/articles/cls). `width` and `height` help the browser to reserve space while the image is still loading, so `@sveltejs/enhanced-img` will add a `width` and `height` for you.
- Always provide a good `alt` text. The Svelte compiler will warn you if you don't do this.
- Do not use `em` or `rem` in `sizes` and change the default size of these measures. When used in `sizes` or `@media` queries, `em` and `rem` are both defined to mean the user's default `font-size`. For a `sizes` declaration like `sizes="(min-width: 768px) min(100vw, 108rem), 64rem"`, the actual `em` or `rem` that controls how the image is laid out on the page can be different if changed by CSS. For example, do not do something like `html { font-size: 62.5%; }` as the slot reserved by the browser preloader will now end up being larger than the actual slot of the CSS object model once it has been created.
# Accessibility
SvelteKit は、アプリにアクセシブルなプラットフォームをデフォルトで提供するよう努めています。Svelte の [コンパイル時のアクセシビリティチェック(compile-time accessibility checks)](../svelte/compiler-warnings) は、あなたがビルドする SvelteKit アプリケーションにも適用されます。
ここでは、SvelteKit の組み込みのアクセシビリティ(accessibility)機能がどのように動作するか、そしてこれらの機能が可能な限りうまく動作するようにするために必要なことについて説明します。SvelteKit はアクセシブルな基盤を提供しますが、アプリケーションのコードをアクセシブルにするのはあなたの責任であることを覚えておいてください。もし、アクセシビリティ(accessibility)についてよく知らないのであれば、このガイドの ["参考文献"](accessibility#Further-reading) セクションで、その他のリソースを参照してください。
私たちは、アクセシビリティ(accessibility)を正しく行うのは難しいことだと認識しています。SvelteKit のアクセシビリティ対応について改善を提案したい方は、[GitHub issue を作成](https://github.com/sveltejs/kit/issues) してください。
## Route announcements
旧来のサーバーレンダリングアプリケーションでは、全てのナビゲーション (例えば、`` タグをクリックするなど) で、ページのフルリロードを引き起こします。これが起こると、スクリーンリーダーやその他の支援技術が新しいページのタイトルを読み上げ、それによってユーザーはページが変更されたことを理解します。
SvelteKit では、ページ間のナビゲーションではページのリロードが発生しないため ([クライアントサイドルーティング](glossary#Routing)として知られる)、SvelteKit はナビゲーションごとに新しいページ名が読み上げられるように[ライブリージョン](https://developer.mozilla.org/ja/docs/Web/Accessibility/ARIA/ARIA_Live_Regions)をページに注入します。これは、`` 要素を検査することで、アナウンスするページ名を決定します。
この動作のために、アプリの全ページにユニークで説明的なタイトルを付けるべきです。SvelteKit では、各ページに `` 要素を配置することでこれを行うことができます:
```svelte
Todo List
```
これにより、スクリーンリーダーやその他の支援技術が、ナビゲーション後に新しいページを識別することができるようになります。説明的なタイトルを提供することは、[SEO](seo#Manual-setup-title-and-meta) にとっても重要なことです。
## フォーカス管理
旧来のサーバーレンダリングアプリケーションでは、ナビゲーションでフォーカスがページのトップにリセットされます。これによって、キーボードやスクリーンリーダーを使用して web をブラウジングする方が、ページの先頭からやり取りできるようになります。
クライアントサイドルーティング中にこの挙動をシミュレートするために、SvelteKit は各ナビゲーションや [強化されたフォーム送信(enhanced form submission)](https://kit.svelte.jp/docs/form-actions#Progressive-enhancement) の後、`` 要素にフォーカスを合わせます。1つ例外があります - [`autofocus`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autofocus) 属性が付いている要素が存在する場合、SvelteKit はその要素にフォーカスを合わせます。この属性を使用するときは、[支援技術(assistive technology)に対する影響を必ず考慮](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autofocus#accessibility_considerations)してください。
SvelteKit のフォーカス管理をカスタマイズしたい場合は、`afterNavigate` hook を使います:
```js
///
// ---cut---
import { afterNavigate } from '$app/navigation';
afterNavigate(() => {
/** @type {HTMLElement | null} */
const to_focus = document.querySelector('.focus-me');
to_focus?.focus();
});
```
[`goto`]($app-navigation#goto) 関数を使用して、プログラムで別のページにナビゲーションさせることもできます。デフォルトでは、これはクライアントサイドルーティングでリンクをクリックするのと同じ動作です。しかし `goto` は、`keepFocus` オプション を受け付けます。このオプションは、フォーカスをリセットする代わりに、現在フォーカスされている要素にフォーカスを保持したままにします。このオプションを有効にする場合は、現在フォーカスされている要素がナビゲーション後にもまだ存在することを確かめてください。もしその要素が存在しなければ、ユーザーのフォーカスは失われ、支援技術のユーザーにとって混乱した体験になります。
## The "lang" attribute
デフォルトでは、SvelteKit のページテンプレートには、ドキュメントのデフォルト言語に英語が設定されています。もしコンテンツが英語でない場合、`src/app.html` の `` 要素を更新し、正しい [`lang`](https://developer.mozilla.org/ja/docs/Web/HTML/Global_attributes/lang#accessibility) 属性を持たせる必要があります。これによって、ドキュメントを読む支援技術が正しい発音を使えるようになります。例えば、コンテンツがドイツ語の場合、`app.html` を以下のように更新してください:
```html
/// file: src/app.html
```
コンテンツが複数の言語で使用可能な場合、開いているページの言語に基づいて `lang` 属性を設定できるようにする必要があります。これは、SvelteKit の [handle hook](hooks#Server-hooks-handle) を使用して行うことができます:
```html
/// file: src/app.html
```
```js
/// file: src/hooks.server.js
// @filename: utils.ts
export function get_lang(event: import('@sveltejs/kit').RequestEvent) {
return 'en';
}
// @filename: hooks.server.js
import { get_lang } from './utils';
// ---cut---
/** @type {import('@sveltejs/kit').Handle} */
export function handle({ event, resolve }) {
return resolve(event, {
transformPageChunk: ({ html }) => html.replace('%lang%', get_lang(event))
});
}
```
## その他の参考情報
ほとんどの場合、アクセシブルな SvelteKit アプリを構築するのはアクセシブルな Web アプリを構築するのと同じです。以下の一般的なアクセシビリティ(accessibility)に関するリソースから得られる情報は、どんな Web エクスペリエンスを構築する場合でも適用できるはずです
- [MDN Web Docs: Accessibility](https://developer.mozilla.org/en-US/docs/Learn/Accessibility)
- [The A11y Project](https://www.a11yproject.com/)
- [How to Meet WCAG (Quick Reference)](https://www.w3.org/WAI/WCAG21/quickref/)
# SEO
SEO で最も重要なのは、高品質なコンテンツを作ること、そしてそれが web 上で広くリンクされることです。しかし、ランクが高いサイトを構築するためにいくつか技術的に考慮すべきこともあります。
## Out of the box
### SSR
近年、検索エンジンはクライアントサイドの JavaScript でレンダリングされたコンテンツのインデックスを改善してきましたが、サーバーサイドレンダリングされたコンテンツのほうがより頻繁に、より確実にインデックスされます。SvelteKit はデフォルトで SSR を採用しています。[`handle`](hooks#Server-hooks-handle) で無効にすることもできますが、適切な理由がない場合はそのままにしておきましょう。
> [!NOTE] SvelteKit のレンダリングは高度な設定が可能です。必要であれば、[動的なレンダリング(dynamic rendering)](https://developers.google.com/search/docs/advanced/javascript/dynamic-rendering) を実装することも可能です。一般的には推奨されません、SSR には SEO 以外のメリットもあるからです。
### パフォーマンス
[Core Web Vitals](https://web.dev/vitals/#core-web-vitals) のような指標は検索エンジンのランクに影響を与えます。Svelte と SvelteKit はオーバーヘッドが最小限であるため、ハイパフォーマンスなサイトを簡単に構築できです。Google の [PageSpeed Insights](https://pagespeed.web.dev/) や [Lighthouse](https://developers.google.com/web/tools/lighthouse) で、ご自身のサイトをテストすることができます。SvelteKit のデフォルトの [ハイブリッドレンダリング](glossary#Hybrid-app)モードや[画像の最適化](images)といったいくつかの重要な処置を講じることで、サイトの速度を大幅に改善することができます。詳細は [パフォーマンスのページ](performance) をお読みください。
### URLの正規化
SvelteKit は、末尾のスラッシュ(trailing slash)付きのパス名から、末尾のスラッシュが無いパス名にリダイレクトします ([設定](page-options#trailingSlash) で逆にできます)。URLの重複は、SEOに悪影響を与えます。
## Manual setup
### <title> と <meta>
全てのページで、よく練られたユニークな `` と ` ` を [``](../svelte/svelte-head) の内側に置くべきです。説明的な title と description の書き方に関するガイダンスと、検索エンジンにとってわかりやすいコンテンツを作るためのその他の方法については、Google の [Lighthouse SEO audits](https://web.dev/lighthouse-seo/) のドキュメントで見つけることができます。
> [!NOTE] よくあるパターンとしては、ページの [`load`](load) 関数から SEO 関連の `data` を返し、それを最上位の[レイアウト](routing#layout)の `` で ([`page.data`]($app-state) として) 使用することです。
### サイトマップ
[サイトマップ](https://developers.google.com/search/docs/advanced/sitemaps/build-sitemap) は、検索エンジンがサイト内のページの優先順位付けをするのに役立ちます、特にコンテンツの量が多い場合は。エンドポイントを使用してサイトマップを動的に作成できます:
```js
/// file: src/routes/sitemap.xml/+server.js
export async function GET() {
return new Response(
`
`.trim(),
{
headers: {
'Content-Type': 'application/xml'
}
}
);
}
```
### AMP
現代の web 開発における不幸な現実として、サイトの [Accelerated Mobile Pages (AMP)](https://amp.dev/) バージョンを作らなければならないときがある、というのがあります。SvelteKit では、[`inlineStyleThreshold`](configuration#inlineStyleThreshold) オプションを設定することでこれを実現することができます…
```js
/// file: svelte.config.js
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
// since isn't
// allowed, inline all styles
inlineStyleThreshold: Infinity
}
};
export default config;
```
…最上位(root)の `+layout.js`/`+layout.server.js` の `csr` を無効にします…
```js
/// file: src/routes/+layout.server.js
export const csr = false;
```
…`amp` を `app.html` に追加します
```html
...
```
…そして、`transformPageChunk` と、`@sveltejs/amp` からインポートできる `transform` を使用して、HTML を変換します:
```js
/// file: src/hooks.server.js
import * as amp from '@sveltejs/amp';
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
let buffer = '';
return await resolve(event, {
transformPageChunk: ({ html, done }) => {
buffer += html;
if (done) return amp.transform(buffer);
}
});
}
```
ページを amp に変換した結果として未使用の CSS が配布されてしまうのを防ぎたければ、[`dropcss`](https://www.npmjs.com/package/dropcss) を使用すると良いでしょう:
```js
// @filename: ambient.d.ts
declare module 'dropcss';
// @filename: index.js
// ---cut---
/// file: src/hooks.server.js
// @errors: 2307
import * as amp from '@sveltejs/amp';
import dropcss from 'dropcss';
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
let buffer = '';
return await resolve(event, {
transformPageChunk: ({ html, done }) => {
buffer += html;
if (done) {
let css = '';
const markup = amp
.transform(buffer)
.replace('⚡', 'amp') // dropcss can't handle this character
.replace(/`;
});
css = dropcss({ css, html: markup }).css;
return markup.replace('', `${css}`);
}
}
});
}
```
> [!NOTE] `amphtml-validator` を使用して変換された HTML を検証するのに、`handle` hook を利用するのは良いアイデアですが、非常に遅くなってしまうので、ページをプリレンダリングするときだけにしてください。
# Frequently asked questions
## Other resources
[Svelte FAQ](../svelte/faq) と [`vite-plugin-svelte` FAQ](https://github.com/sveltejs/vite-plugin-svelte/blob/main/docs/faq.md) も、これらのライブラリに起因する疑問点には役立ちますのでご参照ください。
## What can I make with SvelteKit?
See [the documentation regarding project types](project-types) for more details.
## package.json の詳細をアプリケーションに含めるにはどうすればよいですか?
アプリケーションで、アプリケーションのバージョン番号やその他の情報を `package.json` から読み込みたい場合は、このように JSON を読み込むことができます:
```ts
// @errors: 2732
/// file: svelte.config.js
import pkg from './package.json' with { type: 'json' };
```
## パッケージをインクルードしようとするとエラーが発生するのですが、どうすれば直せますか?
ライブラリのインクルードに関する問題は、ほとんどが不適切なパッケージングによるものです。ライブラリのパッケージングが Node.js に対応しているかどうかは、[publint の web サイト](https://publint.dev/) でチェックできます。
以下は、ライブラリが正しくパッケージングされているかどうかをチェックする際に気を付けるべき点です:
- `exports` は `main` や `module` などの他のエントリーポイントのフィールドよりも優先されます。`exports` フィールドを追加すると、deep import を妨げることになるため、後方互換性が失われる場合があります。
- `"type": "module"` が指定されていない限り、ESM ファイルは `.mjs` で終わる必要があり、CommonJS ファイルは `.cjs` で終わる必要があります。
- `exports` が定義されていない場合、`main` を定義する必要があり、それは CommonJS ファイル か ESM ファイル でなければならず、前項に従わなければなりません。`module` フィールドが定義されている場合、ESM ファイルを参照している必要があります。
- Svelte コンポーネントは、コンパイルされていない `.svelte` ファイルとして配布し、パッケージに含まれる JS は ESM のみとして記述していなければなりません。TypeScript などのカスタムスクリプトや SCSS などのスタイル言語は、それぞれ vanilla JS と CSS にするために前処理(preprocess)をしなければなりません。Svelte ライブラリのパッケージングには、[`svelte-package`](./packaging) を使用することを推奨しています。このパッケージによって、これらの作業が行われます。
ライブラリが ESM バージョンを配布している場合、特に Svelte コンポーネントライブラリがその依存関係に含まれている場合、Vite を使用するとブラウザ上で最適に動作します。ライブラリの作者に ESM バージョンを提供するよう提案すると良いでしょう。しかし、CommonJS (CJS) の依存関係も上手く扱えるようにするため、デフォルトで、[`vite-plugin-svelte` が Vite にそれらを事前バンドルするよう指示します](https://github.com/sveltejs/vite-plugin-svelte/blob/main/docs/faq.md#what-is-going-on-with-vite-and-pre-bundling-dependencies)。Vite は `esbuild` を使ってそれらを ESM に変換します。
それでもまだ問題が解消されない場合は、[Vite の issue tracker](https://github.com/vitejs/vite/issues) と 該当のライブラリの issue tracker を検索することを推奨します。[`optimizeDeps`](https://vitejs.dev/config/#dep-optimization-options) や [`ssr`](https://vitejs.dev/config/#ssr-options) の設定値をいじることで問題を回避できる場合もありますが、これはあくまで一時的な回避策とし、問題のあるライブラリの修正を優先したほうが良いでしょう。
## view transitions API を使うにはどうすればよいですか?
SvelteKit では [view transitions](https://developer.chrome.com/docs/web-platform/view-transitions/) 向けの特別なインテグレーションはありませんが、[`onNavigate`]($app-navigation#onNavigate) の中で `document.startViewTransition` を呼び出すことにより、クライアントサイドナビゲーション毎に view transition をトリガーすることができます。
```js
// @errors: 2339 2810
import { onNavigate } from '$app/navigation';
onNavigate((navigation) => {
if (!document.startViewTransition) return;
return new Promise((resolve) => {
document.startViewTransition(async () => {
resolve();
await navigation.complete;
});
});
});
```
もっと詳しく知りたければ、Svelte ブログの ["Unlocking view transitions"](/blog/view-transitions) をご参照ください。
## データベースのセットアップはどう行えばよいですか?
データベースにクエリするコードを [サーバールート(server route)](./routing#server) に置いてください。.svelte ファイルの中でデータベースにクエリしないでください。コネクションをすぐにセットアップし、シングルトンとしてアプリ全体からクライアントにアクセスできるように `db.js` のようなものを作ると良いでしょう。`hooks.server.js` で1回セットアップするコードを実行し、データベースヘルパーを必要とするすべてのエンドポイントにインポートできます。
You can use [the Svelte CLI](/docs/cli/overview) to automatically set up database integrations.
## `document` や `window` にアクセスするクライアントサイドライブラリはどう使えばよいですか?
もし `document` や `window` 変数にアクセスする必要があったり、クライアントサイドだけで実行するコードが必要な場合は、`browser` チェックでラップしてください:
```js
///
// ---cut---
import { browser } from '$app/environment';
if (browser) {
// client-only code here
}
```
コンポーネントが最初に DOM にレンダリングされた後にコードを実行したい場合は、`onMount` で実行することもできます:
```js
// @filename: ambient.d.ts
// @lib: ES2015
declare module 'some-browser-only-library';
// @filename: index.js
// ---cut---
import { onMount } from 'svelte';
onMount(async () => {
const { method } = await import('some-browser-only-library');
method('hello world');
});
```
使用したいライブラリに副作用がなければ静的にインポートすることができますし、サーバー側のビルドでツリーシェイクされ、`onMount` が自動的に no-op に置き換えられます:
```js
// @filename: ambient.d.ts
// @lib: ES2015
declare module 'some-browser-only-library';
// @filename: index.js
// ---cut---
import { onMount } from 'svelte';
import { method } from 'some-browser-only-library';
onMount(() => {
method('hello world');
});
```
最後に、`{#await}` ブロックのご使用も検討してみてください:
```svelte
{#await ComponentConstructor}
Loading...
{:then component}
{:catch error}
Something went wrong: {error.message}
{/await}
```
## 別のバックエンド API サーバーを使用するにはどうすれば良いですか?
外部の API サーバーにデータをリクエストするのに [`event.fetch`](./load#Making-fetch-requests) を使用することができますが、[CORS](https://developer.mozilla.org/ja/docs/Web/HTTP/CORS) に対応しなければならず、一般的にはリクエストのプリフライトが必要になり、結果として高レイテンシーになるなど、複雑になることにご注意ください。別のサブドメインへのリクエストも、追加の DNS ルックアップや TLS セットアップなどのためにレイテンシーが増加する可能性があります。この方法を使いたい場合は、[`handleFetch`](./hooks#Server-hooks-handleFetch) が参考になるかもしれません。
別の方法は、頭痛の種である CORS をバイパスするためのプロキシーをセットアップすることです。本番環境では、`/api` などのパスを API サーバーに書き換えます(rewrite)。ローカルの開発環境では、Vite の [`server.proxy`](https://vitejs.dev/config/server-options.html#server-proxy) オプションを使用します。
本番環境で書き換え(rewrite)をセットアップする方法は、デプロイ先のプラットフォームに依存します。もし、書き換える方法がなければ、代わりに [API route](./routing#server) を追加します:
```js
/// file: src/routes/api/[...path]/+server.js
/** @type {import('./$types').RequestHandler} */
export function GET({ params, url }) {
return fetch(`https://example.com/${params.path + url.search}`);
}
```
(必要に応じて、`POST`/`PATCH` などのリクエストもプロキシし、`request.headers` も転送(forward)する必要があることにご注意ください)
## ミドルウェア(middleware)を使うにはどうすればよいですか?
`adapter-node` は、プロダクションモードで使用するためのミドルウェアを自分のサーバで構築します。開発モードでは、Vite プラグインを使用して Vite にミドルウェア(middleware) を追加することができます。例えば:
```js
/// file: vite.config.js
import { sveltekit } from '@sveltejs/kit/vite';
/** @type {import('vite').Plugin} */
const myPlugin = {
name: 'log-request-middleware',
configureServer(server) {
server.middlewares.use((req, res, next) => {
console.log(`Got request ${req.url}`);
next();
});
}
};
/** @type {import('vite').UserConfig} */
const config = {
plugins: [myPlugin, sveltekit()]
};
export default config;
```
順序を制御する方法など、詳しくは [Vite の `configureServer` のドキュメント](https://vitejs.dev/guide/api-plugin.html#configureserver) をご覧ください。
## Yarn を使うには?
### Yarn 2 で動作しますか?
Sort of. The Plug'n'Play feature, aka 'pnp', is broken (it deviates from the Node module resolution algorithm, and [doesn't yet work with native JavaScript modules](https://github.com/yarnpkg/berry/issues/638) which SvelteKit — along with an [increasing number of packages](https://github.com/wooorm/npm-esm-vs-cjs) — uses). You can use `nodeLinker: 'node-modules'` in your [`.yarnrc.yml`](https://yarnpkg.com/configuration/yarnrc#nodeLinker) file to disable pnp, but it's probably easier to just use npm or [pnpm](https://pnpm.io/), which is similarly fast and efficient but without the compatibility headaches.
### Yarn 3 を使用するにはどうすれば良いですか?
現時点の、最新の Yarn (version 3) の ESM サポート は [experimental](https://github.com/yarnpkg/berry/pull/2161) であるようです。
結果は異なるかもしれませんが、下記が有効なようです。最初に新しいアプリケーションを作成します:
```sh
yarn create svelte myapp
cd myapp
```
And enable Yarn Berry:
```sh
yarn set version berry
yarn install
```
Yarn Berry の興味深い機能の1つに、ディスク上のプロジェクトごとに複数のコピーを持つのではなく、パッケージ用に単一のグローバルキャッシュを持つことができる、というのがあります。しかし、`enableGlobalCache` の設定を true にするとビルドが失敗するため、`.yarnrc.yml` ファイルに以下を追加することを推奨します:
```yaml
nodeLinker: node-modules
```
これによってパッケージはローカルの node_modules ディレクトリにダウンロードされますが、上記の問題は回避され、現時点では Yarn の version 3 を使用するベストな方法となります。
# Integrations
## `vitePreprocess`
[`vitePreprocess`](https://github.com/sveltejs/vite-plugin-svelte/blob/main/docs/preprocess.md) preprocesses `