Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
f941fc4
docs: plan effect adoption
ScriptedAlchemy Jun 26, 2026
cb8360c
feat: use effect for transform executor cleanup
ScriptedAlchemy Jun 26, 2026
5cce881
fix: align effect tests with transform config
ScriptedAlchemy Jun 26, 2026
5130748
feat: expand effect lifecycle orchestration
ScriptedAlchemy Jun 27, 2026
922efe8
perf: defer dev typegen watch startup
ScriptedAlchemy Jun 27, 2026
1d5b9b4
feat: use effect for bounded prerender scheduling
ScriptedAlchemy Jun 27, 2026
1238eb7
feat: use effect deferred for dev readiness
ScriptedAlchemy Jun 27, 2026
c6e44ab
perf: defer route topology watcher startup
ScriptedAlchemy Jun 27, 2026
198112e
perf: bound route topology directory scans
ScriptedAlchemy Jun 27, 2026
04d0f48
perf: delay dev background startup tasks
ScriptedAlchemy Jun 27, 2026
fc6d873
feat: use effect for bounded concurrency helper
ScriptedAlchemy Jun 27, 2026
65388f4
feat: use effect for prerender request lifecycle
ScriptedAlchemy Jun 27, 2026
356b2bb
feat: use effect for config resolution
ScriptedAlchemy Jun 27, 2026
928b383
feat: use effect for server build resolution
ScriptedAlchemy Jun 27, 2026
3c4ec9c
feat: add effect performance profiling path
ScriptedAlchemy Jun 27, 2026
84caf8e
feat: use effect for build manifest generation
ScriptedAlchemy Jun 27, 2026
e8ae114
feat: use effect for dev server build evaluation
ScriptedAlchemy Jun 27, 2026
1f11065
feat: expand effect adoption across plugin lifecycle
ScriptedAlchemy Jun 27, 2026
54debef
Merge remote-tracking branch 'origin/codex/parallel-dev-compilers' in…
ScriptedAlchemy Jun 28, 2026
02bcedf
chore: simplify effect scheduling cleanup
ScriptedAlchemy Jun 28, 2026
86db9a4
Merge remote-tracking branch 'origin/codex/parallel-dev-compilers' in…
ScriptedAlchemy Jun 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 132 additions & 0 deletions docs/superpowers/plans/2026-06-26-effectts-plugin-adoption.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# EffectTS Plugin Adoption Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Add the first internal Effect-backed scheduling seam to the route transform executor while preserving public Promise APIs and existing React Router generated output.

**Architecture:** Effect is introduced as an internal runtime dependency. The first migration keeps the `RouteTransformExecutor` interface stable and uses Effect behind `close()` cleanup and Promise boundaries, leaving worker-side code untouched.

**Tech Stack:** TypeScript, Rsbuild/Rspack, Rstest, pnpm, Effect 3.x.

---

## Files

- Create: `docs/superpowers/specs/2026-06-26-effectts-plugin-adoption-design.md`
- Create: `docs/superpowers/plans/2026-06-26-effectts-plugin-adoption.md`
- Create: `src/effect-runtime.ts`
- Modify: `package.json`
- Modify: `pnpm-lock.yaml`
- Modify: `src/parallel-route-transforms.ts`
- Modify: `tests/parallel-route-transforms.test.ts`

## Task 1: Add Design And Plan Artifacts

- [ ] **Step 1: Write the design spec**

Create `docs/superpowers/specs/2026-06-26-effectts-plugin-adoption-design.md` with the architecture, non-goals, rollout, and test plan.

- [ ] **Step 2: Write this implementation plan**

Create `docs/superpowers/plans/2026-06-26-effectts-plugin-adoption.md` with task-by-task implementation steps.

- [ ] **Step 3: Commit docs**

Run:

```bash
git add docs/superpowers/specs/2026-06-26-effectts-plugin-adoption-design.md docs/superpowers/plans/2026-06-26-effectts-plugin-adoption.md
git commit -m "docs: plan effect adoption"
```

## Task 2: Add Lifecycle Tests

- [ ] **Step 1: Add tests before production code**

Add tests to `tests/parallel-route-transforms.test.ts` covering:

- `close()` rejects an in-flight worker task.
- `close()` is idempotent and `run()` after close falls back inline.
- A `postMessage` failure clears the source cache so the next request sends full source.

- [ ] **Step 2: Run focused tests and verify the new postMessage test fails**

Run:

```bash
corepack pnpm exec rstest run -c ./rstest.config.ts tests/parallel-route-transforms.test.ts
```

Expected: the source-cache clearing test fails until the worker factory test seam and implementation are added.

## Task 3: Add Effect Dependency And Boundary Helper

- [ ] **Step 1: Add Effect dependency**

Run:

```bash
corepack pnpm add effect
```

- [ ] **Step 2: Add `src/effect-runtime.ts`**

Create a small internal helper that exports:

```ts
import { Effect } from 'effect';

export const runPluginEffect = <A, E>(
effect: Effect.Effect<A, E, never>
): Promise<A> => Effect.runPromise(effect);

export const normalizeEffectError = (cause: unknown): Error =>
cause instanceof Error ? cause : new Error(String(cause));
```

## Task 4: Migrate Route Transform Executor Cleanup

- [ ] **Step 1: Add a worker factory test seam**

Keep `createRouteTransformExecutor()` unchanged for callers. Add an internal exported test helper that accepts a worker factory and delegates to the same implementation.

- [ ] **Step 2: Use Effect inside `close()`**

Replace manual `Promise.all(workers.map(...terminate...))` cleanup with an Effect program that rejects pending tasks, clears maps, terminates workers, and returns through `runPluginEffect`.

- [ ] **Step 3: Preserve behavior**

Keep inline fallback after close, worker startup fallback, transform error propagation, and source-cache invalidation on `postMessage` failure.

## Task 5: Verify And Publish

- [ ] **Step 1: Run focused tests**

```bash
corepack pnpm exec rstest run -c ./rstest.config.ts tests/parallel-route-transforms.test.ts
```

- [ ] **Step 2: Run full verification**

```bash
corepack pnpm run test:core
corepack pnpm exec tsc --noEmit
corepack pnpm run format:check
corepack pnpm run build
corepack pnpm run test:package-interop
git diff --check
```

- [ ] **Step 3: Commit implementation**

```bash
git add package.json pnpm-lock.yaml src/effect-runtime.ts src/parallel-route-transforms.ts tests/parallel-route-transforms.test.ts
git commit -m "feat: use effect for transform executor cleanup"
```

- [ ] **Step 4: Push and open a draft PR**

```bash
git push -u origin codex/effectts-scheduling
gh pr create --draft --base codex/parallel-dev-compilers --head codex/effectts-scheduling
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# EffectTS Plugin Adoption Design

## Goal

Adopt Effect internally in `rsbuild-plugin-react-router` to make async scheduling, lifecycle cleanup, cancellation, retry, and error propagation easier to reason about without changing public plugin APIs or generated React Router framework code.

## Scope

Effect is allowed inside the plugin implementation and build tooling paths. It must not be emitted into generated React Router framework modules, templates, route code, or public plugin configuration types.

The first implementation seam is the route transform executor in `src/parallel-route-transforms.ts`. It already exposes a Promise-shaped `RouteTransformExecutor` with `run()` and `close()`, which makes it possible to migrate internal scheduling while keeping callers unchanged.

Later seams can build on the same internal patterns:

- `src/dev-runtime-controller.ts` and `src/dev-generation.ts` for compiler attempt coordination, invalidation, retry-node scheduling, and stale evaluation cancellation.
- `src/prerender-build.ts` for bounded prerender concurrency and fail-fast semantics.
- Small config/preset hooks only when structured error aggregation is clearly useful.

## Non-Goals

- Do not expose Effect types through `PluginOptions`, `RouteTransformExecutor`, or `loadReactRouterServerBuild`.
- Do not import Effect from `src/templates/*`.
- Do not import Effect from generated virtual React Router modules.
- Do not migrate `src/parallel-route-transform-worker.ts` in the first step; keep worker startup and per-task payloads lean.
- Do not rewrite the whole plugin setup function in one pass.

## Architecture

Add `effect` as a runtime dependency and introduce a small internal adapter module for converting Effect computations back to Promises at Rsbuild/plugin boundaries. The plugin remains Promise-native externally, but internal resources can use Effect concepts where they simplify state:

- `Effect.tryPromise` for worker termination and Promise-returning boundaries.
- `Effect.runPromise` for preserving the existing async API surface.
- `Effect.all` for deterministic close cleanup over worker resources.
- Typed internal helpers for normalizing unknown causes into `Error`.

The first migration keeps the existing `ParallelRouteTransformExecutor` class and replaces manual Promise orchestration in `close()` with Effect-backed cleanup. That is intentionally conservative: it proves dependency, build, type, and test compatibility before moving more subtle lifecycle code.

## Route Transform Executor Behavior To Preserve

- `parallelTransforms: false` runs all tasks inline.
- Invalid explicit worker counts throw the same validation error.
- Worker startup errors disable workers and fall back to inline execution for later tasks.
- Route transform task errors propagate normally.
- `close()` is idempotent.
- `close()` rejects in-flight worker tasks before terminating workers.
- `run()` after `close()` executes inline.
- A failed `postMessage` clears that worker's source cache entry so the next request for the same route sends full source again.

## Test Plan

Add focused tests in `tests/parallel-route-transforms.test.ts` for executor lifecycle behavior before changing implementation:

- `close()` can be called more than once and still allows later inline execution.
- `close()` rejects in-flight tasks.
- A `postMessage` failure clears source cache and the next request sends full code.

Keep existing tests green:

- `corepack pnpm run test:core`
- `corepack pnpm exec tsc --noEmit`
- `corepack pnpm run format:check`
- `corepack pnpm run build`
- `corepack pnpm run test:package-interop`

## Rollout

1. Commit this spec and implementation plan.
2. Add `effect` and the internal Promise boundary helper.
3. Add failing lifecycle tests around route transform executor cleanup.
4. Migrate route transform executor cleanup to Effect internally.
5. Verify the existing suite and package interop.
6. Open a draft PR stacked on the parallel dev compiler PR.

## Risks

Effect adds a real runtime dependency. That is acceptable only if it stays internal and removes enough scheduling complexity over the staged rollout. The first step is intentionally small so the PR proves integration cost before attempting dev-runtime migration.

The dev runtime remains the highest-value target, but it has subtle Rsbuild timing behavior. It should be migrated only after the route transform executor establishes a tested internal Effect pattern.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
"@react-router/node": "^7.13.0",
"@remix-run/node-fetch-server": "^0.13.0",
"@rspack/plugin-react-refresh": "^2.0.2",
"effect": "^3.21.4",
"execa": "^9.6.1",
"fs-extra": "11.3.3",
"isbot": "5.1.34",
Expand Down
Loading
Loading