Comfy-Org / Comfy-Org/ComfyUI_frontend
docs/lint: document and enforce preference for createSharedComposable over module-scoped let singletons
- Dominant language
- TypeScript
- Stars
- 2k
- Forks
- 699
- Avg merge
- 1d 7h
- Merged PRs (30d)
- 490
Description
## Background
Raised during review of PR #11420 (comment: https://github.com/Comfy-Org/ComfyUI_frontend/pull/11420#discussion_r3107573903) by @christian-byrne.
When building singleton composables, developers sometimes reach for a module-scoped `let` variable (e.g. `let instance: Foo | undefined`). This pattern has several drawbacks compared to [`createSharedComposable`](https://vueuse.org/shared/createSharedComposable/) from VueUse.
## Problems with the `let` module-scoped singleton pattern
- **SSR cross-request leakage** — if the module stays loaded on the server, the singleton accidentally becomes shared across requests, which is a serious correctness issue.
- **HMR unpredictability** — module instances may be re-evaluated or preserved in unpredictable ways during hot-module replacement, making dev-mode debugging harder.
- **No automatic cleanup** — watchers, intervals, listeners, and sockets started inside the singleton must be managed manually; there is no lifecycle hook to clean them up.
- **No scoped singleton lifecycle** — the `let` pattern cannot easily implement "create once when the first consumer mounts, dispose when the last consumer unmounts", which is often the optimal behaviour.
- **`createSharedComposable` disposes reactivity automatically** — watchers, computeds, and other effect-scope-tracked side effects are torn down when the last consumer unmounts.
- **Easier to test** — `createSharedComposable` can be reset between tests without module cache tricks.
## Requested action
Add guidance in **one or more** of the following places (team to decide):
1. **`AGENTS.md`** (or equivalent agent/contributor guidelines) — a prose rule such as: _"Prefer `createSharedComposable` from VueUse over module-scoped `let` variables when creating singleton composables. The `let` pattern is only acceptable where `createSharedComposable` is clearly inferior (e.g., the singleton must outlive all Vue component trees)."_
2. **ESLint custom rule or `no-restricted-syntax`** — a lint rule that flags bare `let` declarations at the top level of `src/composables/**` files when the declared type is not a primitive, guiding developers toward `createSharedComposable`.
3. **Both** — prose guidance for context + lint rule for enforcement.
## References
- VueUse docs: https://vueuse.org/shared/createSharedComposable/
- Originating PR: #11420
- Originating comment: https://github.com/Comfy-Org/ComfyUI_frontend/pull/11420#discussion_r3107573903
┆Issue is synchronized with this [Notion page](https://www.notion.so/Issue-11427-docs-lint-document-and-enforce-preference-for-createSharedComposable-over-module-sco-3476d73d3650814f9216e7de532bf722) by [Unito](https://www.unito.io)
Contributor guide
Assessment
This issue has not been assessed yet.