correctness/instance-browser-global · コンポーネント初期化中の browser global
インスタンススクリプトは SSR 時にサーバーでも実行されるため、トップレベルで window や document を参照するとレンダリングが落ちます。
重大度: warning · カテゴリ: correctness
チェック内容
コンポーネントの <script> トップレベルでの browser 専用 global(correctness/server-browser-global と同じリスト)の読み取りを検出します。このコードはコンポーネントの SSR レンダリングのたびにサーバーで実行されます。ガードの扱いも同じです: $app/environment の browser、typeof チェック(early-return ガードを含む)、onMount/$effect 本体、自前の binding、シャドーされたローカルは検出されません。
なぜ重要か
コンポーネント冒頭の const width = window.innerWidth; はブラウザ上とクライアント専用の開発フローでは動きますが、最初の SSR レンダリングで ReferenceError: window is not defined になります。
これが critical ではなく warning なのは、親の {#if browser} の内側でのみレンダリングされる(またはクライアントで動的 import される)コンポーネントは、そもそもサーバーで実行されることがなく、それ自体は正当な作りだからです。ただし、そのことはコンポーネントファイル単体からは証明できません。該当する場合は対象行の直前に // svelte-vitals-disable-next-line correctness/instance-browser-global を書いてください。
$props() の分割代入デフォルト値としてのみ使われる browser global(let { width = window.innerWidth } = $props())も検出されません。デフォルト値は prop が渡されなかった場合にのみ評価され、その評価は SSR 時にも起こり得ますが、スキャナーは分割代入のデフォルト値を走査しません。ガードによる除外ではなく、静かな見逃し(conservative miss)です。
修正方法
<script>
const width = window.innerWidth; // ❌ SSR がクラッシュ
</script>
window のプロパティなら、svelte/reactivity/window(5.11.0 以降)が現在推奨される形です。ガード不要で、サーバーでは undefined、クライアントではリアクティブになります。
<script>
import { innerWidth } from 'svelte/reactivity/window';
</script>
<p>{innerWidth.current}</p>
svelte/reactivity/window がカバーしない場合は、onMount の中で読んでください。onMount はサーバーでは実行されません。
<script>
import { onMount } from 'svelte';
let width2 = $state(0);
onMount(() => {
width2 = window.innerWidth; // ✅ onMount はサーバーでは実行されない
});
</script>
モードによる違い
ありません。このルールが読むのは同じ .svelte / .ts のソースファイルなので、CLI、Vite プラグインのビルド、ライブダッシュボードの静的ベースラインのいずれでも結果は同一で、レンダリング済み HTML の解析で再評価されることもありません。--route で実行範囲を絞ると、このルールは動きません。コンポーネントスコープのルールには、検出を紐づけるルートが無いためです。
無効化
個別に抑制するには、対象行の直前に <!-- svelte-vitals-disable-next-line correctness/instance-browser-global --> を置きます。ルールごと無効化するには、次のように設定します。
export default {
rules: {
'correctness/instance-browser-global': 'off'
}
};