コンテンツにスキップ
svelte-vitals
日本語
Esc
移動開く⌘Jプレビュー
このページの内容

correctness/instance-browser-global · コンポーネント初期化中の browser global

インスタンススクリプトは SSR 時にサーバーでも実行されるため、トップレベルで window や document を参照するとレンダリングが落ちます。

重大度: warning · カテゴリ: correctness

チェック内容

コンポーネントの <script> トップレベルでの browser 専用 global(correctness/server-browser-global と同じリスト)の読み取りを検出します。このコードはコンポーネントの SSR レンダリングのたびにサーバーで実行されます。ガードの扱いも同じです: $app/environmentbrowsertypeof チェック(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'
  }
};