Finalize rename
Lint / lint (push) Successful in 57s

This commit is contained in:
Julien Valverdé
2026-07-26 22:45:01 +02:00
parent 38320b502d
commit a4c3cdf79f
40 changed files with 294 additions and 298 deletions
+3 -3
View File
@@ -2,13 +2,13 @@
## Purpose
This report describes the lifecycle problem in `effect-fc-next`, why abandoned React renders leak Effect scopes, what the experimental implementations attempted, why those implementations are not satisfactory, and how a robust system should be designed.
This report describes the lifecycle problem in `effect-view`, why abandoned React renders leak Effect scopes, what the experimental implementations attempted, why those implementations are not satisfactory, and how a robust system should be designed.
The experimental implementation discussed here has been removed from the source tree. This document is intended as design material for a clean reimplementation.
## Executive summary
The fundamental problem is not scope disposal by itself. It is that `effect-fc-next` performs Effect work and creates resource scopes while React is rendering.
The fundamental problem is not scope disposal by itself. It is that `effect-view` performs Effect work and creates resource scopes while React is rendering.
React distinguishes between two broad phases:
@@ -467,7 +467,7 @@ interface ComponentScope {
Create it at commit and close it at effect cleanup. No registry, snapshot, subscription, speculative timer, or abandonment recovery is necessary unless runtime-wide disposal must independently own it.
## Final recommendation for `effect-fc-next`
## Final recommendation for `effect-view`
Do not attempt to hide both committed component lifecycles and render-time Suspense resources behind one implicit `Scope` mechanism.
@@ -1,10 +1,10 @@
# Effect FC Next error-handling review
# Effect View error-handling review
## Verdict
`ErrorObserver` is a reasonable *opt-in failure notification bus*, but it is
not an application error handler. It neither recovers from errors nor, in
`effect-fc-next`, observes the application's effects by default. Keeping it
`effect-view`, observes the application's effects by default. Keeping it
as the central error-handling mechanism would make error delivery implicit,
incomplete, and easy to duplicate.
@@ -20,7 +20,7 @@ should not replace that state.
## What exists today
`packages/effect-fc-next/src/ErrorObserver.ts` provides a context service
`packages/effect-view/src/ErrorObserver.ts` provides a context service
backed by an unbounded `PubSub<Cause.Cause<E>>`:
- `handle(effect)` uses `Effect.tapCause` to publish every non-successful
@@ -33,7 +33,7 @@ This is narrower than the similarly named service in the legacy
Effect supervisor that attempts to publish every failed fiber. The Next
runtime's `preludeLayer` contains only `Component.ScopeMap`; it does not
install `ErrorObserver.layer`. There are also no `ErrorObserver.handle(...)`
call sites in `effect-fc-next`.
call sites in `effect-view`.
Therefore, as checked at this revision, a consumer can create and subscribe to
the service manually, but no failure is automatically delivered to it. It is
+8 -9
View File
@@ -26,13 +26,12 @@ A production-quality Vite implementation is likely **1018 engineer-days**, in
## Scope examined
The implementation target is `effect-fc-next` (Effect 4 beta), which is
expected to become `effect-view`. The legacy `effect-fc` package is not
supported by the Vite plugin.
The implementation target is `effect-view` (Effect 4 beta). The legacy
`effect-fc` package is not supported by the Vite plugin.
## How Effect View rendering works today
`Component.make` creates a function-shaped descriptor with a `body` property and `ComponentPrototype`; it does not create the React component that will be mounted. See [`packages/effect-fc-next/src/Component.ts`](packages/effect-fc-next/src/Component.ts), around `make`, `makeUntraced`, and `ComponentImplPrototype`.
`Component.make` creates a function-shaped descriptor with a `body` property and `ComponentPrototype`; it does not create the React component that will be mounted. See [`packages/effect-view/src/Component.ts`](packages/effect-view/src/Component.ts), around `make`, `makeUntraced`, and `ComponentImplPrototype`.
The relevant path is:
@@ -45,7 +44,7 @@ source definition
-> mounted React fiber
```
In `effect-fc-next`, `asFunctionComponent` creates a closure over the descriptor
In `effect-view`, `asFunctionComponent` creates a closure over the descriptor
and Effect context. `.use` retains that synthesized function in `componentRef`
while the relevant Effect service identities remain unchanged, and
`withContext` renders the function returned by `.use`.
@@ -88,7 +87,7 @@ Consequently, edits currently propagate through ordinary Vite HMR invalidation.
The initial feasibility study used the legacy implementation for a focused
jsdom/React identity experiment. Its descriptor-caching result also applies to
`effect-fc-next`, but the legacy package is not an implementation target:
`effect-view`, but the legacy package is not an implementation target:
1. Render an Effect View containing `React.useState(0)`.
2. Increment it to `old:1`.
@@ -145,7 +144,7 @@ It should recognize:
- `Component.makeUntraced(...)`
- class declarations extending either factory result
- definitions followed by Effect `pipe` transformations
- aliased imports from `effect-fc-next`
- aliased imports from `effect-view`
For each definition it should inject development-only metadata containing:
@@ -255,7 +254,7 @@ Exit criterion: editing render text updates without a page reload, and incompati
### Phase 1: Vite MVP (47 additional days)
- Implement binding-aware AST detection for all public construction styles.
- Add stable shell/keyed implementation support to the supported `effect-fc-next` Component implementation.
- Add stable shell/keyed implementation support to the supported `effect-view` Component implementation.
- Cover memoized and async traits.
- Add safe self-accept/fallback behavior.
- Add browser integration tests against the example app.
@@ -295,7 +294,7 @@ Minimum cases:
- Async View and Suspense/error recovery.
- Two materializations of the same View under different Effect contexts.
- Reactive and `nonReactiveTags` service changes.
- TanStack Router code splitting used by the `example-next` application.
- TanStack Router code splitting used by the `example` application.
- Successive edits before the previous refresh finishes.
- Syntax error followed by recovery.
- Production build contains no HMR registry/subscription code.