correctness/base-path-navigation · Root-relative navigation under a base path
ルート相対リンクをハードコードすると kit.paths.base ではなくドメインのルートを指すため、base path の配下ではアプリの外に出てしまい、本番で 404 になります。
重大度: warning · カテゴリ: correctness
チェック内容
対象になるのは base path を設定しているプロジェクトだけです(Vite 設定の sveltekit({ paths: { base } })、または svelte.config.* の kit.paths.base。前者が優先されます)。その場合に、ハードコードされたルート相対リテラルで書かれたナビゲーションを3つの箇所で検出します。
<a href="/about">About</a>
goto('/dashboard');
redirect(303, '/login');
base: '/docs' の下では、これらは /about・/dashboard・/login というドメインのルート、つまりアプリの外を指してしまい、本番環境で404になります。
base path の読み取り方は SvelteKit 自身と同じです。Vite の設定に sveltekit({ paths: { base } }) の引数があればそちらを(この場合 svelte.config は無視されます。SvelteKit 自身も警告を出します)、無ければ svelte.config.js/.ts の kit.paths.base を見ます。
設定側で値を計算している場合、よくある base: dev ? '' : '/repo' のような形も対象です。少なくともどれかの環境では base 配下で配信されるためです。base が無い場合や明示的に base: '' の場合は発火しません。
検出は静的なリテラルだけを対象にします。そのため正しい書き方が誤検出されることはありません。href="{base}/about"、href={resolve('/about')}、goto(resolve('/about'))、goto(`${base}/about`) はいずれも文字列リテラルではなく動的な式だからです。
なぜ重要か
この不具合は開発環境では見えません。base path は通常デプロイ先でだけ適用されるため、手元では base が '' になり、ハードコードされたリンクはすべて動いてしまいます。他のツールも教えてくれません。コンパイラにはただの属性に見え、svelte-check が検査するのは文字列の型で、実行時の解決結果ではないからです。結果として「デプロイしたら全部のリンクが404」という形で表面化します。
修正方法
$app/paths の resolve() でパスを包みます。
<script>
import { resolve } from '$app/paths';
</script>
<a href={resolve('/about')}>About</a>
import { resolve } from '$app/paths';
import { goto } from '$app/navigation';
import { redirect } from '@sveltejs/kit';
goto(resolve('/dashboard')); // コンポーネントや .svelte.ts モジュールで
redirect(303, resolve('/login')); // load 関数や form action で
resolve()(SvelteKit 2.26以降)が base path を前置してくれます。ルートIDを渡せばルートパラメータの埋め込みも行います。非推奨になった base と resolveRoute の置き換えです。
制限事項
対象外:
<form action="/…">、fetch('/api/…')、静的アセット(<img src="/logo.png">、<link href>)。アセットも同じように壊れますが、修正にはresolve()ではなくasset()を使うため別のルールに委ねています。- 動的なパス全般、
<svelte:element this="a">、名前空間インポートのgoto/redirect(import * as nav from '$app/navigation')。 - 静的に読めない
sveltekit()の引数(別ファイルからインポートした設定オブジェクトなど)。推測せずに沈黙します。 - 素の
.ts/.jsモジュールのgoto()。収集対象は.svelte・.svelte.ts・.svelte.jsに限られます。 src/hooks.client.tsやsrc/hooks.tsのredirect()。Kit モジュール側の収集対象から外れています。
モードによる違い
ありません。このルールが読むのは同じ .svelte / .ts のソースファイルなので、CLI、Vite プラグインのビルド、ライブダッシュボードの静的ベースラインのいずれでも結果は同一で、レンダリング済み HTML の解析で再評価されることもありません。--route で実行範囲を絞ると、このルールは動きません。コンポーネントスコープのルールには、検出を紐づけるルートが無いためです。
無効化
export default {
rules: {
'correctness/base-path-navigation': 'off'
}
};