メインコンテンツへスキップ

ページオプション

デフォルトでは、SvelteKit はコンポーネントを最初にサーバーでレンダリング(または プリレンダリング)し、HTML としてクライアントに送信します。その後、ブラウザでコンポーネントを再度レンダリングして、ハイドレーションと呼ばれるプロセスでインタラクティブにします。このため、コンポーネントが両方の場所で実行できることを確認する必要があります。その後、SvelteKit は後続のナビゲーションを引き継ぐルーターを初期化します。

+page.jsまたは+page.server.jsからオプションをエクスポートするか、共有の+layout.jsまたは+layout.server.jsを使用してページのグループに対して、ページごとにこれらのオプションを制御できます。アプリ全体のオプションを定義するには、ルートレイアウトからエクスポートします。子レイアウトとページは親レイアウトで設定された値を上書きするため、たとえば、アプリ全体でプリレンダリングを有効にして、動的にレンダリングする必要があるページでは無効にすることができます。

これらのオプションをアプリのさまざまな領域で組み合わせて使用できます。たとえば、マーケティングページをプリレンダリングして速度を最大限に高め、SEOとアクセシビリティのために動的ページをサーバーサイドレンダリングし、管理セクションをクライアントでのみレンダリングすることでSPAにすることができます。これにより、SvelteKit は非常に多用途になります。

prerender

アプリの少なくとも一部のルートは、ビルド時に生成された単純なHTMLファイルとして表現できる可能性があります。これらのルートはプリレンダリングできます。

+page.js/+page.server.js/+server
export const const prerender: trueprerender = true;

あるいは、ルート+layout.jsまたは+layout.server.jsexport const prerender = trueを設定し、明示的にプリレンダリング不可としてマークされていないページを除くすべてをプリレンダリングすることもできます。

+page.js/+page.server.js/+server
export const const prerender: falseprerender = false;

prerender = trueのルートは、動的SSRに使用されるマニフェストから除外され、サーバー(またはサーバーレス/エッジ関数)のサイズが小さくなります。場合によっては、ルートをプリレンダリングすると同時にマニフェストに含める場合もあります(たとえば、/blog/[slug]のようなルートで、最新の/人気のあるコンテンツをプリレンダリングしたいが、ロングテールはサーバーサイドレンダリングしたい場合)—このような場合、3つ目のオプション「auto」があります。

+page.js/+page.server.js/+server
export const const prerender: "auto"prerender = 'auto';

アプリ全体をプリレンダリングするのに適している場合は、adapter-staticを使用できます。これは、任意の静的Webサーバーで使用できるファイルを生成します。

プリレンダラーはアプリのルートから開始し、見つかったプリレンダリング可能なページまたは+server.jsルートのファイルを作成します。各ページは、プリレンダリングの候補となる他のページを指す<a>要素についてスキャンされます—そのため、一般的にアクセスする必要があるページを指定する必要はありません。プリレンダラーでアクセスする必要があるページを指定する必要がある場合は、config.kit.prerender.entriesまたは動的ルートからentries関数をエクスポートすることによって行うことができます。

プリレンダリング中は、$app/environmentからインポートされたbuildingの値はtrueになります。

サーバールートのプリレンダリング

他のページオプションとは異なり、prerender+server.jsファイルにも適用されます。これらのファイルはレイアウトの影響を受けませんが、データを取得するページ(存在する場合)からデフォルト値を継承します。たとえば、+page.jsに次のload関数が含まれている場合…

+page
export const const prerender: trueprerender = true;

/** @type {import('./$types').PageLoad} */
export async function 
function load({ fetch }: {
    fetch: any;
}): Promise<any>
@type{import('./$types').PageLoad}
load
({ fetch: anyfetch }) {
const const res: anyres = await fetch: anyfetch('/my-server-route.json'); return await const res: anyres.json(); }
import type { 
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad
} from './$types';
export const const prerender: trueprerender = true; export const const load: PageLoadload:
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad
= async ({
fetch: {
    (input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
    (input: string | URL | globalThis.Request, init?: RequestInit): Promise<Response>;
}

fetch is equivalent to the native fetch web API, with a few additional features:

  • It can be used to make credentialed requests on the server, as it inherits the cookie and authorization headers for the page request.
  • It can make relative requests on the server (ordinarily, fetch requires a URL with an origin when used in a server context).
  • Internal requests (e.g. for +server.js routes) go directly to the handler function when running on the server, without the overhead of an HTTP call.
  • During server-side rendering, the response will be captured and inlined into the rendered HTML by hooking into the text and json methods of the Response object. Note that headers will not be serialized, unless explicitly included via filterSerializedResponseHeaders
  • During hydration, the response will be read from the HTML, guaranteeing consistency and preventing an additional network request.

You can learn more about making credentialed requests with cookies here

fetch
}) => {
const const res: Responseres = await fetch: (input: string | URL | globalThis.Request, init?: RequestInit) => Promise<Response> (+1 overload)fetch('/my-server-route.json'); return await const res: Responseres.Body.json(): Promise<any>json(); };

src/routes/my-server-route.json/+server.jsは、独自のexport const prerender = falseが含まれていない場合、プリレンダリング可能として扱われます。

プリレンダリングしない場合

基本的なルールは次のとおりです。ページをプリレンダリングするには、直接アクセスする2人のユーザーがサーバーから同じコンテンツを取得する必要があります。

すべてのページがプリレンダリングに適しているわけではありません。プリレンダリングされたコンテンツはすべてのユーザーに表示されます。もちろん、プリレンダリングされたページでonMountでパーソナライズされたデータを取得できますが、これは初期コンテンツが空白になるか、ローディングインジケーターが表示されるため、ユーザーエクスペリエンスが悪くなる可能性があります。

ページのパラメーターに基づいてデータを読み込むページ(src/routes/blog/[slug]/+page.svelteルートなど)をプリレンダリングすることもできます。

プリレンダリング中にurl.searchParamsにアクセスすることは禁止されています。使用する必要がある場合は、ブラウザ内(たとえばonMount内)でのみ使用するようにしてください。

アクションのあるページは、サーバーがアクションPOSTリクエストを処理できる必要があるため、プリレンダリングできません。

ルートの競合

プリレンダリングはファイルシステムに書き込むため、ディレクトリとファイルが同じ名前になる2つのエンドポイントを持つことはできません。たとえば、src/routes/foo/+server.jssrc/routes/foo/bar/+server.jsは、foofoo/barを作成しようとしますが、これは不可能です。

そのため、ファイル拡張子を常に含めることをお勧めします—src/routes/foo.json/+server.jssrc/routes/foo/bar.json/+server.jsは、foo.jsonfoo/bar.jsonファイルが調和して並存する結果になります。

ページの場合、fooではなくfoo/index.htmlを書き込むことでこの問題を回避します。

トラブルシューティング

「次のルートはプリレンダリング可能としてマークされていましたが、プリレンダリングされませんでした」のようなエラーが発生した場合は、問題のルート(またはそれがページの場合、親レイアウト)にexport const prerender = trueがありますが、ページがプリレンダリングクローラーによって到達されなかったため、プリレンダリングされなかったということです。

これらのルートは動的にサーバーサイドレンダリングできないため、ユーザーが問題のルートにアクセスしようとするとエラーが発生します。修正方法はいくつかあります。

  • config.kit.prerender.entriesまたはentriesページオプションからリンクに従って、SvelteKitがルートを見つけられるようにします。パラメーターを持つページ(つまり、[parameters]を含むページ)へのリンクをこのオプションに追加します。そうしないと、パラメーターの値が不明なため、プリレンダリングされません。プリレンダリング可能としてマークされていないページは無視され、それらのページへのリンクは、プリレンダリング可能であってもクロールされません。
  • サーバーサイドレンダリングが有効になっている他のプリレンダリング済みページのいずれかからのリンクを発見することで、SvelteKitがルートを見つけられるようにします。
  • export const prerender = trueexport const prerender = 'auto'に変更します。'auto'のルートは動的にサーバーサイドレンダリングできます。

entries

SvelteKitは、エントリポイントから開始してクロールすることで、自動的にプリレンダリングするページを検出します。デフォルトでは、動的ではないすべてのルートがエントリポイントとして扱われます。たとえば、次のルートがある場合…

/    # non-dynamic
/blog# non-dynamic
/blog/[slug]  # dynamic, because of `[slug]`

…SvelteKitは//blogをプリレンダリングし、その過程で<a href="/blog/hello-world">のようなリンクを発見し、プリレンダリングする新しいページを提供します。

ほとんどの場合、それで十分です。状況によっては、/blog/hello-worldのようなページへのリンクが存在しない(またはプリレンダリングされたページに存在しない)場合があり、その場合はSvelteKitにその存在を知らせる必要があります。

これは、config.kit.prerender.entriesを使用して、または動的ルートに属する+page.js+page.server.js、または+server.jsからentries関数をエクスポートすることによって行うことができます。

src/routes/blog/[slug]/+page.server
/** @type {import('./$types').EntryGenerator} */
export function 
function entries(): {
    slug: string;
}[]
@type{import('./$types').EntryGenerator}
entries
() {
return [ { slug: stringslug: 'hello-world' }, { slug: stringslug: 'another-blog-post' } ]; } export const const prerender: trueprerender = true;
import type { 
type EntryGenerator = () => Promise<Array<Record<string, any>>> | Array<Record<string, any>>
type EntryGenerator = () => Promise<Array<Record<string, any>>> | Array<Record<string, any>>
EntryGenerator
} from './$types';
export const const entries: EntryGeneratorentries:
type EntryGenerator = () => Promise<Array<Record<string, any>>> | Array<Record<string, any>>
type EntryGenerator = () => Promise<Array<Record<string, any>>> | Array<Record<string, any>>
EntryGenerator
= () => {
return [ { slug: stringslug: 'hello-world' }, { slug: stringslug: 'another-blog-post' } ]; }; export const const prerender: trueprerender = true;

entriesasync関数にすることができ、上記の例のように、CMSまたはデータベースから投稿のリストを取得できます。

ssr

通常、SvelteKitは最初にサーバーでページをレンダリングし、そのHTMLをクライアントに送信してハイドレートします。ssrfalseに設定すると、代わりに空の「シェル」ページがレンダリングされます(たとえば、documentのようなブラウザ専用のグローバル変数を使用する場合など、ページをサーバーでレンダリングできない場合に役立ちますが、ほとんどの場合、推奨されません(付録を参照)。

+page
export const const ssr: falsessr = false;
// If both `ssr` and `csr` are `false`, nothing will be rendered!

ルート+layout.jsexport const ssr = falseを追加すると、アプリ全体がクライアントでのみレンダリングされます。これは基本的に、アプリをSPAに変換することを意味します。

csr

通常、SvelteKitはサーバーサイドレンダリングされたHTMLをインタラクティブなクライアントサイドレンダリング(CSR)ページにハイドレートします。一部のページはJavaScriptをまったく必要としません—多くのブログ投稿や「概要」ページはこれに該当します。このような場合、CSRを無効にできます。

+page
export const const csr: falsecsr = false;
// If both `csr` and `ssr` are `false`, nothing will be rendered!

CSRを無効にすると、JavaScriptはクライアントに送信されません。つまり

  • WebページはHTMLとCSSのみで動作する必要があります。
  • すべてのSvelteコンポーネント内の<script>タグは削除されます。
  • <form>要素はプログレッシブエンハンスメントできません。
  • リンクは、フルページナビゲーションを使用してブラウザによって処理されます。
  • ホットモジュール置換(HMR)は無効になります。

開発中にcsrを有効にすることができます(たとえば、HMRを利用する場合)

+page
import { const dev: boolean

Whether the dev server is running. This is not guaranteed to correspond to NODE_ENV or MODE.

dev
} from '$app/environment';
export const const csr: booleancsr = const dev: boolean

Whether the dev server is running. This is not guaranteed to correspond to NODE_ENV or MODE.

dev
;

trailingSlash

デフォルトでは、SvelteKitはURLから末尾のスラッシュを削除します—/about/にアクセスすると、/aboutへのリダイレクトが返されます。この動作はtrailingSlashオプションで変更できます。これは'never'(デフォルト)、'always'、または'ignore'のいずれかになります。

他のページオプションと同様に、この値を+layout.jsまたは+layout.server.jsからエクスポートすると、すべての子ページに適用されます。+server.jsファイルからも設定をエクスポートできます。

src/routes/+layout
export const const trailingSlash: "always"trailingSlash = 'always';

このオプションはプリレンダリングにも影響します。trailingSlashalwaysの場合、/aboutのようなルートはabout/index.htmlファイルになります。それ以外の場合はabout.htmlが作成され、静的ウェブサーバーの慣例を反映します。

末尾のスラッシュを無視することはお勧めしません。相対パスのセマンティクスは、両方のケースで異なります(/xからの./y/yですが、/x/からは/x/yです)。また、/x/x/は別々のURLとして扱われ、SEOに悪影響を及ぼします。

config

アダプターの概念により、SvelteKitはさまざまなプラットフォームで実行できます。これらそれぞれには、デプロイメントをさらに微調整するための特定の設定がある場合があります。たとえば、Vercelでは、アプリケーションの一部をエッジに、他の部分をサーバーレス環境にデプロイすることを選択できます。

configは、最上位レベルにキーと値のペアを持つオブジェクトです。それ以降の具体的な形状は、使用しているアダプターによって異なります。すべてのアダプターは、型安全のためにインポートするConfigインターフェースを提供する必要があります。詳細については、使用しているアダプターのドキュメントを参照してください。

src/routes/+page
/** @type {import('some-adapter').Config} */
export const const config: Config
@type{import('some-adapter').Config}
config
= {
Config.runtime: stringruntime: 'edge' };
import type { Config } from 'some-adapter';

export const const config: Configconfig: Config = {
	Config.runtime: stringruntime: 'edge'
};

configオブジェクトは最上位レベルでマージされます(ただし、より深いレベルではマージされません)。つまり、上位の+layout.jsの一部の値のみをオーバーライドする場合は、+page.jsですべての値を繰り返す必要はありません。たとえば、このレイアウト設定...

src/routes/+layout
export const 
const config: {
    runtime: string;
    regions: string;
    foo: {
        bar: boolean;
    };
}
config
= {
runtime: stringruntime: 'edge', regions: stringregions: 'all',
foo: {
    bar: boolean;
}
foo
: {
bar: booleanbar: true } }

...はこのページの設定によってオーバーライドされます...

src/routes/+page
export const 
const config: {
    regions: string[];
    foo: {
        baz: boolean;
    };
}
config
= {
regions: string[]regions: ['us1', 'us2'],
foo: {
    baz: boolean;
}
foo
: {
baz: booleanbaz: true } }

...その結果、そのページのconfig値は{ runtime: 'edge', regions: ['us1', 'us2'], foo: { baz: true } }になります。

さらに読む

GitHubでこのページを編集する