@@ -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.
|
||||
|
||||
|
||||
+4
-4
@@ -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
|
||||
@@ -26,13 +26,12 @@ A production-quality Vite implementation is likely **10–18 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 (4–7 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.
|
||||
|
||||
Reference in New Issue
Block a user