ページオプション
デフォルトでは、SvelteKit はコンポーネントを最初にサーバーでレンダリング(または プリレンダリング)し、HTML としてクライアントに送信します。その後、ブラウザでコンポーネントを再度レンダリングして、ハイドレーションと呼ばれるプロセスでインタラクティブにします。このため、コンポーネントが両方の場所で実行できることを確認する必要があります。その後、SvelteKit は後続のナビゲーションを引き継ぐルーターを初期化します。
+page.js
または+page.server.js
からオプションをエクスポートするか、共有の+layout.js
または+layout.server.js
を使用してページのグループに対して、ページごとにこれらのオプションを制御できます。アプリ全体のオプションを定義するには、ルートレイアウトからエクスポートします。子レイアウトとページは親レイアウトで設定された値を上書きするため、たとえば、アプリ全体でプリレンダリングを有効にして、動的にレンダリングする必要があるページでは無効にすることができます。
これらのオプションをアプリのさまざまな領域で組み合わせて使用できます。たとえば、マーケティングページをプリレンダリングして速度を最大限に高め、SEOとアクセシビリティのために動的ページをサーバーサイドレンダリングし、管理セクションをクライアントでのみレンダリングすることでSPAにすることができます。これにより、SvelteKit は非常に多用途になります。
prerender
アプリの少なくとも一部のルートは、ビルド時に生成された単純なHTMLファイルとして表現できる可能性があります。これらのルートはプリレンダリングできます。
export const const prerender: true
prerender = true;
あるいは、ルート+layout.js
または+layout.server.js
でexport const prerender = true
を設定し、明示的にプリレンダリング不可としてマークされていないページを除くすべてをプリレンダリングすることもできます。
export const const prerender: false
prerender = false;
prerender = true
のルートは、動的SSRに使用されるマニフェストから除外され、サーバー(またはサーバーレス/エッジ関数)のサイズが小さくなります。場合によっては、ルートをプリレンダリングすると同時にマニフェストに含める場合もあります(たとえば、/blog/[slug]
のようなルートで、最新の/人気のあるコンテンツをプリレンダリングしたいが、ロングテールはサーバーサイドレンダリングしたい場合)—このような場合、3つ目のオプション「auto」があります。
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
関数が含まれている場合…
export const const prerender: true
prerender = true;
/** @type {import('./$types').PageLoad} */
export async function function load({ fetch }: {
fetch: any;
}): Promise<any>
load({ fetch: any
fetch }) {
const const res: any
res = await fetch: any
fetch('/my-server-route.json');
return await const res: any
res.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: true
prerender = true;
export const const load: PageLoad
load: 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: Response
res = await fetch: (input: string | URL | globalThis.Request, init?: RequestInit) => Promise<Response> (+1 overload)
fetch('/my-server-route.json');
return await const res: Response
res.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.js
とsrc/routes/foo/bar/+server.js
は、foo
とfoo/bar
を作成しようとしますが、これは不可能です。
そのため、ファイル拡張子を常に含めることをお勧めします—src/routes/foo.json/+server.js
とsrc/routes/foo/bar.json/+server.js
は、foo.json
とfoo/bar.json
ファイルが調和して並存する結果になります。
ページの場合、foo
ではなくfoo/index.html
を書き込むことでこの問題を回避します。
トラブルシューティング
「次のルートはプリレンダリング可能としてマークされていましたが、プリレンダリングされませんでした」のようなエラーが発生した場合は、問題のルート(またはそれがページの場合、親レイアウト)にexport const prerender = true
がありますが、ページがプリレンダリングクローラーによって到達されなかったため、プリレンダリングされなかったということです。
これらのルートは動的にサーバーサイドレンダリングできないため、ユーザーが問題のルートにアクセスしようとするとエラーが発生します。修正方法はいくつかあります。
config.kit.prerender.entries
またはentries
ページオプションからリンクに従って、SvelteKitがルートを見つけられるようにします。パラメーターを持つページ(つまり、[parameters]
を含むページ)へのリンクをこのオプションに追加します。そうしないと、パラメーターの値が不明なため、プリレンダリングされません。プリレンダリング可能としてマークされていないページは無視され、それらのページへのリンクは、プリレンダリング可能であってもクロールされません。- サーバーサイドレンダリングが有効になっている他のプリレンダリング済みページのいずれかからのリンクを発見することで、SvelteKitがルートを見つけられるようにします。
export const prerender = true
をexport 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
関数をエクスポートすることによって行うことができます。
/** @type {import('./$types').EntryGenerator} */
export function function entries(): {
slug: string;
}[]
entries() {
return [
{ slug: string
slug: 'hello-world' },
{ slug: string
slug: 'another-blog-post' }
];
}
export const const prerender: true
prerender = 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: EntryGenerator
entries: 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: string
slug: 'hello-world' },
{ slug: string
slug: 'another-blog-post' }
];
};
export const const prerender: true
prerender = true;
entries
はasync
関数にすることができ、上記の例のように、CMSまたはデータベースから投稿のリストを取得できます。
ssr
通常、SvelteKitは最初にサーバーでページをレンダリングし、そのHTMLをクライアントに送信してハイドレートします。ssr
をfalse
に設定すると、代わりに空の「シェル」ページがレンダリングされます(たとえば、document
のようなブラウザ専用のグローバル変数を使用する場合など、ページをサーバーでレンダリングできない場合に役立ちますが、ほとんどの場合、推奨されません(付録を参照)。
export const const ssr: false
ssr = false;
// If both `ssr` and `csr` are `false`, nothing will be rendered!
ルート+layout.js
にexport const ssr = false
を追加すると、アプリ全体がクライアントでのみレンダリングされます。これは基本的に、アプリをSPAに変換することを意味します。
csr
通常、SvelteKitはサーバーサイドレンダリングされたHTMLをインタラクティブなクライアントサイドレンダリング(CSR)ページにハイドレートします。一部のページはJavaScriptをまったく必要としません—多くのブログ投稿や「概要」ページはこれに該当します。このような場合、CSRを無効にできます。
export const const csr: false
csr = false;
// If both `csr` and `ssr` are `false`, nothing will be rendered!
CSRを無効にすると、JavaScriptはクライアントに送信されません。つまり
- WebページはHTMLとCSSのみで動作する必要があります。
- すべてのSvelteコンポーネント内の
<script>
タグは削除されます。 <form>
要素はプログレッシブエンハンスメントできません。- リンクは、フルページナビゲーションを使用してブラウザによって処理されます。
- ホットモジュール置換(HMR)は無効になります。
開発中にcsr
を有効にすることができます(たとえば、HMRを利用する場合)
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: boolean
csr = 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
ファイルからも設定をエクスポートできます。
export const const trailingSlash: "always"
trailingSlash = 'always';
このオプションはプリレンダリングにも影響します。trailingSlash
がalways
の場合、/about
のようなルートはabout/index.html
ファイルになります。それ以外の場合はabout.html
が作成され、静的ウェブサーバーの慣例を反映します。
末尾のスラッシュを無視することはお勧めしません。相対パスのセマンティクスは、両方のケースで異なります(
/x
からの./y
は/y
ですが、/x/
からは/x/y
です)。また、/x
と/x/
は別々のURLとして扱われ、SEOに悪影響を及ぼします。
config
アダプターの概念により、SvelteKitはさまざまなプラットフォームで実行できます。これらそれぞれには、デプロイメントをさらに微調整するための特定の設定がある場合があります。たとえば、Vercelでは、アプリケーションの一部をエッジに、他の部分をサーバーレス環境にデプロイすることを選択できます。
config
は、最上位レベルにキーと値のペアを持つオブジェクトです。それ以降の具体的な形状は、使用しているアダプターによって異なります。すべてのアダプターは、型安全のためにインポートするConfig
インターフェースを提供する必要があります。詳細については、使用しているアダプターのドキュメントを参照してください。
/** @type {import('some-adapter').Config} */
export const const config: Config
config = {
Config.runtime: string
runtime: 'edge'
};
import type { Config } from 'some-adapter';
export const const config: Config
config: Config = {
Config.runtime: string
runtime: 'edge'
};
config
オブジェクトは最上位レベルでマージされます(ただし、より深いレベルではマージされません)。つまり、上位の+layout.js
の一部の値のみをオーバーライドする場合は、+page.js
ですべての値を繰り返す必要はありません。たとえば、このレイアウト設定...
export const const config: {
runtime: string;
regions: string;
foo: {
bar: boolean;
};
}
config = {
runtime: string
runtime: 'edge',
regions: string
regions: 'all',
foo: {
bar: boolean;
}
foo: {
bar: boolean
bar: true
}
}
...はこのページの設定によってオーバーライドされます...
export const const config: {
regions: string[];
foo: {
baz: boolean;
};
}
config = {
regions: string[]
regions: ['us1', 'us2'],
foo: {
baz: boolean;
}
foo: {
baz: boolean
baz: true
}
}
...その結果、そのページのconfig値は{ runtime: 'edge', regions: ['us1', 'us2'], foo: { baz: true } }
になります。