Skip to content
11 changes: 11 additions & 0 deletions .changeset/correct003-effect-onmount.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
'@svelte-vitals/core': minor
'svelte-vitals': minor
'@svelte-vitals/mcp': minor
---

Add **CORRECT003 (effect used as onMount)** — the Correctness/reactivity slice of
#69. Flags an `$effect`/`$effect.pre` whose non-empty body reads no reactive value
(no `$state`/`$derived`/`$props`, no store subscription, no bare function call), so
it never re-runs and should be `onMount`. Reported under `correctness` (warning).
`EffectFact` gains `mountOnly`.
26 changes: 26 additions & 0 deletions docs/src/content/docs/ja/rules/correct003.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
title: CORRECT003 · onMount 代わりの $effect
description: reactive 値を読まない $effect には onMount を使います。
---

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

## チェック内容

空でない本体が reactive 値を一切読まない `$effect` / `$effect.pre` を検出します — `$state`・`$derived`・`$props` の参照、store 購読、裸の関数呼び出し(`foo()`)のいずれも無いものです。そのような effect はマウント後に一度だけ実行され、再実行されません。コンポーネントの instance スクリプトを静的(CLI)解析します。

## なぜ重要か

何にも反応しない `$effect` は実質 `onMount` です。`$effect` を使うとその意図が曖昧になり、リアクティビティの仕組みを誤用します。`onMount` なら「マウント時に一度だけ実行する」ことを直接表現できます。

## 修正方法

```svelte
<script>
import { onMount } from 'svelte';
// $effect(() => { element.focus(); }); の代わりに
onMount(() => {
element.focus();
});
</script>
```
26 changes: 26 additions & 0 deletions docs/src/content/docs/rules/correct003.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
title: CORRECT003 · Effect used as onMount
description: Use onMount for an $effect that reads no reactive value.
---

**Severity:** warning · **Category:** correctness

## What it checks

Flags an `$effect` / `$effect.pre` whose non-empty body reads no reactive value — no `$state`, `$derived`, or `$props`, no store subscription, and no bare function call (`foo()`). Such an effect runs once after mount and never re-runs. Checked by static (CLI) analysis of component instance scripts.

## Why it matters

An `$effect` that never reacts to anything is an `onMount` in disguise. Using `$effect` obscures that intent and misuses the reactivity system; `onMount` says "run this once when the component mounts" directly.

## How to fix

```svelte
<script>
import { onMount } from 'svelte';
// Instead of: $effect(() => { element.focus(); });
onMount(() => {
element.focus();
});
</script>
```
Loading