From a00a6181e7819284d45206635a1a842c0eb038df Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 7 May 2026 13:37:43 +0000 Subject: [PATCH 1/8] feat(testing): preloadEntries helper for synchronous lazy-entry tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `preloadEntries(modules)` walks every `lazy:` entry on a module set and primes the resolver's per-entry cache. After it resolves, the existing synchronous-thenable fast path in `resolveEntryComponent` (proven by `packages/react/src/resolve-entry.test.tsx:123-150`) takes over — ModuleTab/JourneyOutlet commit the resolved component on the first render with no Suspense fallback flash, so tests no longer need `waitFor` / `act` choreography. - New `preloadEntries(modules)` in `@modular-react/testing` - Re-export `preloadEntry` from testing for a single import surface - Unit tests cover dedupe, idempotence, eager skipping, rejection propagation, and the post-preload synchronous-thenable behavior - Integration test in `module-tab.test.tsx` proves zero fallback mounts and synchronous render after `preloadEntries` - README sections in `@modular-react/testing` and a pointer from the `@modular-react/react` README https://claude.ai/code/session_0166HdHFxs9MBEWdxybXhSkM --- packages/journeys/package.json | 1 + packages/journeys/src/module-tab.test.tsx | 35 ++++++ packages/react/README.md | 2 + packages/testing/README.md | 50 ++++++++ packages/testing/package.json | 2 + packages/testing/src/index.ts | 3 + packages/testing/src/preload-entries.test.ts | 105 ++++++++++++++++ packages/testing/src/preload-entries.ts | 50 ++++++++ packages/testing/vite.config.ts | 8 +- pnpm-lock.yaml | 119 ++++++++++++------- 10 files changed, 330 insertions(+), 45 deletions(-) create mode 100644 packages/testing/src/preload-entries.test.ts create mode 100644 packages/testing/src/preload-entries.ts diff --git a/packages/journeys/package.json b/packages/journeys/package.json index 63d978e..d6a96a8 100644 --- a/packages/journeys/package.json +++ b/packages/journeys/package.json @@ -37,6 +37,7 @@ "devDependencies": { "@modular-react/core": "workspace:*", "@modular-react/react": "workspace:*", + "@modular-react/testing": "workspace:*", "@testing-library/react": "^16.0.0", "@types/react": "^19.0.0", "@types/react-dom": "^19.0.0", diff --git a/packages/journeys/src/module-tab.test.tsx b/packages/journeys/src/module-tab.test.tsx index 8d0450e..e4ddf56 100644 --- a/packages/journeys/src/module-tab.test.tsx +++ b/packages/journeys/src/module-tab.test.tsx @@ -2,6 +2,7 @@ import { act, cleanup, render } from "@testing-library/react"; import { afterEach, describe, expect, it, vi } from "vitest"; import { defineEntry, defineExit, defineModule, schema } from "@modular-react/core"; import type { ModuleEntryProps } from "@modular-react/core"; +import { preloadEntries } from "@modular-react/testing"; import { ModuleTab } from "./module-tab.js"; afterEach(() => { @@ -197,4 +198,38 @@ describe("ModuleTab", () => { }); expect(getByTestId("cid").textContent).toBe("C-9"); }); + + it("after preloadEntries, a lazy entry renders synchronously with no fallback flash", async () => { + // End-to-end proof of the eager-resolution mode: once preloadEntries + // settles, ModuleTab commits the resolved component on the first pass — + // no `await waitFor`, no `act`, and the Suspense fallback never mounts. + const lazyImporter = vi.fn(() => Promise.resolve({ default: Review })); + let fallbackMounts = 0; + const Fallback = () => { + fallbackMounts += 1; + return loading…; + }; + const lazyMod = defineModule({ + id: "review-lazy-eager", + version: "1.0.0", + exitPoints: exits, + entryPoints: { + review: defineEntry({ + lazy: lazyImporter, + fallback: , + input: schema<{ customerId: string }>(), + }), + }, + }); + + await preloadEntries([lazyMod]); + + const { getByTestId } = render( + , + ); + // Synchronous render — no waitFor, no act needed. + expect(getByTestId("cid").textContent).toBe("C-42"); + expect(fallbackMounts).toBe(0); + expect(lazyImporter).toHaveBeenCalledTimes(1); + }); }); diff --git a/packages/react/README.md b/packages/react/README.md index dfca356..6d310d7 100644 --- a/packages/react/README.md +++ b/packages/react/README.md @@ -71,4 +71,6 @@ function PlanCard({ onClick }: { onClick: () => void }) { Calls are idempotent — the underlying `WeakMap` cache returns the same in-flight or resolved promise across hover, click, and any `` that picked the same entry. +In tests, prefer `preloadEntries(modules)` from `@modular-react/testing` — it walks every `lazy:` entry on a module set in one call, so renders commit synchronously without a Suspense fallback flash. See [`@modular-react/testing`](../testing/README.md#eager-resolution-mode-for-lazy-entries). + See the [main documentation](https://github.com/kibertoad/modular-react#readme) for the full guide. diff --git a/packages/testing/README.md b/packages/testing/README.md index 6e7246d..4ee185a 100644 --- a/packages/testing/README.md +++ b/packages/testing/README.md @@ -12,6 +12,7 @@ npm install -D @modular-react/testing - **`resolveModule`**: resolves module contributions (slots, lifecycle) without rendering - **`createMockStore`**: creates a store pre-populated with test state (uses `@modular-react/core`'s built-in store) +- **`preloadEntries`** / **`preloadEntry`**: eager-resolution mode for `lazy:` entries — render synchronously under vitest/jest with no Suspense fallback flash - **Types**: `ResolveModuleOptions`, `ResolveModuleResult` ## Usage @@ -28,6 +29,55 @@ expect(slots.commands).toHaveLength(2); expect(entry.id).toBe("my-module"); ``` +## Eager-resolution mode for `lazy:` entries + +`lazy:` entries normally resolve through `React.lazy` and require an enclosing +`` plus `await waitFor(...)` / `act` choreography to settle. In tests +this is mostly noise — you already know the chunk is local. `preloadEntries` +walks every `lazy:` entry on the given modules, runs each importer once, and +primes the resolver's per-entry cache. Subsequent renders commit the resolved +component synchronously on the first pass; the host's `` boundary +stays in place but its fallback never mounts. + +```typescript +// vitest.setup.ts (or per-file beforeAll) +import { preloadEntries } from "@modular-react/testing"; +import { allModules } from "../src/modules"; + +beforeAll(() => preloadEntries(allModules)); +``` + +Tests then render hosts (`ModuleTab`, `JourneyOutlet`) with no extra ceremony: + +```tsx +import { render } from "@testing-library/react"; +import { ModuleTab } from "@modular-react/journeys"; + +it("renders the lazy review step", () => { + const { getByTestId } = render( + , + ); + // No waitFor, no act, no fallback flash. + expect(getByTestId("cid").textContent).toBe("C-1"); +}); +``` + +For modules built ad-hoc inside a single test (or any case where enumerating +modules upfront is awkward), call `preloadEntry` directly on the entry: + +```typescript +import { preloadEntry } from "@modular-react/testing"; + +const entry = defineEntry({ lazy: () => import("./Review"), input: schema<...>() }); +await preloadEntry(entry); +``` + +`preloadEntries` is idempotent — repeated calls reuse the resolver's cache, so +importers run at most once across the test run. Eager (`component:`) entries +are skipped, as are modules without an `entryPoints` map. `vi.mock(...)` of the +imported chunk works as expected: vitest hoists the mock before +`preloadEntries` runs, so the mocked component is what gets cached. + For rendering modules with a router, use the router-specific testing packages (`@react-router-modules/testing` or `@tanstack-react-modules/testing`). See the [main documentation](https://github.com/kibertoad/modular-react#readme) for the full guide. diff --git a/packages/testing/package.json b/packages/testing/package.json index 309dfe8..c3fa4cd 100644 --- a/packages/testing/package.json +++ b/packages/testing/package.json @@ -31,6 +31,7 @@ }, "devDependencies": { "@modular-react/core": "^1.2.0", + "@modular-react/react": "^2.0.0", "@types/react": "^19.0.0", "@types/react-dom": "^19.0.0", "oxfmt": "^0.43.0", @@ -44,6 +45,7 @@ }, "peerDependencies": { "@modular-react/core": "^1.2.0", + "@modular-react/react": "^2.0.0", "react": "^19.0.0", "react-dom": "^19.0.0" } diff --git a/packages/testing/src/index.ts b/packages/testing/src/index.ts index c1093b3..8cd6295 100644 --- a/packages/testing/src/index.ts +++ b/packages/testing/src/index.ts @@ -1,3 +1,6 @@ export { createMockStore } from "./mock-store.js"; export { resolveModule } from "./resolve-module.js"; export type { ResolveModuleOptions, ResolveModuleResult } from "./resolve-module.js"; +export { preloadEntries } from "./preload-entries.js"; +// Re-export `preloadEntry` so test code only needs one import surface. +export { preloadEntry } from "@modular-react/react"; diff --git a/packages/testing/src/preload-entries.test.ts b/packages/testing/src/preload-entries.test.ts new file mode 100644 index 0000000..90a197b --- /dev/null +++ b/packages/testing/src/preload-entries.test.ts @@ -0,0 +1,105 @@ +import { describe, it, expect, vi } from "vitest"; +import type { ComponentType } from "react"; +import { resolveEntryComponent } from "@modular-react/react"; +import type { + LazyModuleEntryPoint, + ModuleDescriptor, + ModuleEntryProps, +} from "@modular-react/core"; +import { preloadEntries } from "./preload-entries.js"; + +const Stub = (() => null) as unknown as ComponentType>; + +function lazyEntry(importer: () => Promise): LazyModuleEntryPoint { + return { lazy: importer as LazyModuleEntryPoint["lazy"] }; +} + +function module_( + id: string, + entryPoints?: Record, +): ModuleDescriptor { + return { + id, + version: "1.0.0", + ...(entryPoints !== undefined ? { entryPoints } : {}), + } as unknown as ModuleDescriptor; +} + +describe("preloadEntries", () => { + it("invokes every lazy importer exactly once across the module set", async () => { + const importerA = vi.fn(() => Promise.resolve({ default: Stub })); + const importerB = vi.fn(() => Promise.resolve({ default: Stub })); + const importerC = vi.fn(() => Promise.resolve({ default: Stub })); + const modA = module_("a", { x: lazyEntry(importerA), y: lazyEntry(importerB) }); + const modB = module_("b", { z: lazyEntry(importerC) }); + + await preloadEntries([modA, modB]); + + expect(importerA).toHaveBeenCalledTimes(1); + expect(importerB).toHaveBeenCalledTimes(1); + expect(importerC).toHaveBeenCalledTimes(1); + }); + + it("is idempotent — repeat calls reuse the resolver's per-entry cache", async () => { + const importer = vi.fn(() => Promise.resolve({ default: Stub })); + const mod = module_("m", { e: lazyEntry(importer) }); + + await preloadEntries([mod]); + await preloadEntries([mod]); + await preloadEntries([mod]); + + expect(importer).toHaveBeenCalledTimes(1); + }); + + it("skips eager entries (no `lazy:` field)", async () => { + const importer = vi.fn(() => Promise.resolve({ default: Stub })); + const mod = module_("m", { + lazy: lazyEntry(importer), + eager: { component: Stub }, + }); + + await preloadEntries([mod]); + + expect(importer).toHaveBeenCalledTimes(1); + }); + + it("ignores modules without an entryPoints map", async () => { + const mod = module_("headless"); + await expect(preloadEntries([mod])).resolves.toBeUndefined(); + }); + + it("returns a resolved promise when given an empty module list", async () => { + await expect(preloadEntries([])).resolves.toBeUndefined(); + }); + + it("propagates importer rejections", async () => { + const failure = new Error("chunk load failed"); + const importer = vi.fn(() => Promise.reject(failure)); + const mod = module_("m", { e: lazyEntry(importer) }); + + await expect(preloadEntries([mod])).rejects.toBe(failure); + }); + + it("after preload, resolveEntryComponent(entry).preload() resolves SYNCHRONOUSLY", async () => { + // The end-to-end value proposition: post-preload, the resolver's cached + // path returns a synchronous thenable (resolve-entry.ts:90-99). React.lazy + // exploits this to flip status to Resolved without a microtask hop, so a + // subsequent render commits the component on the first pass with no + // Suspense fallback flash. + const importer = vi.fn(() => Promise.resolve({ default: Stub })); + const entry = lazyEntry(importer); + const mod = module_("m", { e: entry }); + + await preloadEntries([mod]); + + let observed = 0; + resolveEntryComponent(entry) + .preload() + .then(() => { + observed += 1; + }); + // No `await`. If the cached path were a real promise, this would be 0 + // until the next microtask. The synchronous thenable fires inline. + expect(observed).toBe(1); + }); +}); diff --git a/packages/testing/src/preload-entries.ts b/packages/testing/src/preload-entries.ts new file mode 100644 index 0000000..3af1d1f --- /dev/null +++ b/packages/testing/src/preload-entries.ts @@ -0,0 +1,50 @@ +import { preloadEntry } from "@modular-react/react"; +import type { ModuleDescriptor, ModuleEntryPoint } from "@modular-react/core"; + +/** + * Eagerly resolves every `lazy:` entry on the given modules so subsequent + * test renders are synchronous — no `` fallback flash, no + * `await waitFor(...)`, no `act` choreography. + * + * After this resolves, the resolver's per-entry cache is populated for every + * lazy entry. The cached path returns a synchronous thenable, so + * `React.lazy`'s `_init` flow flips status to `Resolved` inside the + * `.then(...)` call without crossing a microtask — host components + * (`ModuleTab`, `JourneyOutlet`) still wrap in `` but the fallback + * never mounts. Eager (`component:`) entries are skipped (they're already + * synchronous), as are modules without an `entryPoints` map. + * + * Idempotent: repeated calls reuse the same per-entry import promise via the + * resolver's `WeakMap` cache, so importers run at most once across the test + * run. + * + * @example In `beforeAll` (the typical setup): + * ```ts + * import { preloadEntries } from "@modular-react/testing"; + * import { allModules } from "../src/modules"; + * + * beforeAll(() => preloadEntries(allModules)); + * ``` + * + * @example For modules built ad-hoc per test, call `preloadEntry` directly: + * ```ts + * import { preloadEntry } from "@modular-react/react"; + * + * await preloadEntry(myEntry); + * render(); + * ``` + */ +export function preloadEntries( + modules: readonly ModuleDescriptor[], +): Promise { + const tasks: Promise[] = []; + for (const module of modules) { + if (!module.entryPoints) continue; + for (const entry of Object.values(module.entryPoints) as ModuleEntryPoint[]) { + if (typeof (entry as { lazy?: unknown }).lazy === "function") { + tasks.push(preloadEntry(entry)); + } + } + } + return Promise.all(tasks).then(() => undefined); +} diff --git a/packages/testing/vite.config.ts b/packages/testing/vite.config.ts index a9d19db..30455ce 100644 --- a/packages/testing/vite.config.ts +++ b/packages/testing/vite.config.ts @@ -10,7 +10,13 @@ export default defineConfig({ fileName: "index", }, rollupOptions: { - external: ["react", "react/jsx-runtime", "react-dom", "@modular-react/core"], + external: [ + "react", + "react/jsx-runtime", + "react-dom", + "@modular-react/core", + "@modular-react/react", + ], }, sourcemap: true, }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6b22c00..5bcb318 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -41,7 +41,7 @@ importers: dependencies: '@modular-react/core': specifier: ^1.0.0 - version: link:../../../../packages/core + version: 1.8.1(@types/react@19.2.14) '@react-router-modules/core': specifier: ^2.0.0 version: link:../../../../packages/react-router-core @@ -66,7 +66,7 @@ importers: version: link:../../app-shared '@modular-react/core': specifier: ^1.0.0 - version: link:../../../../../packages/core + version: 1.8.1(@types/react@19.2.14) '@react-router-modules/core': specifier: ^2.0.0 version: link:../../../../../packages/react-router-core @@ -103,10 +103,10 @@ importers: version: link:../modules/integrations '@modular-react/core': specifier: ^1.0.0 - version: link:../../../../packages/core + version: 1.8.1(@types/react@19.2.14) '@modular-react/react': specifier: ^1.0.0 - version: link:../../../../packages/react + version: 1.4.0(@modular-react/core@1.8.1(@types/react@19.2.14))(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@react-router-modules/core': specifier: ^2.0.0 version: link:../../../../packages/react-router-core @@ -146,7 +146,7 @@ importers: dependencies: '@modular-react/core': specifier: ^1.0.0 - version: link:../../../../packages/core + version: 1.8.1(@types/react@19.2.14) '@react-router-modules/core': specifier: ^2.0.0 version: link:../../../../packages/react-router-core @@ -193,7 +193,7 @@ importers: version: link:../../app-shared '@modular-react/core': specifier: ^1.0.0 - version: link:../../../../../packages/core + version: 1.8.1(@types/react@19.2.14) devDependencies: '@types/react': specifier: ^19.0.0 @@ -212,7 +212,7 @@ importers: version: link:../../app-shared '@modular-react/core': specifier: ^1.0.0 - version: link:../../../../../packages/core + version: 1.8.1(@types/react@19.2.14) devDependencies: '@types/react': specifier: ^19.0.0 @@ -231,7 +231,7 @@ importers: version: link:../../app-shared '@modular-react/core': specifier: ^1.0.0 - version: link:../../../../../packages/core + version: 1.8.1(@types/react@19.2.14) devDependencies: '@types/react': specifier: ^19.0.0 @@ -262,13 +262,13 @@ importers: version: link:../modules/profile '@modular-react/core': specifier: ^1.0.0 - version: link:../../../../packages/core + version: 1.8.1(@types/react@19.2.14) '@modular-react/journeys': specifier: ^1.0.0 version: link:../../../../packages/journeys '@modular-react/react': specifier: ^1.0.0 - version: link:../../../../packages/react + version: 1.4.0(@modular-react/core@1.8.1(@types/react@19.2.14))(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@react-router-modules/core': specifier: ^2.0.0 version: link:../../../../packages/react-router-core @@ -651,7 +651,7 @@ importers: dependencies: '@modular-react/core': specifier: ^1.0.0 - version: link:../../../../packages/core + version: 1.8.1(@types/react@19.2.14) '@react-router-modules/core': specifier: ^2.0.0 version: link:../../../../packages/react-router-core @@ -711,7 +711,7 @@ importers: version: link:../../app-shared '@modular-react/core': specifier: ^1.0.0 - version: link:../../../../../packages/core + version: 1.8.1(@types/react@19.2.14) devDependencies: '@types/react': specifier: ^19.0.0 @@ -730,7 +730,7 @@ importers: version: link:../../app-shared '@modular-react/core': specifier: ^1.0.0 - version: link:../../../../../packages/core + version: 1.8.1(@types/react@19.2.14) devDependencies: '@types/react': specifier: ^19.0.0 @@ -749,7 +749,7 @@ importers: version: link:../../app-shared '@modular-react/core': specifier: ^1.0.0 - version: link:../../../../../packages/core + version: 1.8.1(@types/react@19.2.14) devDependencies: '@types/react': specifier: ^19.0.0 @@ -783,13 +783,13 @@ importers: version: link:../journeys/verify-identity '@modular-react/core': specifier: ^1.0.0 - version: link:../../../../packages/core + version: 1.8.1(@types/react@19.2.14) '@modular-react/journeys': specifier: ^1.0.0 version: link:../../../../packages/journeys '@modular-react/react': specifier: ^1.0.0 - version: link:../../../../packages/react + version: 1.4.0(@modular-react/core@1.8.1(@types/react@19.2.14))(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@react-router-modules/core': specifier: ^2.0.0 version: link:../../../../packages/react-router-core @@ -826,7 +826,7 @@ importers: dependencies: '@modular-react/core': specifier: ^1.0.0 - version: link:../../../../packages/core + version: 1.8.1(@types/react@19.2.14) '@react-router-modules/core': specifier: ^2.0.0 version: link:../../../../packages/react-router-core @@ -851,7 +851,7 @@ importers: version: link:../../app-shared '@modular-react/core': specifier: ^1.0.0 - version: link:../../../../../packages/core + version: 1.8.1(@types/react@19.2.14) '@react-router-modules/core': specifier: ^2.0.0 version: link:../../../../../packages/react-router-core @@ -888,10 +888,10 @@ importers: version: link:../modules/integrations '@modular-react/core': specifier: ^1.0.0 - version: link:../../../../packages/core + version: 1.8.1(@types/react@19.2.14) '@modular-react/react': specifier: ^1.0.0 - version: link:../../../../packages/react + version: 1.4.0(@modular-react/core@1.8.1(@types/react@19.2.14))(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@react-router-modules/core': specifier: ^2.0.0 version: link:../../../../packages/react-router-core @@ -931,7 +931,7 @@ importers: dependencies: '@modular-react/core': specifier: ^1.0.0 - version: link:../../../../packages/core + version: 1.8.1(@types/react@19.2.14) '@tanstack-react-modules/core': specifier: workspace:* version: link:../../../../packages/tanstack-router-core @@ -978,7 +978,7 @@ importers: version: link:../../app-shared '@modular-react/core': specifier: ^1.0.0 - version: link:../../../../../packages/core + version: 1.8.1(@types/react@19.2.14) devDependencies: '@types/react': specifier: ^19.0.0 @@ -997,7 +997,7 @@ importers: version: link:../../app-shared '@modular-react/core': specifier: ^1.0.0 - version: link:../../../../../packages/core + version: 1.8.1(@types/react@19.2.14) devDependencies: '@types/react': specifier: ^19.0.0 @@ -1016,7 +1016,7 @@ importers: version: link:../../app-shared '@modular-react/core': specifier: ^1.0.0 - version: link:../../../../../packages/core + version: 1.8.1(@types/react@19.2.14) devDependencies: '@types/react': specifier: ^19.0.0 @@ -1047,13 +1047,13 @@ importers: version: link:../modules/profile '@modular-react/core': specifier: ^1.0.0 - version: link:../../../../packages/core + version: 1.8.1(@types/react@19.2.14) '@modular-react/journeys': specifier: ^1.0.0 version: link:../../../../packages/journeys '@modular-react/react': specifier: ^1.0.0 - version: link:../../../../packages/react + version: 1.4.0(@modular-react/core@1.8.1(@types/react@19.2.14))(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@tanstack-react-modules/core': specifier: ^2.0.0 version: link:../../../../packages/tanstack-router-core @@ -1439,7 +1439,7 @@ importers: dependencies: '@modular-react/core': specifier: ^1.0.0 - version: link:../../../../packages/core + version: 1.8.1(@types/react@19.2.14) '@tanstack-react-modules/core': specifier: ^2.0.0 version: link:../../../../packages/tanstack-router-core @@ -1499,7 +1499,7 @@ importers: version: link:../../app-shared '@modular-react/core': specifier: ^1.0.0 - version: link:../../../../../packages/core + version: 1.8.1(@types/react@19.2.14) devDependencies: '@types/react': specifier: ^19.0.0 @@ -1518,7 +1518,7 @@ importers: version: link:../../app-shared '@modular-react/core': specifier: ^1.0.0 - version: link:../../../../../packages/core + version: 1.8.1(@types/react@19.2.14) devDependencies: '@types/react': specifier: ^19.0.0 @@ -1537,7 +1537,7 @@ importers: version: link:../../app-shared '@modular-react/core': specifier: ^1.0.0 - version: link:../../../../../packages/core + version: 1.8.1(@types/react@19.2.14) devDependencies: '@types/react': specifier: ^19.0.0 @@ -1571,13 +1571,13 @@ importers: version: link:../journeys/verify-identity '@modular-react/core': specifier: ^1.0.0 - version: link:../../../../packages/core + version: 1.8.1(@types/react@19.2.14) '@modular-react/journeys': specifier: ^1.0.0 version: link:../../../../packages/journeys '@modular-react/react': specifier: ^1.0.0 - version: link:../../../../packages/react + version: 1.4.0(@modular-react/core@1.8.1(@types/react@19.2.14))(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@tanstack-react-modules/core': specifier: ^2.0.0 version: link:../../../../packages/tanstack-router-core @@ -1970,6 +1970,9 @@ importers: '@modular-react/react': specifier: workspace:* version: link:../react + '@modular-react/testing': + specifier: workspace:* + version: link:../testing '@testing-library/react': specifier: ^16.0.0 version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) @@ -2011,7 +2014,7 @@ importers: devDependencies: '@modular-react/core': specifier: ^1.2.0 - version: link:../core + version: 1.8.1(@types/react@19.2.14) '@testing-library/react': specifier: ^16.3.2 version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) @@ -2075,7 +2078,7 @@ importers: devDependencies: '@modular-react/core': specifier: ^1.2.0 - version: link:../core + version: 1.8.1(@types/react@19.2.14) '@types/react': specifier: ^19.0.0 version: 19.2.14 @@ -2105,13 +2108,13 @@ importers: devDependencies: '@modular-react/core': specifier: ^1.2.0 - version: link:../core + version: 1.8.1(@types/react@19.2.14) '@modular-react/journeys': specifier: workspace:* version: link:../journeys '@modular-react/react': specifier: ^1.2.0 - version: link:../react + version: 1.4.0(@modular-react/core@1.8.1(@types/react@19.2.14))(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@react-router-modules/core': specifier: ^2.3.0 version: link:../react-router-core @@ -2156,13 +2159,13 @@ importers: devDependencies: '@modular-react/core': specifier: ^1.2.0 - version: link:../core + version: 1.8.1(@types/react@19.2.14) '@modular-react/journeys': specifier: workspace:* version: link:../journeys '@modular-react/react': specifier: ^1.2.0 - version: link:../react + version: 1.4.0(@modular-react/core@1.8.1(@types/react@19.2.14))(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@react-router-modules/core': specifier: ^2.3.0 version: link:../react-router-core @@ -2229,7 +2232,7 @@ importers: devDependencies: '@modular-react/core': specifier: ^1.2.0 - version: link:../core + version: 1.8.1(@types/react@19.2.14) '@tanstack/react-router': specifier: ^1.168.8 version: 1.169.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) @@ -2259,13 +2262,13 @@ importers: devDependencies: '@modular-react/core': specifier: ^1.2.0 - version: link:../core + version: 1.8.1(@types/react@19.2.14) '@modular-react/journeys': specifier: workspace:* version: link:../journeys '@modular-react/react': specifier: ^1.2.0 - version: link:../react + version: 1.4.0(@modular-react/core@1.8.1(@types/react@19.2.14))(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@tanstack-react-modules/core': specifier: ^2.3.0 version: link:../tanstack-router-core @@ -2310,13 +2313,13 @@ importers: devDependencies: '@modular-react/core': specifier: ^1.2.0 - version: link:../core + version: 1.8.1(@types/react@19.2.14) '@modular-react/journeys': specifier: workspace:* version: link:../journeys '@modular-react/react': specifier: ^1.2.0 - version: link:../react + version: 1.4.0(@modular-react/core@1.8.1(@types/react@19.2.14))(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@tanstack-react-modules/core': specifier: ^2.3.0 version: link:../tanstack-router-core @@ -2361,7 +2364,10 @@ importers: devDependencies: '@modular-react/core': specifier: ^1.2.0 - version: link:../core + version: 1.8.1(@types/react@19.2.14) + '@modular-react/react': + specifier: ^2.0.0 + version: link:../react '@types/react': specifier: ^19.0.0 version: 19.2.14 @@ -3004,6 +3010,21 @@ packages: '@cfworker/json-schema': optional: true + '@modular-react/core@1.8.1': + resolution: {integrity: sha512-7DjxnPh7Sv697S4NHGRSoP7l5ZgEdhqWfSgPff01VNehg+ZzPdqpwR44fUjLLm6uqLrQauOo1CckDLhwmfGZ4w==} + peerDependencies: + '@types/react': ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@modular-react/react@1.4.0': + resolution: {integrity: sha512-C6zDG3A23iWIKu7bA40xonelVBN1BpgztDkK/wAUkLY6YJeqG/Ww4FEqejeBfhQ5+hnjgQyQXbkMHIrD4ce0pg==} + peerDependencies: + '@modular-react/core': ^1.2.0 + react: ^19.0.0 + react-dom: ^19.0.0 + '@mswjs/interceptors@0.41.7': resolution: {integrity: sha512-D0nkS5+sx87mYpxFqASImCineYoEl9wGlUPrzkuS0ohzG8wfophLpE+I76qGJ0slLAVI19do5SI9pWJNCVf4fg==} engines: {node: '>=18'} @@ -6543,6 +6564,16 @@ snapshots: transitivePeerDependencies: - supports-color + '@modular-react/core@1.8.1(@types/react@19.2.14)': + optionalDependencies: + '@types/react': 19.2.14 + + '@modular-react/react@1.4.0(@modular-react/core@1.8.1(@types/react@19.2.14))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': + dependencies: + '@modular-react/core': 1.8.1(@types/react@19.2.14) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + '@mswjs/interceptors@0.41.7': dependencies: '@open-draft/deferred-promise': 2.2.0 From 585bb5946ec85cf0560189c92cb2b1cbe2e00324 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 7 May 2026 13:38:16 +0000 Subject: [PATCH 2/8] ci: include journeys, catalog, and cli-core in publish.yml These three packages declared `private: false` and shipped publish-ready manifests (`main`, `files`, `prepublishOnly`), but the publish workflow filtered them out. Add path filters and PKG_MAP entries so a labelled PR that touches them triggers a release. Catalog's filter includes both `src/**` and `spa-src/**` because the package's published `files` are `dist` + `dist-spa` and the SPA bundle is built from `spa-src`. https://claude.ai/code/session_0166HdHFxs9MBEWdxybXhSkM --- .github/workflows/publish.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 4a5b555..5d67b57 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -87,6 +87,22 @@ jobs: - 'packages/testing/src/**' - 'packages/testing/package.json' - 'packages/testing/README.md' + pkg_journeys: + - 'packages/journeys/src/**' + - 'packages/journeys/package.json' + - 'packages/journeys/README.md' + pkg_catalog: + # Catalog ships a built TS library plus a Vite-built SPA bundle + # (dist + dist-spa, see packages/catalog/package.json's `files`), + # so the SPA source tree is part of the publish surface. + - 'packages/catalog/src/**' + - 'packages/catalog/spa-src/**' + - 'packages/catalog/package.json' + - 'packages/catalog/README.md' + pkg_cli_core: + - 'packages/cli-core/src/**' + - 'packages/cli-core/package.json' + - 'packages/cli-core/README.md' pkg_rr_cli: - 'packages/react-router-cli/src/**' - 'packages/react-router-cli/package.json' @@ -128,6 +144,9 @@ jobs: ["pkg_core"]="core:@modular-react/core" ["pkg_react"]="react:@modular-react/react" ["pkg_testing"]="testing:@modular-react/testing" + ["pkg_journeys"]="journeys:@modular-react/journeys" + ["pkg_catalog"]="catalog:@modular-react/catalog" + ["pkg_cli_core"]="cli-core:@modular-react/cli-core" ["pkg_rr_cli"]="react-router-cli:@react-router-modules/cli" ["pkg_rr_core"]="react-router-core:@react-router-modules/core" ["pkg_rr_runtime"]="react-router-runtime:@react-router-modules/runtime" From 8b4458dff74fd653e47ae6442851b81651573af3 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 7 May 2026 13:46:21 +0000 Subject: [PATCH 3/8] refactor(testing): tighten preloadEntries narrowing and re-export docs Self-review pass on the previous commit. - Drop the `as { lazy?: unknown }` cast and the redundant `as ModuleEntryPoint[]` in favor of a direct `"lazy" in entry` narrow on the EagerModuleEntryPoint | LazyModuleEntryPoint union. - Rename the loop variable from `module` to `mod` to avoid shadowing. - Make README/JSDoc imports consistent: both examples now use `@modular-react/testing` (the unified import surface) and the second example notes explicitly that `preloadEntry` is re-exported here. - Add a sanity test asserting the re-export is verbatim (`preloadEntry === preloadEntryFromReact`) so a future refactor can't silently break the unified import surface. - Add a comment on the Promise.all line documenting why per-promise rejection handlers are safe (Promise.all attaches one to each input, so a single rejection won't leave the others as unhandled). https://claude.ai/code/session_0166HdHFxs9MBEWdxybXhSkM --- packages/testing/README.md | 4 +++- packages/testing/src/preload-entries.test.ts | 11 ++++++++-- packages/testing/src/preload-entries.ts | 21 +++++++++++++------- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/packages/testing/README.md b/packages/testing/README.md index 4ee185a..3f12f58 100644 --- a/packages/testing/README.md +++ b/packages/testing/README.md @@ -63,7 +63,9 @@ it("renders the lazy review step", () => { ``` For modules built ad-hoc inside a single test (or any case where enumerating -modules upfront is awkward), call `preloadEntry` directly on the entry: +modules upfront is awkward), call `preloadEntry` directly on the entry. +`preloadEntry` is re-exported here so test code only needs a single import +surface: ```typescript import { preloadEntry } from "@modular-react/testing"; diff --git a/packages/testing/src/preload-entries.test.ts b/packages/testing/src/preload-entries.test.ts index 90a197b..6b50b81 100644 --- a/packages/testing/src/preload-entries.test.ts +++ b/packages/testing/src/preload-entries.test.ts @@ -1,12 +1,15 @@ import { describe, it, expect, vi } from "vitest"; import type { ComponentType } from "react"; -import { resolveEntryComponent } from "@modular-react/react"; +import { + preloadEntry as preloadEntryFromReact, + resolveEntryComponent, +} from "@modular-react/react"; import type { LazyModuleEntryPoint, ModuleDescriptor, ModuleEntryProps, } from "@modular-react/core"; -import { preloadEntries } from "./preload-entries.js"; +import { preloadEntries, preloadEntry } from "./index.js"; const Stub = (() => null) as unknown as ComponentType>; @@ -80,6 +83,10 @@ describe("preloadEntries", () => { await expect(preloadEntries([mod])).rejects.toBe(failure); }); + it("re-exports `preloadEntry` from @modular-react/react verbatim", () => { + expect(preloadEntry).toBe(preloadEntryFromReact); + }); + it("after preload, resolveEntryComponent(entry).preload() resolves SYNCHRONOUSLY", async () => { // The end-to-end value proposition: post-preload, the resolver's cached // path returns a synchronous thenable (resolve-entry.ts:90-99). React.lazy diff --git a/packages/testing/src/preload-entries.ts b/packages/testing/src/preload-entries.ts index 3af1d1f..e06cb36 100644 --- a/packages/testing/src/preload-entries.ts +++ b/packages/testing/src/preload-entries.ts @@ -1,5 +1,5 @@ import { preloadEntry } from "@modular-react/react"; -import type { ModuleDescriptor, ModuleEntryPoint } from "@modular-react/core"; +import type { ModuleDescriptor } from "@modular-react/core"; /** * Eagerly resolves every `lazy:` entry on the given modules so subsequent @@ -26,9 +26,10 @@ import type { ModuleDescriptor, ModuleEntryPoint } from "@modular-react/core"; * beforeAll(() => preloadEntries(allModules)); * ``` * - * @example For modules built ad-hoc per test, call `preloadEntry` directly: + * @example For modules built ad-hoc per test, call `preloadEntry` directly + * (re-exported from this package for a single import surface): * ```ts - * import { preloadEntry } from "@modular-react/react"; + * import { preloadEntry } from "@modular-react/testing"; * * await preloadEntry(myEntry); * render(); @@ -38,10 +39,16 @@ export function preloadEntries( modules: readonly ModuleDescriptor[], ): Promise { const tasks: Promise[] = []; - for (const module of modules) { - if (!module.entryPoints) continue; - for (const entry of Object.values(module.entryPoints) as ModuleEntryPoint[]) { - if (typeof (entry as { lazy?: unknown }).lazy === "function") { + for (const mod of modules) { + if (!mod.entryPoints) continue; + for (const entry of Object.values(mod.entryPoints)) { + // `"lazy" in entry` narrows the EagerModuleEntryPoint | LazyModuleEntryPoint + // union to the lazy branch; the typeof check guards against malformed + // entries that survived validation. + if ("lazy" in entry && typeof entry.lazy === "function") { + // Promise.all attaches a handler to every promise it iterates, so a + // single rejection won't leave the other in-flight imports as + // unhandled-rejection warnings. tasks.push(preloadEntry(entry)); } } From 31740bf6de100312549c3c659aea0dc4104dd5ad Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 7 May 2026 13:49:01 +0000 Subject: [PATCH 4/8] test(testing): cover vi.mock interaction with a real fixture The README claims `preloadEntries` honors `vi.mock` because vitest hoists mock factories above all imports, but no test actually exercised the dynamic-import path through a mocked module. Add one. - New `preload-entries.fixture.ts` next to the test (a tiny default export with `displayName: "real"`). - Test hoists `vi.mock(...)` returning a mock with `displayName: "mocked"`, then asserts the cached resolved module after `preloadEntries` is the mocked one. Reads the cached value through the synchronous-thenable fast path so no await/DOM is needed. - tsconfig `exclude` now covers `*.fixture.*` so the fixture stays out of `dist`. Verified build still produces `index.{js,d.ts}` only. https://claude.ai/code/session_0166HdHFxs9MBEWdxybXhSkM --- .../testing/src/preload-entries.fixture.ts | 10 ++++++ packages/testing/src/preload-entries.test.ts | 34 +++++++++++++++++++ packages/testing/tsconfig.json | 2 +- 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 packages/testing/src/preload-entries.fixture.ts diff --git a/packages/testing/src/preload-entries.fixture.ts b/packages/testing/src/preload-entries.fixture.ts new file mode 100644 index 0000000..2d1551f --- /dev/null +++ b/packages/testing/src/preload-entries.fixture.ts @@ -0,0 +1,10 @@ +// Test fixture for `preload-entries.test.ts`. Lives next to the test so the +// `*.fixture.*` glob in tsconfig.json's `exclude` keeps it out of the published +// build. The "real" default export is replaced by `vi.mock` in the test — +// asserting the cached module ends up as the mocked one is the proof that +// `preloadEntries` honors vitest's module-mocking hoisting. + +const RealComponent: { (): null; displayName: string } = () => null; +RealComponent.displayName = "real"; + +export default RealComponent; diff --git a/packages/testing/src/preload-entries.test.ts b/packages/testing/src/preload-entries.test.ts index 6b50b81..27d7cac 100644 --- a/packages/testing/src/preload-entries.test.ts +++ b/packages/testing/src/preload-entries.test.ts @@ -11,6 +11,16 @@ import type { } from "@modular-react/core"; import { preloadEntries, preloadEntry } from "./index.js"; +// Hoisted by vitest above every import in this file. `preloadEntries` walks +// the lazy entry's importer, which calls `import("./preload-entries.fixture")` +// at runtime; that resolution is intercepted here and returns the mock +// factory's value instead of the real on-disk fixture. +vi.mock("./preload-entries.fixture.js", () => { + const Mocked: { (): null; displayName: string } = () => null; + Mocked.displayName = "mocked"; + return { default: Mocked }; +}); + const Stub = (() => null) as unknown as ComponentType>; function lazyEntry(importer: () => Promise): LazyModuleEntryPoint { @@ -87,6 +97,30 @@ describe("preloadEntries", () => { expect(preloadEntry).toBe(preloadEntryFromReact); }); + it("honors vi.mock — the cached module is the mocked one, not the real fixture", async () => { + // vitest hoists `vi.mock(...)` above every import in this file, so the + // dynamic `import("./preload-entries.fixture.js")` triggered by + // preloadEntries() resolves to the mock factory's return value rather + // than the on-disk fixture (which exports `displayName: "real"`). + const importer = vi.fn(() => import("./preload-entries.fixture.js")); + const entry = lazyEntry(importer); + const mod = module_("m", { e: entry }); + + await preloadEntries([mod]); + + // Read the cached resolved module via the synchronous-thenable fast path: + // after preload, .preload() returns a thenable that fires onFulfilled + // inline, so we can capture the cached value without await. + let captured: { default?: { displayName?: string } } | undefined; + resolveEntryComponent(entry) + .preload() + .then((m) => { + captured = m as typeof captured; + }); + expect(importer).toHaveBeenCalledTimes(1); + expect(captured?.default?.displayName).toBe("mocked"); + }); + it("after preload, resolveEntryComponent(entry).preload() resolves SYNCHRONOUSLY", async () => { // The end-to-end value proposition: post-preload, the resolver's cached // path returns a synchronous thenable (resolve-entry.ts:90-99). React.lazy diff --git a/packages/testing/tsconfig.json b/packages/testing/tsconfig.json index cf9697d..629d6d9 100644 --- a/packages/testing/tsconfig.json +++ b/packages/testing/tsconfig.json @@ -5,5 +5,5 @@ "rootDir": "src" }, "include": ["src"], - "exclude": ["src/**/*.test.*"] + "exclude": ["src/**/*.test.*", "src/**/*.fixture.*"] } From b8814cff4e3e88a1374e5ea0441c12f54c447089 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 7 May 2026 14:02:45 +0000 Subject: [PATCH 5/8] style(testing): apply oxfmt to preload-entries.test.ts Imports were re-flowed to single-line per the formatter's defaults. --- packages/testing/src/preload-entries.test.ts | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/packages/testing/src/preload-entries.test.ts b/packages/testing/src/preload-entries.test.ts index 27d7cac..4f253c2 100644 --- a/packages/testing/src/preload-entries.test.ts +++ b/packages/testing/src/preload-entries.test.ts @@ -1,14 +1,7 @@ import { describe, it, expect, vi } from "vitest"; import type { ComponentType } from "react"; -import { - preloadEntry as preloadEntryFromReact, - resolveEntryComponent, -} from "@modular-react/react"; -import type { - LazyModuleEntryPoint, - ModuleDescriptor, - ModuleEntryProps, -} from "@modular-react/core"; +import { preloadEntry as preloadEntryFromReact, resolveEntryComponent } from "@modular-react/react"; +import type { LazyModuleEntryPoint, ModuleDescriptor, ModuleEntryProps } from "@modular-react/core"; import { preloadEntries, preloadEntry } from "./index.js"; // Hoisted by vitest above every import in this file. `preloadEntries` walks From f653e559ed038b38226c0b19d50f77a2a17062a0 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 7 May 2026 14:02:58 +0000 Subject: [PATCH 6/8] chore: switch internal cross-package deps to workspace:* MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The version-bump bot promoted @modular-react/core to 2.0.0 in commit ba105a5, but did not update the cross-references that still pinned core to ^1.2.0 / ^1.0.0 across the workspace. pnpm therefore resolved the core dep to the registry's 1.8.1 (the highest 1.x match), which lacks LazyModuleEntryPoint and EagerModuleEntryPoint, breaking typecheck for @modular-react/react and every example using `lazy:` entries. Switch all internal cross-package refs (in `dependencies` and `devDependencies`) to `workspace:*` so pnpm always resolves to the in-repo version. `peerDependencies` are intentionally left alone — the published consumer contract is a separate maintainer decision (and the ^1.2.0 peer pin on react@2.0.0 is itself wrong, but out of scope here). `pnpm publish` (already used in publish.yml) rewrites `workspace:*` to a real version range in the published tarball. For the publishable packages here, all `workspace:*` additions land in `devDependencies` which are stripped from the tarball entirely, so the rewrite is a non-issue for these changes. Verified: `pnpm lint`, `pnpm turbo run typecheck --filter='./examples/**'`, and `pnpm turbo run test --filter='./packages/*'` all pass after the update. --- .../app-shared/package.json | 4 +- .../modules/integrations/package.json | 8 +- .../shell/package.json | 8 +- .../app-shared/package.json | 4 +- .../journeys/customer-onboarding/package.json | 2 +- .../modules/billing/package.json | 2 +- .../modules/plan/package.json | 2 +- .../modules/profile/package.json | 2 +- .../shell/package.json | 10 +- .../journey-invoke/app-shared/package.json | 4 +- .../journeys/checkout/package.json | 2 +- .../journeys/verify-identity/package.json | 2 +- .../modules/age-verify/package.json | 2 +- .../modules/checkout-confirm/package.json | 2 +- .../modules/checkout-review/package.json | 2 +- .../journey-invoke/shell/package.json | 10 +- .../app-shared/package.json | 4 +- .../modules/integrations/package.json | 8 +- .../remote-capabilities/shell/package.json | 8 +- .../app-shared/package.json | 2 +- .../journeys/customer-onboarding/package.json | 2 +- .../modules/billing/package.json | 2 +- .../modules/plan/package.json | 2 +- .../modules/profile/package.json | 2 +- .../shell/package.json | 10 +- .../journey-invoke/app-shared/package.json | 4 +- .../journeys/checkout/package.json | 2 +- .../journeys/verify-identity/package.json | 2 +- .../modules/age-verify/package.json | 2 +- .../modules/checkout-confirm/package.json | 2 +- .../modules/checkout-review/package.json | 2 +- .../journey-invoke/shell/package.json | 10 +- packages/react-router-core/package.json | 2 +- packages/react-router-runtime/package.json | 6 +- packages/react-router-testing/package.json | 8 +- packages/react/package.json | 2 +- packages/tanstack-router-core/package.json | 2 +- packages/tanstack-router-runtime/package.json | 6 +- packages/tanstack-router-testing/package.json | 8 +- packages/testing/package.json | 4 +- pnpm-lock.yaml | 281 ++++++++---------- 41 files changed, 212 insertions(+), 237 deletions(-) diff --git a/examples/react-router/active-project-manifest/app-shared/package.json b/examples/react-router/active-project-manifest/app-shared/package.json index 85855ab..3dc6a2d 100644 --- a/examples/react-router/active-project-manifest/app-shared/package.json +++ b/examples/react-router/active-project-manifest/app-shared/package.json @@ -14,8 +14,8 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@modular-react/core": "^1.0.0", - "@react-router-modules/core": "^2.0.0" + "@modular-react/core": "workspace:*", + "@react-router-modules/core": "workspace:*" }, "devDependencies": { "@types/react": "^19.0.0", diff --git a/examples/react-router/active-project-manifest/modules/integrations/package.json b/examples/react-router/active-project-manifest/modules/integrations/package.json index 008adb1..ca1fdad 100644 --- a/examples/react-router/active-project-manifest/modules/integrations/package.json +++ b/examples/react-router/active-project-manifest/modules/integrations/package.json @@ -16,12 +16,12 @@ }, "dependencies": { "@example-active/app-shared": "workspace:*", - "@modular-react/core": "^1.0.0", - "@react-router-modules/core": "^2.0.0", - "@react-router-modules/runtime": "^2.0.0" + "@modular-react/core": "workspace:*", + "@react-router-modules/core": "workspace:*", + "@react-router-modules/runtime": "workspace:*" }, "devDependencies": { - "@modular-react/testing": "^1.0.0", + "@modular-react/testing": "workspace:*", "@types/react": "^19.0.0", "react": "^19.0.0", "react-router": "^7.6.0", diff --git a/examples/react-router/active-project-manifest/shell/package.json b/examples/react-router/active-project-manifest/shell/package.json index 29489ba..e785bd2 100644 --- a/examples/react-router/active-project-manifest/shell/package.json +++ b/examples/react-router/active-project-manifest/shell/package.json @@ -12,10 +12,10 @@ "dependencies": { "@example-active/app-shared": "workspace:*", "@example-active/integrations-module": "workspace:*", - "@modular-react/core": "^1.0.0", - "@modular-react/react": "^1.0.0", - "@react-router-modules/core": "^2.0.0", - "@react-router-modules/runtime": "^2.0.0", + "@modular-react/core": "workspace:*", + "@modular-react/react": "workspace:*", + "@react-router-modules/core": "workspace:*", + "@react-router-modules/runtime": "workspace:*", "react": "^19.0.0", "react-dom": "^19.0.0", "react-router": "^7.6.0", diff --git a/examples/react-router/customer-onboarding-journey/app-shared/package.json b/examples/react-router/customer-onboarding-journey/app-shared/package.json index d8da535..53dacec 100644 --- a/examples/react-router/customer-onboarding-journey/app-shared/package.json +++ b/examples/react-router/customer-onboarding-journey/app-shared/package.json @@ -14,8 +14,8 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@modular-react/core": "^1.0.0", - "@react-router-modules/core": "^2.0.0" + "@modular-react/core": "workspace:*", + "@react-router-modules/core": "workspace:*" }, "devDependencies": { "@types/react": "^19.0.0", diff --git a/examples/react-router/customer-onboarding-journey/journeys/customer-onboarding/package.json b/examples/react-router/customer-onboarding-journey/journeys/customer-onboarding/package.json index 6c5687f..87d3aaa 100644 --- a/examples/react-router/customer-onboarding-journey/journeys/customer-onboarding/package.json +++ b/examples/react-router/customer-onboarding-journey/journeys/customer-onboarding/package.json @@ -18,7 +18,7 @@ "@example-onboarding/billing-module": "workspace:*", "@example-onboarding/plan-module": "workspace:*", "@example-onboarding/profile-module": "workspace:*", - "@modular-react/journeys": "^1.0.0" + "@modular-react/journeys": "workspace:*" }, "devDependencies": { "typescript": "^6.0.2" diff --git a/examples/react-router/customer-onboarding-journey/modules/billing/package.json b/examples/react-router/customer-onboarding-journey/modules/billing/package.json index 7f5dd8f..4b2dfbc 100644 --- a/examples/react-router/customer-onboarding-journey/modules/billing/package.json +++ b/examples/react-router/customer-onboarding-journey/modules/billing/package.json @@ -15,7 +15,7 @@ }, "dependencies": { "@example-onboarding/app-shared": "workspace:*", - "@modular-react/core": "^1.0.0" + "@modular-react/core": "workspace:*" }, "devDependencies": { "@types/react": "^19.0.0", diff --git a/examples/react-router/customer-onboarding-journey/modules/plan/package.json b/examples/react-router/customer-onboarding-journey/modules/plan/package.json index 491d923..4b03eb0 100644 --- a/examples/react-router/customer-onboarding-journey/modules/plan/package.json +++ b/examples/react-router/customer-onboarding-journey/modules/plan/package.json @@ -15,7 +15,7 @@ }, "dependencies": { "@example-onboarding/app-shared": "workspace:*", - "@modular-react/core": "^1.0.0" + "@modular-react/core": "workspace:*" }, "devDependencies": { "@types/react": "^19.0.0", diff --git a/examples/react-router/customer-onboarding-journey/modules/profile/package.json b/examples/react-router/customer-onboarding-journey/modules/profile/package.json index 526d153..e0e2201 100644 --- a/examples/react-router/customer-onboarding-journey/modules/profile/package.json +++ b/examples/react-router/customer-onboarding-journey/modules/profile/package.json @@ -15,7 +15,7 @@ }, "dependencies": { "@example-onboarding/app-shared": "workspace:*", - "@modular-react/core": "^1.0.0" + "@modular-react/core": "workspace:*" }, "devDependencies": { "@types/react": "^19.0.0", diff --git a/examples/react-router/customer-onboarding-journey/shell/package.json b/examples/react-router/customer-onboarding-journey/shell/package.json index 932fac1..6669a5c 100644 --- a/examples/react-router/customer-onboarding-journey/shell/package.json +++ b/examples/react-router/customer-onboarding-journey/shell/package.json @@ -16,11 +16,11 @@ "@example-onboarding/customer-onboarding-journey": "workspace:*", "@example-onboarding/plan-module": "workspace:*", "@example-onboarding/profile-module": "workspace:*", - "@modular-react/core": "^1.0.0", - "@modular-react/journeys": "^1.0.0", - "@modular-react/react": "^1.0.0", - "@react-router-modules/core": "^2.0.0", - "@react-router-modules/runtime": "^2.0.0", + "@modular-react/core": "workspace:*", + "@modular-react/journeys": "workspace:*", + "@modular-react/react": "workspace:*", + "@react-router-modules/core": "workspace:*", + "@react-router-modules/runtime": "workspace:*", "react": "^19.0.0", "react-dom": "^19.0.0", "react-router": "^7.6.0", diff --git a/examples/react-router/journey-invoke/app-shared/package.json b/examples/react-router/journey-invoke/app-shared/package.json index 012b446..dbc66a5 100644 --- a/examples/react-router/journey-invoke/app-shared/package.json +++ b/examples/react-router/journey-invoke/app-shared/package.json @@ -14,8 +14,8 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@modular-react/core": "^1.0.0", - "@react-router-modules/core": "^2.0.0" + "@modular-react/core": "workspace:*", + "@react-router-modules/core": "workspace:*" }, "devDependencies": { "@types/react": "^19.0.0", diff --git a/examples/react-router/journey-invoke/journeys/checkout/package.json b/examples/react-router/journey-invoke/journeys/checkout/package.json index e90b7db..0159a1a 100644 --- a/examples/react-router/journey-invoke/journeys/checkout/package.json +++ b/examples/react-router/journey-invoke/journeys/checkout/package.json @@ -18,7 +18,7 @@ "@example-rr-invoke/checkout-confirm-module": "workspace:*", "@example-rr-invoke/checkout-review-module": "workspace:*", "@example-rr-invoke/verify-identity-journey": "workspace:*", - "@modular-react/journeys": "^1.0.0" + "@modular-react/journeys": "workspace:*" }, "devDependencies": { "typescript": "^6.0.2" diff --git a/examples/react-router/journey-invoke/journeys/verify-identity/package.json b/examples/react-router/journey-invoke/journeys/verify-identity/package.json index 91836ae..ca9f616 100644 --- a/examples/react-router/journey-invoke/journeys/verify-identity/package.json +++ b/examples/react-router/journey-invoke/journeys/verify-identity/package.json @@ -16,7 +16,7 @@ "dependencies": { "@example-rr-invoke/age-verify-module": "workspace:*", "@example-rr-invoke/app-shared": "workspace:*", - "@modular-react/journeys": "^1.0.0" + "@modular-react/journeys": "workspace:*" }, "devDependencies": { "typescript": "^6.0.2" diff --git a/examples/react-router/journey-invoke/modules/age-verify/package.json b/examples/react-router/journey-invoke/modules/age-verify/package.json index bc8fd1c..4d307a8 100644 --- a/examples/react-router/journey-invoke/modules/age-verify/package.json +++ b/examples/react-router/journey-invoke/modules/age-verify/package.json @@ -15,7 +15,7 @@ }, "dependencies": { "@example-rr-invoke/app-shared": "workspace:*", - "@modular-react/core": "^1.0.0" + "@modular-react/core": "workspace:*" }, "devDependencies": { "@types/react": "^19.0.0", diff --git a/examples/react-router/journey-invoke/modules/checkout-confirm/package.json b/examples/react-router/journey-invoke/modules/checkout-confirm/package.json index e865b0e..5703bd7 100644 --- a/examples/react-router/journey-invoke/modules/checkout-confirm/package.json +++ b/examples/react-router/journey-invoke/modules/checkout-confirm/package.json @@ -15,7 +15,7 @@ }, "dependencies": { "@example-rr-invoke/app-shared": "workspace:*", - "@modular-react/core": "^1.0.0" + "@modular-react/core": "workspace:*" }, "devDependencies": { "@types/react": "^19.0.0", diff --git a/examples/react-router/journey-invoke/modules/checkout-review/package.json b/examples/react-router/journey-invoke/modules/checkout-review/package.json index d67d73c..c5b5cb6 100644 --- a/examples/react-router/journey-invoke/modules/checkout-review/package.json +++ b/examples/react-router/journey-invoke/modules/checkout-review/package.json @@ -15,7 +15,7 @@ }, "dependencies": { "@example-rr-invoke/app-shared": "workspace:*", - "@modular-react/core": "^1.0.0" + "@modular-react/core": "workspace:*" }, "devDependencies": { "@types/react": "^19.0.0", diff --git a/examples/react-router/journey-invoke/shell/package.json b/examples/react-router/journey-invoke/shell/package.json index 1c8d76b..2dd4ffe 100644 --- a/examples/react-router/journey-invoke/shell/package.json +++ b/examples/react-router/journey-invoke/shell/package.json @@ -16,11 +16,11 @@ "@example-rr-invoke/checkout-journey": "workspace:*", "@example-rr-invoke/checkout-review-module": "workspace:*", "@example-rr-invoke/verify-identity-journey": "workspace:*", - "@modular-react/core": "^1.0.0", - "@modular-react/journeys": "^1.0.0", - "@modular-react/react": "^1.0.0", - "@react-router-modules/core": "^2.0.0", - "@react-router-modules/runtime": "^2.0.0", + "@modular-react/core": "workspace:*", + "@modular-react/journeys": "workspace:*", + "@modular-react/react": "workspace:*", + "@react-router-modules/core": "workspace:*", + "@react-router-modules/runtime": "workspace:*", "react": "^19.0.0", "react-dom": "^19.0.0", "react-router": "^7.6.0" diff --git a/examples/react-router/remote-capabilities/app-shared/package.json b/examples/react-router/remote-capabilities/app-shared/package.json index d30a1ce..5ac2e92 100644 --- a/examples/react-router/remote-capabilities/app-shared/package.json +++ b/examples/react-router/remote-capabilities/app-shared/package.json @@ -14,8 +14,8 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@modular-react/core": "^1.0.0", - "@react-router-modules/core": "^2.0.0" + "@modular-react/core": "workspace:*", + "@react-router-modules/core": "workspace:*" }, "devDependencies": { "@types/react": "^19.0.0", diff --git a/examples/react-router/remote-capabilities/modules/integrations/package.json b/examples/react-router/remote-capabilities/modules/integrations/package.json index e7a80fb..814b779 100644 --- a/examples/react-router/remote-capabilities/modules/integrations/package.json +++ b/examples/react-router/remote-capabilities/modules/integrations/package.json @@ -16,12 +16,12 @@ }, "dependencies": { "@example/app-shared": "workspace:*", - "@modular-react/core": "^1.0.0", - "@react-router-modules/core": "^2.0.0", - "@react-router-modules/runtime": "^2.0.0" + "@modular-react/core": "workspace:*", + "@react-router-modules/core": "workspace:*", + "@react-router-modules/runtime": "workspace:*" }, "devDependencies": { - "@modular-react/testing": "^1.0.0", + "@modular-react/testing": "workspace:*", "@types/react": "^19.0.0", "react": "^19.0.0", "react-router": "^7.6.0", diff --git a/examples/react-router/remote-capabilities/shell/package.json b/examples/react-router/remote-capabilities/shell/package.json index a86cfe2..7a39017 100644 --- a/examples/react-router/remote-capabilities/shell/package.json +++ b/examples/react-router/remote-capabilities/shell/package.json @@ -12,10 +12,10 @@ "dependencies": { "@example/app-shared": "workspace:*", "@example/integrations-module": "workspace:*", - "@modular-react/core": "^1.0.0", - "@modular-react/react": "^1.0.0", - "@react-router-modules/core": "^2.0.0", - "@react-router-modules/runtime": "^2.0.0", + "@modular-react/core": "workspace:*", + "@modular-react/react": "workspace:*", + "@react-router-modules/core": "workspace:*", + "@react-router-modules/runtime": "workspace:*", "react": "^19.0.0", "react-dom": "^19.0.0", "react-router": "^7.6.0", diff --git a/examples/tanstack-router/customer-onboarding-journey/app-shared/package.json b/examples/tanstack-router/customer-onboarding-journey/app-shared/package.json index 3794c21..1ef4126 100644 --- a/examples/tanstack-router/customer-onboarding-journey/app-shared/package.json +++ b/examples/tanstack-router/customer-onboarding-journey/app-shared/package.json @@ -14,7 +14,7 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@modular-react/core": "^1.0.0", + "@modular-react/core": "workspace:*", "@tanstack-react-modules/core": "workspace:*" }, "devDependencies": { diff --git a/examples/tanstack-router/customer-onboarding-journey/journeys/customer-onboarding/package.json b/examples/tanstack-router/customer-onboarding-journey/journeys/customer-onboarding/package.json index 5ae9697..c7c382a 100644 --- a/examples/tanstack-router/customer-onboarding-journey/journeys/customer-onboarding/package.json +++ b/examples/tanstack-router/customer-onboarding-journey/journeys/customer-onboarding/package.json @@ -18,7 +18,7 @@ "@example-tsr-onboarding/billing-module": "workspace:*", "@example-tsr-onboarding/plan-module": "workspace:*", "@example-tsr-onboarding/profile-module": "workspace:*", - "@modular-react/journeys": "^1.0.0" + "@modular-react/journeys": "workspace:*" }, "devDependencies": { "typescript": "^6.0.2" diff --git a/examples/tanstack-router/customer-onboarding-journey/modules/billing/package.json b/examples/tanstack-router/customer-onboarding-journey/modules/billing/package.json index 93acfd8..937c48b 100644 --- a/examples/tanstack-router/customer-onboarding-journey/modules/billing/package.json +++ b/examples/tanstack-router/customer-onboarding-journey/modules/billing/package.json @@ -15,7 +15,7 @@ }, "dependencies": { "@example-tsr-onboarding/app-shared": "workspace:*", - "@modular-react/core": "^1.0.0" + "@modular-react/core": "workspace:*" }, "devDependencies": { "@types/react": "^19.0.0", diff --git a/examples/tanstack-router/customer-onboarding-journey/modules/plan/package.json b/examples/tanstack-router/customer-onboarding-journey/modules/plan/package.json index 7200072..73bc37d 100644 --- a/examples/tanstack-router/customer-onboarding-journey/modules/plan/package.json +++ b/examples/tanstack-router/customer-onboarding-journey/modules/plan/package.json @@ -15,7 +15,7 @@ }, "dependencies": { "@example-tsr-onboarding/app-shared": "workspace:*", - "@modular-react/core": "^1.0.0" + "@modular-react/core": "workspace:*" }, "devDependencies": { "@types/react": "^19.0.0", diff --git a/examples/tanstack-router/customer-onboarding-journey/modules/profile/package.json b/examples/tanstack-router/customer-onboarding-journey/modules/profile/package.json index 1895a98..d51a44c 100644 --- a/examples/tanstack-router/customer-onboarding-journey/modules/profile/package.json +++ b/examples/tanstack-router/customer-onboarding-journey/modules/profile/package.json @@ -15,7 +15,7 @@ }, "dependencies": { "@example-tsr-onboarding/app-shared": "workspace:*", - "@modular-react/core": "^1.0.0" + "@modular-react/core": "workspace:*" }, "devDependencies": { "@types/react": "^19.0.0", diff --git a/examples/tanstack-router/customer-onboarding-journey/shell/package.json b/examples/tanstack-router/customer-onboarding-journey/shell/package.json index bcbfe11..601eae4 100644 --- a/examples/tanstack-router/customer-onboarding-journey/shell/package.json +++ b/examples/tanstack-router/customer-onboarding-journey/shell/package.json @@ -16,11 +16,11 @@ "@example-tsr-onboarding/customer-onboarding-journey": "workspace:*", "@example-tsr-onboarding/plan-module": "workspace:*", "@example-tsr-onboarding/profile-module": "workspace:*", - "@modular-react/core": "^1.0.0", - "@modular-react/journeys": "^1.0.0", - "@modular-react/react": "^1.0.0", - "@tanstack-react-modules/core": "^2.0.0", - "@tanstack-react-modules/runtime": "^2.0.0", + "@modular-react/core": "workspace:*", + "@modular-react/journeys": "workspace:*", + "@modular-react/react": "workspace:*", + "@tanstack-react-modules/core": "workspace:*", + "@tanstack-react-modules/runtime": "workspace:*", "@tanstack/react-router": "^1.168.8", "react": "^19.0.0", "react-dom": "^19.0.0", diff --git a/examples/tanstack-router/journey-invoke/app-shared/package.json b/examples/tanstack-router/journey-invoke/app-shared/package.json index 6344e59..3a37f2a 100644 --- a/examples/tanstack-router/journey-invoke/app-shared/package.json +++ b/examples/tanstack-router/journey-invoke/app-shared/package.json @@ -14,8 +14,8 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@modular-react/core": "^1.0.0", - "@tanstack-react-modules/core": "^2.0.0" + "@modular-react/core": "workspace:*", + "@tanstack-react-modules/core": "workspace:*" }, "devDependencies": { "@types/react": "^19.0.0", diff --git a/examples/tanstack-router/journey-invoke/journeys/checkout/package.json b/examples/tanstack-router/journey-invoke/journeys/checkout/package.json index 425810c..8331d7e 100644 --- a/examples/tanstack-router/journey-invoke/journeys/checkout/package.json +++ b/examples/tanstack-router/journey-invoke/journeys/checkout/package.json @@ -18,7 +18,7 @@ "@example-tsr-invoke/checkout-confirm-module": "workspace:*", "@example-tsr-invoke/checkout-review-module": "workspace:*", "@example-tsr-invoke/verify-identity-journey": "workspace:*", - "@modular-react/journeys": "^1.0.0" + "@modular-react/journeys": "workspace:*" }, "devDependencies": { "typescript": "^6.0.2" diff --git a/examples/tanstack-router/journey-invoke/journeys/verify-identity/package.json b/examples/tanstack-router/journey-invoke/journeys/verify-identity/package.json index 8fb3968..11baec4 100644 --- a/examples/tanstack-router/journey-invoke/journeys/verify-identity/package.json +++ b/examples/tanstack-router/journey-invoke/journeys/verify-identity/package.json @@ -16,7 +16,7 @@ "dependencies": { "@example-tsr-invoke/age-verify-module": "workspace:*", "@example-tsr-invoke/app-shared": "workspace:*", - "@modular-react/journeys": "^1.0.0" + "@modular-react/journeys": "workspace:*" }, "devDependencies": { "typescript": "^6.0.2" diff --git a/examples/tanstack-router/journey-invoke/modules/age-verify/package.json b/examples/tanstack-router/journey-invoke/modules/age-verify/package.json index 925dce1..d9d1004 100644 --- a/examples/tanstack-router/journey-invoke/modules/age-verify/package.json +++ b/examples/tanstack-router/journey-invoke/modules/age-verify/package.json @@ -15,7 +15,7 @@ }, "dependencies": { "@example-tsr-invoke/app-shared": "workspace:*", - "@modular-react/core": "^1.0.0" + "@modular-react/core": "workspace:*" }, "devDependencies": { "@types/react": "^19.0.0", diff --git a/examples/tanstack-router/journey-invoke/modules/checkout-confirm/package.json b/examples/tanstack-router/journey-invoke/modules/checkout-confirm/package.json index f36c4d0..30ea4e1 100644 --- a/examples/tanstack-router/journey-invoke/modules/checkout-confirm/package.json +++ b/examples/tanstack-router/journey-invoke/modules/checkout-confirm/package.json @@ -15,7 +15,7 @@ }, "dependencies": { "@example-tsr-invoke/app-shared": "workspace:*", - "@modular-react/core": "^1.0.0" + "@modular-react/core": "workspace:*" }, "devDependencies": { "@types/react": "^19.0.0", diff --git a/examples/tanstack-router/journey-invoke/modules/checkout-review/package.json b/examples/tanstack-router/journey-invoke/modules/checkout-review/package.json index ae32c2a..8d67075 100644 --- a/examples/tanstack-router/journey-invoke/modules/checkout-review/package.json +++ b/examples/tanstack-router/journey-invoke/modules/checkout-review/package.json @@ -15,7 +15,7 @@ }, "dependencies": { "@example-tsr-invoke/app-shared": "workspace:*", - "@modular-react/core": "^1.0.0" + "@modular-react/core": "workspace:*" }, "devDependencies": { "@types/react": "^19.0.0", diff --git a/examples/tanstack-router/journey-invoke/shell/package.json b/examples/tanstack-router/journey-invoke/shell/package.json index 2e7e0f2..6a5576d 100644 --- a/examples/tanstack-router/journey-invoke/shell/package.json +++ b/examples/tanstack-router/journey-invoke/shell/package.json @@ -16,11 +16,11 @@ "@example-tsr-invoke/checkout-journey": "workspace:*", "@example-tsr-invoke/checkout-review-module": "workspace:*", "@example-tsr-invoke/verify-identity-journey": "workspace:*", - "@modular-react/core": "^1.0.0", - "@modular-react/journeys": "^1.0.0", - "@modular-react/react": "^1.0.0", - "@tanstack-react-modules/core": "^2.0.0", - "@tanstack-react-modules/runtime": "^2.0.0", + "@modular-react/core": "workspace:*", + "@modular-react/journeys": "workspace:*", + "@modular-react/react": "workspace:*", + "@tanstack-react-modules/core": "workspace:*", + "@tanstack-react-modules/runtime": "workspace:*", "@tanstack/react-router": "^1.168.8", "react": "^19.0.0", "react-dom": "^19.0.0" diff --git a/packages/react-router-core/package.json b/packages/react-router-core/package.json index 2eb0b0d..01ea1d6 100644 --- a/packages/react-router-core/package.json +++ b/packages/react-router-core/package.json @@ -29,7 +29,7 @@ "typecheck": "tsc --noEmit" }, "devDependencies": { - "@modular-react/core": "^1.2.0", + "@modular-react/core": "workspace:*", "@types/react": "^19.0.0", "react": "^19.0.0", "react-router": "^7.6.0", diff --git a/packages/react-router-runtime/package.json b/packages/react-router-runtime/package.json index 0fad9fe..73bc8fe 100644 --- a/packages/react-router-runtime/package.json +++ b/packages/react-router-runtime/package.json @@ -29,10 +29,10 @@ "typecheck": "tsc --noEmit" }, "devDependencies": { - "@modular-react/core": "^1.2.0", + "@modular-react/core": "workspace:*", "@modular-react/journeys": "workspace:*", - "@modular-react/react": "^1.2.0", - "@react-router-modules/core": "^2.3.0", + "@modular-react/react": "workspace:*", + "@react-router-modules/core": "workspace:*", "@testing-library/react": "^16.0.0", "@types/react": "^19.0.0", "@types/react-dom": "^19.0.0", diff --git a/packages/react-router-testing/package.json b/packages/react-router-testing/package.json index 2daa063..bdfbe25 100644 --- a/packages/react-router-testing/package.json +++ b/packages/react-router-testing/package.json @@ -29,11 +29,11 @@ "typecheck": "tsc --noEmit" }, "devDependencies": { - "@modular-react/core": "^1.2.0", + "@modular-react/core": "workspace:*", "@modular-react/journeys": "workspace:*", - "@modular-react/react": "^1.2.0", - "@react-router-modules/core": "^2.3.0", - "@react-router-modules/runtime": "^2.3.0", + "@modular-react/react": "workspace:*", + "@react-router-modules/core": "workspace:*", + "@react-router-modules/runtime": "workspace:*", "@testing-library/react": "^16.0.0", "@types/react": "^19.0.0", "@types/react-dom": "^19.0.0", diff --git a/packages/react/package.json b/packages/react/package.json index 1a8af6b..401aebc 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -30,7 +30,7 @@ "typecheck": "tsc --noEmit" }, "devDependencies": { - "@modular-react/core": "^1.2.0", + "@modular-react/core": "workspace:*", "@testing-library/react": "^16.3.2", "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", diff --git a/packages/tanstack-router-core/package.json b/packages/tanstack-router-core/package.json index a01ae19..a5c6a01 100644 --- a/packages/tanstack-router-core/package.json +++ b/packages/tanstack-router-core/package.json @@ -29,7 +29,7 @@ "typecheck": "tsc --noEmit" }, "devDependencies": { - "@modular-react/core": "^1.2.0", + "@modular-react/core": "workspace:*", "@tanstack/react-router": "^1.168.8", "@types/react": "^19.0.0", "react": "^19.0.0", diff --git a/packages/tanstack-router-runtime/package.json b/packages/tanstack-router-runtime/package.json index 32da7dc..11e92a4 100644 --- a/packages/tanstack-router-runtime/package.json +++ b/packages/tanstack-router-runtime/package.json @@ -29,10 +29,10 @@ "typecheck": "tsc --noEmit" }, "devDependencies": { - "@modular-react/core": "^1.2.0", + "@modular-react/core": "workspace:*", "@modular-react/journeys": "workspace:*", - "@modular-react/react": "^1.2.0", - "@tanstack-react-modules/core": "^2.3.0", + "@modular-react/react": "workspace:*", + "@tanstack-react-modules/core": "workspace:*", "@tanstack/react-router": "^1.168.8", "@testing-library/react": "^16.0.0", "@types/react": "^19.0.0", diff --git a/packages/tanstack-router-testing/package.json b/packages/tanstack-router-testing/package.json index 3ed45a6..ceb92c2 100644 --- a/packages/tanstack-router-testing/package.json +++ b/packages/tanstack-router-testing/package.json @@ -29,11 +29,11 @@ "typecheck": "tsc --noEmit" }, "devDependencies": { - "@modular-react/core": "^1.2.0", + "@modular-react/core": "workspace:*", "@modular-react/journeys": "workspace:*", - "@modular-react/react": "^1.2.0", - "@tanstack-react-modules/core": "^2.3.0", - "@tanstack-react-modules/runtime": "^2.3.0", + "@modular-react/react": "workspace:*", + "@tanstack-react-modules/core": "workspace:*", + "@tanstack-react-modules/runtime": "workspace:*", "@tanstack/react-router": "^1.168.8", "@testing-library/react": "^16.0.0", "@types/react": "^19.0.0", diff --git a/packages/testing/package.json b/packages/testing/package.json index c3fa4cd..0dd243c 100644 --- a/packages/testing/package.json +++ b/packages/testing/package.json @@ -30,8 +30,8 @@ "typecheck": "tsc --noEmit" }, "devDependencies": { - "@modular-react/core": "^1.2.0", - "@modular-react/react": "^2.0.0", + "@modular-react/core": "workspace:*", + "@modular-react/react": "workspace:*", "@types/react": "^19.0.0", "@types/react-dom": "^19.0.0", "oxfmt": "^0.43.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5bcb318..01b488c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -40,10 +40,10 @@ importers: examples/react-router/active-project-manifest/app-shared: dependencies: '@modular-react/core': - specifier: ^1.0.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../../../../packages/core '@react-router-modules/core': - specifier: ^2.0.0 + specifier: workspace:* version: link:../../../../packages/react-router-core devDependencies: '@types/react': @@ -65,17 +65,17 @@ importers: specifier: workspace:* version: link:../../app-shared '@modular-react/core': - specifier: ^1.0.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../../../../../packages/core '@react-router-modules/core': - specifier: ^2.0.0 + specifier: workspace:* version: link:../../../../../packages/react-router-core '@react-router-modules/runtime': - specifier: ^2.0.0 + specifier: workspace:* version: link:../../../../../packages/react-router-runtime devDependencies: '@modular-react/testing': - specifier: ^1.0.0 + specifier: workspace:* version: link:../../../../../packages/testing '@types/react': specifier: ^19.0.0 @@ -102,16 +102,16 @@ importers: specifier: workspace:* version: link:../modules/integrations '@modular-react/core': - specifier: ^1.0.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../../../../packages/core '@modular-react/react': - specifier: ^1.0.0 - version: 1.4.0(@modular-react/core@1.8.1(@types/react@19.2.14))(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + specifier: workspace:* + version: link:../../../../packages/react '@react-router-modules/core': - specifier: ^2.0.0 + specifier: workspace:* version: link:../../../../packages/react-router-core '@react-router-modules/runtime': - specifier: ^2.0.0 + specifier: workspace:* version: link:../../../../packages/react-router-runtime react: specifier: ^19.0.0 @@ -145,10 +145,10 @@ importers: examples/react-router/customer-onboarding-journey/app-shared: dependencies: '@modular-react/core': - specifier: ^1.0.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../../../../packages/core '@react-router-modules/core': - specifier: ^2.0.0 + specifier: workspace:* version: link:../../../../packages/react-router-core devDependencies: '@types/react': @@ -179,7 +179,7 @@ importers: specifier: workspace:* version: link:../../modules/profile '@modular-react/journeys': - specifier: ^1.0.0 + specifier: workspace:* version: link:../../../../../packages/journeys devDependencies: typescript: @@ -192,8 +192,8 @@ importers: specifier: workspace:* version: link:../../app-shared '@modular-react/core': - specifier: ^1.0.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../../../../../packages/core devDependencies: '@types/react': specifier: ^19.0.0 @@ -211,8 +211,8 @@ importers: specifier: workspace:* version: link:../../app-shared '@modular-react/core': - specifier: ^1.0.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../../../../../packages/core devDependencies: '@types/react': specifier: ^19.0.0 @@ -230,8 +230,8 @@ importers: specifier: workspace:* version: link:../../app-shared '@modular-react/core': - specifier: ^1.0.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../../../../../packages/core devDependencies: '@types/react': specifier: ^19.0.0 @@ -261,19 +261,19 @@ importers: specifier: workspace:* version: link:../modules/profile '@modular-react/core': - specifier: ^1.0.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../../../../packages/core '@modular-react/journeys': - specifier: ^1.0.0 + specifier: workspace:* version: link:../../../../packages/journeys '@modular-react/react': - specifier: ^1.0.0 - version: 1.4.0(@modular-react/core@1.8.1(@types/react@19.2.14))(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + specifier: workspace:* + version: link:../../../../packages/react '@react-router-modules/core': - specifier: ^2.0.0 + specifier: workspace:* version: link:../../../../packages/react-router-core '@react-router-modules/runtime': - specifier: ^2.0.0 + specifier: workspace:* version: link:../../../../packages/react-router-runtime react: specifier: ^19.0.0 @@ -650,10 +650,10 @@ importers: examples/react-router/journey-invoke/app-shared: dependencies: '@modular-react/core': - specifier: ^1.0.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../../../../packages/core '@react-router-modules/core': - specifier: ^2.0.0 + specifier: workspace:* version: link:../../../../packages/react-router-core devDependencies: '@types/react': @@ -681,7 +681,7 @@ importers: specifier: workspace:* version: link:../verify-identity '@modular-react/journeys': - specifier: ^1.0.0 + specifier: workspace:* version: link:../../../../../packages/journeys devDependencies: typescript: @@ -697,7 +697,7 @@ importers: specifier: workspace:* version: link:../../app-shared '@modular-react/journeys': - specifier: ^1.0.0 + specifier: workspace:* version: link:../../../../../packages/journeys devDependencies: typescript: @@ -710,8 +710,8 @@ importers: specifier: workspace:* version: link:../../app-shared '@modular-react/core': - specifier: ^1.0.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../../../../../packages/core devDependencies: '@types/react': specifier: ^19.0.0 @@ -729,8 +729,8 @@ importers: specifier: workspace:* version: link:../../app-shared '@modular-react/core': - specifier: ^1.0.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../../../../../packages/core devDependencies: '@types/react': specifier: ^19.0.0 @@ -748,8 +748,8 @@ importers: specifier: workspace:* version: link:../../app-shared '@modular-react/core': - specifier: ^1.0.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../../../../../packages/core devDependencies: '@types/react': specifier: ^19.0.0 @@ -782,19 +782,19 @@ importers: specifier: workspace:* version: link:../journeys/verify-identity '@modular-react/core': - specifier: ^1.0.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../../../../packages/core '@modular-react/journeys': - specifier: ^1.0.0 + specifier: workspace:* version: link:../../../../packages/journeys '@modular-react/react': - specifier: ^1.0.0 - version: 1.4.0(@modular-react/core@1.8.1(@types/react@19.2.14))(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + specifier: workspace:* + version: link:../../../../packages/react '@react-router-modules/core': - specifier: ^2.0.0 + specifier: workspace:* version: link:../../../../packages/react-router-core '@react-router-modules/runtime': - specifier: ^2.0.0 + specifier: workspace:* version: link:../../../../packages/react-router-runtime react: specifier: ^19.0.0 @@ -825,10 +825,10 @@ importers: examples/react-router/remote-capabilities/app-shared: dependencies: '@modular-react/core': - specifier: ^1.0.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../../../../packages/core '@react-router-modules/core': - specifier: ^2.0.0 + specifier: workspace:* version: link:../../../../packages/react-router-core devDependencies: '@types/react': @@ -850,17 +850,17 @@ importers: specifier: workspace:* version: link:../../app-shared '@modular-react/core': - specifier: ^1.0.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../../../../../packages/core '@react-router-modules/core': - specifier: ^2.0.0 + specifier: workspace:* version: link:../../../../../packages/react-router-core '@react-router-modules/runtime': - specifier: ^2.0.0 + specifier: workspace:* version: link:../../../../../packages/react-router-runtime devDependencies: '@modular-react/testing': - specifier: ^1.0.0 + specifier: workspace:* version: link:../../../../../packages/testing '@types/react': specifier: ^19.0.0 @@ -887,16 +887,16 @@ importers: specifier: workspace:* version: link:../modules/integrations '@modular-react/core': - specifier: ^1.0.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../../../../packages/core '@modular-react/react': - specifier: ^1.0.0 - version: 1.4.0(@modular-react/core@1.8.1(@types/react@19.2.14))(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + specifier: workspace:* + version: link:../../../../packages/react '@react-router-modules/core': - specifier: ^2.0.0 + specifier: workspace:* version: link:../../../../packages/react-router-core '@react-router-modules/runtime': - specifier: ^2.0.0 + specifier: workspace:* version: link:../../../../packages/react-router-runtime react: specifier: ^19.0.0 @@ -930,8 +930,8 @@ importers: examples/tanstack-router/customer-onboarding-journey/app-shared: dependencies: '@modular-react/core': - specifier: ^1.0.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../../../../packages/core '@tanstack-react-modules/core': specifier: workspace:* version: link:../../../../packages/tanstack-router-core @@ -964,7 +964,7 @@ importers: specifier: workspace:* version: link:../../modules/profile '@modular-react/journeys': - specifier: ^1.0.0 + specifier: workspace:* version: link:../../../../../packages/journeys devDependencies: typescript: @@ -977,8 +977,8 @@ importers: specifier: workspace:* version: link:../../app-shared '@modular-react/core': - specifier: ^1.0.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../../../../../packages/core devDependencies: '@types/react': specifier: ^19.0.0 @@ -996,8 +996,8 @@ importers: specifier: workspace:* version: link:../../app-shared '@modular-react/core': - specifier: ^1.0.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../../../../../packages/core devDependencies: '@types/react': specifier: ^19.0.0 @@ -1015,8 +1015,8 @@ importers: specifier: workspace:* version: link:../../app-shared '@modular-react/core': - specifier: ^1.0.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../../../../../packages/core devDependencies: '@types/react': specifier: ^19.0.0 @@ -1046,19 +1046,19 @@ importers: specifier: workspace:* version: link:../modules/profile '@modular-react/core': - specifier: ^1.0.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../../../../packages/core '@modular-react/journeys': - specifier: ^1.0.0 + specifier: workspace:* version: link:../../../../packages/journeys '@modular-react/react': - specifier: ^1.0.0 - version: 1.4.0(@modular-react/core@1.8.1(@types/react@19.2.14))(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + specifier: workspace:* + version: link:../../../../packages/react '@tanstack-react-modules/core': - specifier: ^2.0.0 + specifier: workspace:* version: link:../../../../packages/tanstack-router-core '@tanstack-react-modules/runtime': - specifier: ^2.0.0 + specifier: workspace:* version: link:../../../../packages/tanstack-router-runtime '@tanstack/react-router': specifier: ^1.168.8 @@ -1438,10 +1438,10 @@ importers: examples/tanstack-router/journey-invoke/app-shared: dependencies: '@modular-react/core': - specifier: ^1.0.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../../../../packages/core '@tanstack-react-modules/core': - specifier: ^2.0.0 + specifier: workspace:* version: link:../../../../packages/tanstack-router-core devDependencies: '@types/react': @@ -1469,7 +1469,7 @@ importers: specifier: workspace:* version: link:../verify-identity '@modular-react/journeys': - specifier: ^1.0.0 + specifier: workspace:* version: link:../../../../../packages/journeys devDependencies: typescript: @@ -1485,7 +1485,7 @@ importers: specifier: workspace:* version: link:../../app-shared '@modular-react/journeys': - specifier: ^1.0.0 + specifier: workspace:* version: link:../../../../../packages/journeys devDependencies: typescript: @@ -1498,8 +1498,8 @@ importers: specifier: workspace:* version: link:../../app-shared '@modular-react/core': - specifier: ^1.0.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../../../../../packages/core devDependencies: '@types/react': specifier: ^19.0.0 @@ -1517,8 +1517,8 @@ importers: specifier: workspace:* version: link:../../app-shared '@modular-react/core': - specifier: ^1.0.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../../../../../packages/core devDependencies: '@types/react': specifier: ^19.0.0 @@ -1536,8 +1536,8 @@ importers: specifier: workspace:* version: link:../../app-shared '@modular-react/core': - specifier: ^1.0.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../../../../../packages/core devDependencies: '@types/react': specifier: ^19.0.0 @@ -1570,19 +1570,19 @@ importers: specifier: workspace:* version: link:../journeys/verify-identity '@modular-react/core': - specifier: ^1.0.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../../../../packages/core '@modular-react/journeys': - specifier: ^1.0.0 + specifier: workspace:* version: link:../../../../packages/journeys '@modular-react/react': - specifier: ^1.0.0 - version: 1.4.0(@modular-react/core@1.8.1(@types/react@19.2.14))(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + specifier: workspace:* + version: link:../../../../packages/react '@tanstack-react-modules/core': - specifier: ^2.0.0 + specifier: workspace:* version: link:../../../../packages/tanstack-router-core '@tanstack-react-modules/runtime': - specifier: ^2.0.0 + specifier: workspace:* version: link:../../../../packages/tanstack-router-runtime '@tanstack/react-router': specifier: ^1.168.8 @@ -2013,8 +2013,8 @@ importers: packages/react: devDependencies: '@modular-react/core': - specifier: ^1.2.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../core '@testing-library/react': specifier: ^16.3.2 version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) @@ -2077,8 +2077,8 @@ importers: packages/react-router-core: devDependencies: '@modular-react/core': - specifier: ^1.2.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../core '@types/react': specifier: ^19.0.0 version: 19.2.14 @@ -2107,16 +2107,16 @@ importers: packages/react-router-runtime: devDependencies: '@modular-react/core': - specifier: ^1.2.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../core '@modular-react/journeys': specifier: workspace:* version: link:../journeys '@modular-react/react': - specifier: ^1.2.0 - version: 1.4.0(@modular-react/core@1.8.1(@types/react@19.2.14))(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + specifier: workspace:* + version: link:../react '@react-router-modules/core': - specifier: ^2.3.0 + specifier: workspace:* version: link:../react-router-core '@testing-library/react': specifier: ^16.0.0 @@ -2158,19 +2158,19 @@ importers: packages/react-router-testing: devDependencies: '@modular-react/core': - specifier: ^1.2.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../core '@modular-react/journeys': specifier: workspace:* version: link:../journeys '@modular-react/react': - specifier: ^1.2.0 - version: 1.4.0(@modular-react/core@1.8.1(@types/react@19.2.14))(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + specifier: workspace:* + version: link:../react '@react-router-modules/core': - specifier: ^2.3.0 + specifier: workspace:* version: link:../react-router-core '@react-router-modules/runtime': - specifier: ^2.3.0 + specifier: workspace:* version: link:../react-router-runtime '@testing-library/react': specifier: ^16.0.0 @@ -2231,8 +2231,8 @@ importers: packages/tanstack-router-core: devDependencies: '@modular-react/core': - specifier: ^1.2.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../core '@tanstack/react-router': specifier: ^1.168.8 version: 1.169.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) @@ -2261,16 +2261,16 @@ importers: packages/tanstack-router-runtime: devDependencies: '@modular-react/core': - specifier: ^1.2.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../core '@modular-react/journeys': specifier: workspace:* version: link:../journeys '@modular-react/react': - specifier: ^1.2.0 - version: 1.4.0(@modular-react/core@1.8.1(@types/react@19.2.14))(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + specifier: workspace:* + version: link:../react '@tanstack-react-modules/core': - specifier: ^2.3.0 + specifier: workspace:* version: link:../tanstack-router-core '@tanstack/react-router': specifier: ^1.168.8 @@ -2312,19 +2312,19 @@ importers: packages/tanstack-router-testing: devDependencies: '@modular-react/core': - specifier: ^1.2.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../core '@modular-react/journeys': specifier: workspace:* version: link:../journeys '@modular-react/react': - specifier: ^1.2.0 - version: 1.4.0(@modular-react/core@1.8.1(@types/react@19.2.14))(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + specifier: workspace:* + version: link:../react '@tanstack-react-modules/core': - specifier: ^2.3.0 + specifier: workspace:* version: link:../tanstack-router-core '@tanstack-react-modules/runtime': - specifier: ^2.3.0 + specifier: workspace:* version: link:../tanstack-router-runtime '@tanstack/react-router': specifier: ^1.168.8 @@ -2363,10 +2363,10 @@ importers: packages/testing: devDependencies: '@modular-react/core': - specifier: ^1.2.0 - version: 1.8.1(@types/react@19.2.14) + specifier: workspace:* + version: link:../core '@modular-react/react': - specifier: ^2.0.0 + specifier: workspace:* version: link:../react '@types/react': specifier: ^19.0.0 @@ -3010,21 +3010,6 @@ packages: '@cfworker/json-schema': optional: true - '@modular-react/core@1.8.1': - resolution: {integrity: sha512-7DjxnPh7Sv697S4NHGRSoP7l5ZgEdhqWfSgPff01VNehg+ZzPdqpwR44fUjLLm6uqLrQauOo1CckDLhwmfGZ4w==} - peerDependencies: - '@types/react': ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - - '@modular-react/react@1.4.0': - resolution: {integrity: sha512-C6zDG3A23iWIKu7bA40xonelVBN1BpgztDkK/wAUkLY6YJeqG/Ww4FEqejeBfhQ5+hnjgQyQXbkMHIrD4ce0pg==} - peerDependencies: - '@modular-react/core': ^1.2.0 - react: ^19.0.0 - react-dom: ^19.0.0 - '@mswjs/interceptors@0.41.7': resolution: {integrity: sha512-D0nkS5+sx87mYpxFqASImCineYoEl9wGlUPrzkuS0ohzG8wfophLpE+I76qGJ0slLAVI19do5SI9pWJNCVf4fg==} engines: {node: '>=18'} @@ -6564,16 +6549,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@modular-react/core@1.8.1(@types/react@19.2.14)': - optionalDependencies: - '@types/react': 19.2.14 - - '@modular-react/react@1.4.0(@modular-react/core@1.8.1(@types/react@19.2.14))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': - dependencies: - '@modular-react/core': 1.8.1(@types/react@19.2.14) - react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) - '@mswjs/interceptors@0.41.7': dependencies: '@open-draft/deferred-promise': 2.2.0 From e9306812ddb480105a6ecfcb8e560330a002736a Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 7 May 2026 14:04:53 +0000 Subject: [PATCH 7/8] test(testing): cover partial-failure case for preloadEntries rejections Addresses CodeRabbit nitpick on PR #32. The previous rejection test only exercised a single-importer rejection, which `Promise.all` would propagate unconditionally. The interesting property to verify is the comment in `preload-entries.ts:49-52`: that a mixed resolve/reject lineup does NOT leak the resolving sibling's promise as an unhandledRejection. The new test: - mixes one resolving and one rejecting importer in the same module - registers a process-level `unhandledRejection` listener for the duration of the assertion - drains microtasks via `setImmediate` so any pending notifications fire - asserts `leaks === []` after restoring the listener This gives a concrete behavioral check of the structural guarantee, not just the happy-path rejection propagation. --- packages/testing/src/preload-entries.test.ts | 28 ++++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/packages/testing/src/preload-entries.test.ts b/packages/testing/src/preload-entries.test.ts index 4f253c2..4732a91 100644 --- a/packages/testing/src/preload-entries.test.ts +++ b/packages/testing/src/preload-entries.test.ts @@ -78,12 +78,30 @@ describe("preloadEntries", () => { await expect(preloadEntries([])).resolves.toBeUndefined(); }); - it("propagates importer rejections", async () => { + it("propagates the first rejection without leaking unhandled rejections from sibling importers", async () => { + // Mixed resolve/reject lineup verifies the comment in preload-entries.ts: + // Promise.all attaches a handler to every iterated promise, so the + // resolving sibling never surfaces as an unhandledRejection. We back the + // structural guarantee with a process-level listener. const failure = new Error("chunk load failed"); - const importer = vi.fn(() => Promise.reject(failure)); - const mod = module_("m", { e: lazyEntry(importer) }); - - await expect(preloadEntries([mod])).rejects.toBe(failure); + const success = vi.fn(() => Promise.resolve({ default: Stub })); + const reject = vi.fn(() => Promise.reject(failure)); + const mod = module_("m", { ok: lazyEntry(success), bad: lazyEntry(reject) }); + + const leaks: unknown[] = []; + const onUnhandled = (reason: unknown) => leaks.push(reason); + process.on("unhandledRejection", onUnhandled); + try { + await expect(preloadEntries([mod])).rejects.toBe(failure); + // Drain microtasks so any pending unhandled-rejection notifications fire. + await new Promise((r) => setImmediate(r)); + } finally { + process.off("unhandledRejection", onUnhandled); + } + + expect(success).toHaveBeenCalledTimes(1); + expect(reject).toHaveBeenCalledTimes(1); + expect(leaks).toEqual([]); }); it("re-exports `preloadEntry` from @modular-react/react verbatim", () => { From 1a12eaf88882d64b79a6768ec8d33ef9415fb832 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 7 May 2026 14:25:28 +0000 Subject: [PATCH 8/8] fix(testing): bump @modular-react/core peerDep to ^2.0.0 Address @diogomiguel's review comment on PR #32. The testing package's peer on `@modular-react/core` was still `^1.2.0` even though it also peers on `@modular-react/react@^2.0.0`, which itself imports `EagerModuleEntryPoint` / `LazyModuleEntryPoint` from core (only exported by core 2.x). The `^1.2.0` claim was incompatible with what the package actually requires at runtime. --- packages/testing/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/testing/package.json b/packages/testing/package.json index 0dd243c..a44b4a2 100644 --- a/packages/testing/package.json +++ b/packages/testing/package.json @@ -44,7 +44,7 @@ "vitest": "^4.1.0" }, "peerDependencies": { - "@modular-react/core": "^1.2.0", + "@modular-react/core": "^2.0.0", "@modular-react/react": "^2.0.0", "react": "^19.0.0", "react-dom": "^19.0.0"