@wcstack/state 1.21.6 → 1.21.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.ja.md CHANGED
@@ -1832,6 +1832,47 @@ buildBindings(root)
1832
1832
  - **StateAddress** — PathInfo + ListIndex の組み合わせ
1833
1833
  - **AbsoluteStateAddress** — 状態名 + StateAddress(クロス状態参照用)
1834
1834
 
1835
+ ## パフォーマンス
1836
+
1837
+ リポジトリ同梱の [js-framework-benchmark](https://github.com/krausest/js-framework-benchmark) 流
1838
+ ドライバ(`e2e/bench/jsfb-verify.mjs`・`e2e/bench/memory-profile.mjs`)で、標準の
1839
+ 1,000 / 10,000 行テーブルページを計測(headless Chromium・中央値・両実装を同一
1840
+ セッションで連続実行)。`@wcstack/state` は公式の keyed 判定に合格しつつ、行 DOM
1841
+ を上限 1,000 行の有界プールでリサイクルします。
1842
+
1843
+ | 所要時間(ms・中央値) | `@wcstack/state` | [`@wcstack/signals`](../signals/) |
1844
+ |---|---|---|
1845
+ | 1,000 行の生成 | 25.2 | 9.5 |
1846
+ | 1,000 行の全置換 | 18.8 | 12.5 |
1847
+ | 10,000 行の 10 行ごと更新 | 11.4 | 4.7 |
1848
+ | 行の選択 | 0.1 | 0.4 |
1849
+ | 2 行の入れ替え | 0.9 | 0.4 |
1850
+ | 行の削除 | 2.8 | 0.6 |
1851
+ | 10,000 行への 1,000 行追加 | 48.6 | 14.2 |
1852
+ | 10,000 行のクリア | 54.6 | 52.2 |
1853
+
1854
+ | 強制 GC 後のヒープ(MB) | `@wcstack/state` | `@wcstack/signals` |
1855
+ |---|---|---|
1856
+ | ページ表示直後 | 1.0 | 0.6 |
1857
+ | 1,000 行生成後 | 5.6 | 3.5 |
1858
+ | 1,000 行×5 回置換後 | 6.4 | 3.7 |
1859
+ | 10,000 行生成後 | 35.1 | 18.0 |
1860
+ | 10,000 行生成 + クリア後 | 13.2 | 1.9 |
1861
+
1862
+ 正直な読み方:
1863
+
1864
+ - 対話系の操作(選択 / 入れ替え / 削除)は数ミリ秒以下で、巨大リストのクリアは
1865
+ signals 実装と同等です。
1866
+ - 行の生成・追加は `@wcstack/signals` の約 2.5〜3.5 倍のコストです。これは本
1867
+ パッケージが行ごとに構築する宣言的バインディング台帳の対価で、`data-wcs` の
1868
+ 検査・DevTools の配線表示・SSR ハイドレーションを支えているのは同じ台帳です。
1869
+ 両パッケージは相互運用できるため、ホットなリストだけ signals の `For` で描画
1870
+ し、残りのページは宣言的なまま保てます。
1871
+ - クリア後に残るヒープは、次のリスト生成を安くする有界の行プールです。
1872
+
1873
+ 絶対値は 1 台の開発機での計測です(v1.21.6 + PR#87 の clear リーク修正)。
1874
+ `e2e/bench/` のドライバで手元のハードウェアでも再現できます。
1875
+
1835
1876
  ## サーバーサイドレンダリング
1836
1877
 
1837
1878
  `@wcstack/state` は [`@wcstack/server`](../server/) パッケージと連携して SSR をサポートしています。クライアント用に書いたテンプレートがそのままサーバーでレンダリングされます — 変更不要。
package/README.md CHANGED
@@ -1834,6 +1834,50 @@ Paths like `users.*.name` are decomposed into:
1834
1834
  - **StateAddress** — combination of PathInfo + ListIndex
1835
1835
  - **AbsoluteStateAddress** — state name + StateAddress (for cross-state references)
1836
1836
 
1837
+ ## Performance
1838
+
1839
+ Measured with the repository's [js-framework-benchmark](https://github.com/krausest/js-framework-benchmark)-style
1840
+ drivers (`e2e/bench/jsfb-verify.mjs`, `e2e/bench/memory-profile.mjs`) against the
1841
+ standard 1,000 / 10,000-row table page — headless Chromium, medians, both
1842
+ implementations measured back-to-back in the same session. `@wcstack/state`
1843
+ passes the official keyed-mode classification while recycling row DOM through a
1844
+ bounded pool (up to 1,000 rows).
1845
+
1846
+ | Duration (ms, median) | `@wcstack/state` | [`@wcstack/signals`](../signals/) |
1847
+ |---|---|---|
1848
+ | create 1,000 rows | 25.2 | 9.5 |
1849
+ | replace all 1,000 rows | 18.8 | 12.5 |
1850
+ | update every 10th of 10,000 | 11.4 | 4.7 |
1851
+ | select row | 0.1 | 0.4 |
1852
+ | swap 2 rows | 0.9 | 0.4 |
1853
+ | remove row | 2.8 | 0.6 |
1854
+ | append 1,000 to 10,000 | 48.6 | 14.2 |
1855
+ | clear 10,000 rows | 54.6 | 52.2 |
1856
+
1857
+ | Heap after forced GC (MB) | `@wcstack/state` | `@wcstack/signals` |
1858
+ |---|---|---|
1859
+ | page ready | 1.0 | 0.6 |
1860
+ | after create 1,000 | 5.6 | 3.5 |
1861
+ | after 5× replace 1,000 | 6.4 | 3.7 |
1862
+ | after create 10,000 | 35.1 | 18.0 |
1863
+ | after create 10,000 + clear | 13.2 | 1.9 |
1864
+
1865
+ How to read this, honestly:
1866
+
1867
+ - Interactive operations (select / swap / remove) run in a few milliseconds or
1868
+ less, and clearing a huge list matches the signals implementation.
1869
+ - Creating and appending rows costs ~2.5–3.5× `@wcstack/signals`. That is the
1870
+ price of the declarative binding ledger this package builds per row — the same
1871
+ ledger that powers `data-wcs` inspection, DevTools wiring, and SSR hydration.
1872
+ The two packages interoperate, so a hot list can be rendered with signals'
1873
+ `For` while the rest of the page stays declarative.
1874
+ - The heap retained after a clear is the bounded row pool that makes the next
1875
+ list population cheap.
1876
+
1877
+ Absolute numbers are from one development machine (v1.21.6 + the clear-leak fix
1878
+ in PR#87); the drivers in `e2e/bench/` reproduce the comparison on your own
1879
+ hardware.
1880
+
1837
1881
  ## Server-Side Rendering
1838
1882
 
1839
1883
  `@wcstack/state` supports SSR via the companion [`@wcstack/server`](../server/) package. The same templates you write for the client render on the server — no changes needed.
package/dist/index.esm.js CHANGED
@@ -3849,13 +3849,22 @@ class BindingSession {
3849
3849
  }
3850
3850
  /**
3851
3851
  * 全 record を teardown を走らせずに終端化する(canWholesaleDestroy が true の
3852
- * content 専用)。イベント listener・アドレス台帳・loopContext はノード/binding
3853
- * もろとも GC で崩壊する(recordByBinding 以下は全て弱参照)。
3852
+ * content 専用)。イベント listenerloopContext・パターン台帳(listIndex キー)は
3853
+ * ノード/binding もろとも GC で崩壊する(recordByBinding 以下は全て弱参照)。
3854
+ * 例外は null-listIndex の従来台帳(record.address): キーの intern 済み
3855
+ * AbsoluteStateAddress が PathInfo キャッシュ経由で生涯生存するため GC で
3856
+ * 崩壊せず、共有エントリに残った binding が binding.node 経由で行 DOM 全体を
3857
+ * 永久リークする。ここだけ明示除去する(行イベント binding が典型で行あたり
3858
+ * 高々数件・Set.delete のみなので wholesale の速度特性は保たれる)。
3854
3859
  * handlerBindingRegistry のカウンタは減らないが、残るのはキー文字列と数値のみで
3855
3860
  * 実害はない設計(handlerBindingRegistry.ts の弱参照化コメント参照)。
3856
3861
  */
3857
3862
  destroyRecords() {
3858
3863
  for (const record of this.records) {
3864
+ if (record.address !== null) {
3865
+ removeBindingByAbsoluteStateAddress(record.address, record.info);
3866
+ record.address = null;
3867
+ }
3859
3868
  record.phase = "disposed";
3860
3869
  record.teardowns = null;
3861
3870
  }
@@ -6864,7 +6873,7 @@ async function buildBindings(root) {
6864
6873
  }
6865
6874
  }
6866
6875
 
6867
- var version = "1.21.6";
6876
+ var version = "1.21.7";
6868
6877
  var pkg = {
6869
6878
  version: version};
6870
6879