feat(react): support activity component/data preload outside React runtime context#716
feat(react): support activity component/data preload outside React runtime context#716ENvironmentSet wants to merge 6 commits into
Conversation
- Add Jest + @swc/jest + jsdom + Testing Library to integrations/react, following the inline-config convention of plugin-blocker/plugin-history-sync - Exclude *.spec.* files from esbuild/dts build output; add tsconfig.test.json so `yarn typecheck` covers spec files (incl. Register augmentations) - Type-only cast in PluginRenderer so library source stays type-checkable when specs augment the Register interface - Add a harness smoke spec using an inline renderer plugin (public render API) to avoid a workspace dependency cycle with plugin-renderer-basic Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- FEP-2357-SPEC.md: Linear issue + locked interface design, plus spec-owner decisions (reject semantics, original-reason propagation, retry after failure; loader dedupe / chunk duplicate firing / atomicity left unspecified) - FEP-2357-TEST-PLAN.md: 32 given-when-then test items (A-G), approved by test reviewer after two review rounds Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Translates FEP-2357-TEST-PLAN.md items A2-A9, B1-B3, C1-C2, E1-E10 and
F1-F2 into Jest specs against the public entry (./index). `prepare` is
not implemented yet, so all 25 tests fail with "prepare is not a
function" — verified red for the right reason by temporarily wiring a
reference implementation (all green) and reverting it.
Register augmentation uses optional params only ({ id?: string });
registering required params breaks package-internal typecheck variance
in stackflow.tsx/useStepFlow.ts. Because Register merges globally,
every stackflow() call passes a complete components map via
baseComponents spread.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
D1-D2 verify the current usePrepare behavior that the new prepare must match (spec §3 "thin wrapper"). These run against existing code and pass today. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
G1-G4 are typecheck-only assertions placed in never-called function bodies (swc does not typecheck; runtime execution must be avoided). A1 lives here because Jest requires at least one test per spec file. Until prepare lands, `yarn workspace @stackflow/react typecheck` fails with TS2339 (Property 'prepare' does not exist on StackflowOutput) in both this file and prepare.spec.tsx — a single root cause. Verified that a typed reference implementation turns typecheck fully green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The smoke spec invited removal once real specs cover the same ground; prepare.spec.tsx/usePrepare.spec.tsx now exercise the same harness surface (spec pickup, @swc/jest, jsdom + Testing Library, workspace deps, inline renderer plugin). Keeping it would also break typecheck: Register augmentation merges package-wide, so its stackflow() call would need components for every Prepare* activity registered by the new specs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
@stackflow/link
@stackflow/plugin-basic-ui
@stackflow/plugin-blocker
@stackflow/plugin-google-analytics-4
@stackflow/plugin-history-sync
@stackflow/plugin-lifecycle
@stackflow/plugin-renderer-basic
@stackflow/plugin-renderer-web
@stackflow/react-ui-core
@stackflow/react
commit: |
Deploying stackflow-demo with
|
| Latest commit: |
51ad11d
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://7e048082.stackflow-demo.pages.dev |
| Branch Preview URL: | https://feature-fep-2357.stackflow-demo.pages.dev |
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
stackflow-docs | 51ad11d | Commit Preview URL | Jun 04 2026, 11:26 AM |
Problem
Preloading an activity's resources before entering it — the lazy component chunk and the data described by the activity's
loader— is currently only possible through theusePreparehook.Because
usePrepareis a React hook, it depends on React Context (useConfig,useDataLoader,useActivityComponentMap) and can therefore only be called inside a mounted React tree. This makes it impossible to warm up chunks/data at the moments that matter most for initial-entry performance:In practice, consumers who need render-ahead preloading have had to reach for private APIs (e.g. the lazy component's internal
_load), which is fragile and unsupported.Solution
Expose the same preload capability as a plain function on the
stackflow()output, alongside the existing render-outside APIs (actions,stepActions):Design decisions:
preparecomes from the samestackflow()call asStack/actions, so config and components never have to be passed twice and can never drift from the running instance. Since it does not touch the core store, it is usable from module-evaluation time — before<Stack>is mounted.Preparetype is reused as-is: omittingactivityParamspreloads only the component chunk; passing params also fires the activity's data loader. The returnedPromise<void>resolves when all fired preload work settles.preparedoes not store loader results; injectingloaderDatainto activities remains the loader plugin's responsibility.prepare, so transient failures don't poison the cache. Fire-and-forget callers should attach.catch.usePreparebecomes a thin wrapper over the same implementation, so existing in-tree callers keep working unchanged.RegisteredActivityName/InferActivityParams<K>flow through unchanged, so invalid activity names or params remain compile-time errors.🤖 Generated with Claude Code