@rangojs/router 0.0.0-experimental.97 → 0.0.0-experimental.98914650
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -9
- package/dist/bin/rango.js +157 -63
- package/dist/testing/vitest.js +82 -0
- package/dist/vite/index.js +1584 -639
- package/package.json +71 -21
- package/skills/api-client/SKILL.md +211 -0
- package/skills/breadcrumbs/SKILL.md +60 -0
- package/skills/bundle-analysis/SKILL.md +159 -0
- package/skills/cache-guide/SKILL.md +222 -30
- package/skills/caching/SKILL.md +263 -8
- package/skills/composability/SKILL.md +27 -2
- package/skills/css/SKILL.md +76 -0
- package/skills/document-cache/SKILL.md +78 -55
- package/skills/handler-use/SKILL.md +3 -1
- package/skills/hooks/SKILL.md +235 -28
- package/skills/host-router/SKILL.md +122 -22
- package/skills/i18n/SKILL.md +276 -0
- package/skills/intercept/SKILL.md +29 -5
- package/skills/layout/SKILL.md +13 -9
- package/skills/links/SKILL.md +173 -17
- package/skills/loader/SKILL.md +170 -23
- package/skills/middleware/SKILL.md +16 -10
- package/skills/migrate-nextjs/SKILL.md +38 -16
- package/skills/mime-routes/SKILL.md +27 -0
- package/skills/observability/SKILL.md +137 -0
- package/skills/parallel/SKILL.md +11 -7
- package/skills/prerender/SKILL.md +14 -33
- package/skills/rango/SKILL.md +250 -25
- package/skills/react-compiler/SKILL.md +168 -0
- package/skills/response-routes/SKILL.md +114 -47
- package/skills/route/SKILL.md +42 -5
- package/skills/router-setup/SKILL.md +3 -3
- package/skills/server-actions/SKILL.md +78 -42
- package/skills/tailwind/SKILL.md +27 -3
- package/skills/testing/SKILL.md +129 -0
- package/skills/testing/bindings.md +89 -0
- package/skills/testing/cache-prerender.md +124 -0
- package/skills/testing/client-components.md +122 -0
- package/skills/testing/e2e-parity.md +125 -0
- package/skills/testing/flight.md +92 -0
- package/skills/testing/handles.md +129 -0
- package/skills/testing/loader.md +128 -0
- package/skills/testing/middleware.md +99 -0
- package/skills/testing/render-handler.md +121 -0
- package/skills/testing/response-routes.md +95 -0
- package/skills/testing/reverse-and-types.md +84 -0
- package/skills/testing/server-actions.md +107 -0
- package/skills/testing/server-tree.md +128 -0
- package/skills/testing/setup.md +120 -0
- package/skills/typesafety/SKILL.md +316 -26
- package/skills/use-cache/SKILL.md +36 -5
- package/skills/vercel/SKILL.md +107 -0
- package/skills/view-transitions/SKILL.md +294 -0
- package/src/__augment-tests__/augment.ts +81 -0
- package/src/__augment-tests__/augmented.check.ts +116 -0
- package/src/__internal.ts +0 -65
- package/src/browser/action-coordinator.ts +53 -36
- package/src/browser/action-fence.ts +47 -0
- package/src/browser/app-shell.ts +14 -27
- package/src/browser/cookie-name.ts +140 -0
- package/src/browser/event-controller.ts +37 -143
- package/src/browser/history-state.ts +21 -0
- package/src/browser/index.ts +3 -3
- package/src/browser/invalidate-client-cache.ts +52 -0
- package/src/browser/navigation-bridge.ts +30 -59
- package/src/browser/navigation-client.ts +96 -84
- package/src/browser/navigation-store-handle.ts +38 -0
- package/src/browser/navigation-store.ts +32 -82
- package/src/browser/navigation-transaction.ts +9 -59
- package/src/browser/partial-update.ts +60 -127
- package/src/browser/prefetch/cache.ts +82 -72
- package/src/browser/prefetch/fetch.ts +108 -33
- package/src/browser/prefetch/queue.ts +6 -3
- package/src/browser/rango-state.ts +157 -115
- package/src/browser/react/Link.tsx +0 -2
- package/src/browser/react/NavigationProvider.tsx +41 -48
- package/src/browser/react/ScrollRestoration.tsx +10 -6
- package/src/browser/react/filter-segment-order.ts +0 -2
- package/src/browser/react/index.ts +0 -48
- package/src/browser/react/location-state-shared.ts +166 -8
- package/src/browser/react/location-state.ts +39 -14
- package/src/browser/react/use-action.ts +6 -15
- package/src/browser/react/use-handle.ts +17 -14
- package/src/browser/react/use-link-status.ts +0 -4
- package/src/browser/react/use-navigation.ts +0 -3
- package/src/browser/react/use-params.ts +11 -11
- package/src/browser/react/use-reverse.ts +106 -0
- package/src/browser/react/use-router.ts +20 -5
- package/src/browser/react/use-search-params.ts +0 -5
- package/src/browser/react/use-segments.ts +0 -13
- package/src/browser/response-adapter.ts +52 -1
- package/src/browser/rsc-router.tsx +70 -34
- package/src/browser/scroll-restoration.ts +22 -14
- package/src/browser/segment-structure-assert.ts +2 -2
- package/src/browser/server-action-bridge.ts +168 -44
- package/src/browser/types.ts +36 -21
- package/src/browser/validate-redirect-origin.ts +43 -16
- package/src/build/collect-fallback-refs.ts +107 -0
- package/src/build/generate-manifest.ts +60 -35
- package/src/build/generate-route-types.ts +3 -0
- package/src/build/index.ts +8 -2
- package/src/build/prefix-tree-utils.ts +123 -0
- package/src/build/route-trie.ts +89 -10
- package/src/build/route-types/codegen.ts +4 -4
- package/src/build/route-types/include-resolution.ts +1 -1
- package/src/build/route-types/param-extraction.ts +6 -3
- package/src/build/route-types/per-module-writer.ts +7 -4
- package/src/build/route-types/router-processing.ts +122 -22
- package/src/build/route-types/scan-filter.ts +1 -1
- package/src/build/route-types/source-scan.ts +118 -0
- package/src/build/runtime-discovery.ts +9 -20
- package/src/cache/cache-error.ts +104 -0
- package/src/cache/cache-policy.ts +68 -28
- package/src/cache/cache-runtime.ts +134 -32
- package/src/cache/cache-scope.ts +100 -74
- package/src/cache/cache-tag.ts +98 -0
- package/src/cache/cf/cf-cache-store.ts +2255 -238
- package/src/cache/cf/index.ts +6 -16
- package/src/cache/document-cache.ts +61 -20
- package/src/cache/handle-snapshot.ts +63 -0
- package/src/cache/index.ts +22 -20
- package/src/cache/memory-segment-store.ts +136 -37
- package/src/cache/profile-registry.ts +6 -30
- package/src/cache/read-through-swr.ts +41 -11
- package/src/cache/segment-codec.ts +0 -16
- package/src/cache/tag-invalidation.ts +230 -0
- package/src/cache/types.ts +33 -100
- package/src/cache/vercel/index.ts +11 -0
- package/src/cache/vercel/vercel-cache-store.ts +799 -0
- package/src/client.rsc.tsx +6 -21
- package/src/client.tsx +25 -61
- package/src/component-utils.ts +19 -0
- package/src/context-var.ts +17 -5
- package/src/decode-loader-results.ts +36 -0
- package/src/defer.ts +196 -0
- package/src/deps/ssr.ts +0 -1
- package/src/errors.ts +30 -4
- package/src/handle.ts +31 -23
- package/src/handles/MetaTags.tsx +0 -14
- package/src/handles/breadcrumbs.ts +16 -5
- package/src/handles/meta.ts +0 -39
- package/src/host/cookie-handler.ts +0 -36
- package/src/host/errors.ts +0 -24
- package/src/host/index.ts +8 -2
- package/src/host/pattern-matcher.ts +7 -50
- package/src/host/router.ts +107 -99
- package/src/host/testing.ts +40 -27
- package/src/host/types.ts +37 -4
- package/src/host/utils.ts +1 -1
- package/src/href-client.ts +137 -22
- package/src/index.rsc.ts +63 -9
- package/src/index.ts +64 -9
- package/src/internal-debug.ts +2 -4
- package/src/loader-store.ts +500 -0
- package/src/loader.rsc.ts +20 -13
- package/src/loader.ts +12 -11
- package/src/missing-id-error.ts +68 -0
- package/src/network-error-thrower.tsx +1 -6
- package/src/outlet-provider.tsx +1 -5
- package/src/prerender/param-hash.ts +10 -11
- package/src/prerender/store.ts +32 -37
- package/src/prerender.ts +61 -6
- package/src/redirect-origin.ts +100 -0
- package/src/response-utils.ts +9 -0
- package/src/reverse.ts +65 -40
- package/src/root-error-boundary.tsx +1 -19
- package/src/route-content-wrapper.tsx +7 -72
- package/src/route-definition/dsl-helpers.ts +244 -281
- package/src/route-definition/helper-factories.ts +29 -139
- package/src/route-definition/helpers-types.ts +40 -17
- package/src/route-definition/redirect.ts +43 -9
- package/src/route-definition/resolve-handler-use.ts +6 -0
- package/src/route-definition/use-item-types.ts +32 -0
- package/src/route-map-builder.ts +0 -16
- package/src/route-types.ts +19 -41
- package/src/router/basename.ts +14 -0
- package/src/router/content-negotiation.ts +15 -15
- package/src/router/error-handling.ts +13 -17
- package/src/router/find-match.ts +44 -23
- package/src/router/handler-context.ts +4 -41
- package/src/router/intercept-resolution.ts +14 -19
- package/src/router/lazy-includes.ts +9 -46
- package/src/router/loader-resolution.ts +91 -46
- package/src/router/logging.ts +0 -6
- package/src/router/manifest.ts +18 -29
- package/src/router/match-api.ts +0 -20
- package/src/router/match-context.ts +0 -22
- package/src/router/match-handlers.ts +57 -58
- package/src/router/match-middleware/background-revalidation.ts +0 -7
- package/src/router/match-middleware/cache-lookup.ts +150 -271
- package/src/router/match-middleware/cache-store.ts +3 -33
- package/src/router/match-middleware/intercept-resolution.ts +0 -22
- package/src/router/match-middleware/segment-resolution.ts +0 -22
- package/src/router/match-pipelines.ts +1 -42
- package/src/router/match-result.ts +31 -80
- package/src/router/metrics.ts +0 -34
- package/src/router/middleware-types.ts +5 -112
- package/src/router/middleware.ts +118 -133
- package/src/router/navigation-snapshot.ts +0 -51
- package/src/router/params-util.ts +23 -0
- package/src/router/pattern-matching.ts +62 -67
- package/src/router/prerender-match.ts +99 -63
- package/src/router/preview-match.ts +3 -1
- package/src/router/request-classification.ts +28 -62
- package/src/router/revalidation.ts +50 -56
- package/src/router/route-snapshot.ts +0 -1
- package/src/router/router-context.ts +0 -27
- package/src/router/router-interfaces.ts +68 -35
- package/src/router/router-options.ts +55 -1
- package/src/router/router-registry.ts +2 -5
- package/src/router/segment-resolution/fresh.ts +44 -63
- package/src/router/segment-resolution/helpers.ts +34 -0
- package/src/router/segment-resolution/loader-cache.ts +40 -37
- package/src/router/segment-resolution/revalidation.ts +203 -285
- package/src/router/segment-resolution/static-store.ts +19 -5
- package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
- package/src/router/segment-resolution/view-transition-default.ts +36 -0
- package/src/router/segment-resolution.ts +4 -1
- package/src/router/segment-wrappers.ts +0 -3
- package/src/router/state-cookie-name.ts +33 -0
- package/src/router/substitute-pattern-params.ts +56 -0
- package/src/router/telemetry-otel.ts +0 -20
- package/src/router/telemetry.ts +96 -19
- package/src/router/timeout.ts +0 -20
- package/src/router/trie-matching.ts +87 -48
- package/src/router/types.ts +9 -63
- package/src/router/url-params.ts +0 -5
- package/src/router.ts +80 -41
- package/src/rsc/handler-context.ts +3 -2
- package/src/rsc/handler.ts +83 -78
- package/src/rsc/helpers.ts +93 -5
- package/src/rsc/index.ts +1 -1
- package/src/rsc/json-route-result.ts +38 -0
- package/src/rsc/manifest-init.ts +28 -41
- package/src/rsc/origin-guard.ts +39 -25
- package/src/rsc/progressive-enhancement.ts +12 -1
- package/src/rsc/redirect-guard.ts +99 -0
- package/src/rsc/response-error.ts +79 -12
- package/src/rsc/response-route-handler.ts +76 -62
- package/src/rsc/rsc-rendering.ts +41 -60
- package/src/rsc/runtime-warnings.ts +23 -10
- package/src/rsc/server-action.ts +62 -67
- package/src/rsc/ssr-setup.ts +16 -0
- package/src/rsc/types.ts +10 -5
- package/src/runtime-env.ts +18 -0
- package/src/search-params.ts +4 -20
- package/src/segment-loader-promise.ts +14 -2
- package/src/segment-system.tsx +199 -142
- package/src/serialize.ts +243 -0
- package/src/server/context.ts +150 -51
- package/src/server/cookie-store.ts +80 -5
- package/src/server/handle-store.ts +7 -24
- package/src/server/loader-registry.ts +5 -24
- package/src/server/request-context.ts +165 -87
- package/src/ssr/index.tsx +14 -14
- package/src/static-handler.ts +10 -13
- package/src/testing/cache-status.ts +162 -0
- package/src/testing/collect-handle.ts +40 -0
- package/src/testing/dispatch.ts +618 -0
- package/src/testing/dom.entry.ts +22 -0
- package/src/testing/e2e/fixture.ts +188 -0
- package/src/testing/e2e/index.ts +128 -0
- package/src/testing/e2e/matchers.ts +35 -0
- package/src/testing/e2e/page-helpers.ts +272 -0
- package/src/testing/e2e/parity.ts +387 -0
- package/src/testing/e2e/server.ts +195 -0
- package/src/testing/flight-matchers.ts +97 -0
- package/src/testing/flight-normalize.ts +11 -0
- package/src/testing/flight-runtime.d.ts +57 -0
- package/src/testing/flight-tree.ts +682 -0
- package/src/testing/flight.entry.ts +52 -0
- package/src/testing/flight.ts +232 -0
- package/src/testing/generated-routes.ts +183 -0
- package/src/testing/index.ts +99 -0
- package/src/testing/internal/context.ts +348 -0
- package/src/testing/internal/flight-client-globals.ts +30 -0
- package/src/testing/internal/seed-vars.ts +54 -0
- package/src/testing/render-handler.ts +330 -0
- package/src/testing/render-route.tsx +566 -0
- package/src/testing/run-loader.ts +378 -0
- package/src/testing/run-middleware.ts +205 -0
- package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
- package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
- package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
- package/src/testing/vitest-stubs/version.ts +5 -0
- package/src/testing/vitest.ts +305 -0
- package/src/theme/ThemeProvider.tsx +0 -52
- package/src/theme/ThemeScript.tsx +0 -6
- package/src/theme/constants.ts +0 -12
- package/src/theme/index.ts +0 -7
- package/src/theme/theme-context.ts +1 -5
- package/src/theme/theme-script.ts +0 -14
- package/src/theme/use-theme.ts +0 -3
- package/src/types/boundaries.ts +0 -35
- package/src/types/cache-types.ts +13 -4
- package/src/types/error-types.ts +30 -90
- package/src/types/global-namespace.ts +54 -41
- package/src/types/handler-context.ts +97 -22
- package/src/types/index.ts +1 -10
- package/src/types/loader-types.ts +6 -3
- package/src/types/request-scope.ts +0 -19
- package/src/types/route-config.ts +6 -50
- package/src/types/route-entry.ts +0 -6
- package/src/types/segments.ts +18 -14
- package/src/urls/include-helper.ts +9 -56
- package/src/urls/index.ts +1 -11
- package/src/urls/path-helper-types.ts +19 -5
- package/src/urls/path-helper.ts +17 -106
- package/src/urls/pattern-types.ts +36 -19
- package/src/urls/response-types.ts +20 -19
- package/src/urls/type-extraction.ts +58 -139
- package/src/urls/urls-function.ts +1 -18
- package/src/use-loader.tsx +292 -107
- package/src/vite/debug.ts +1 -0
- package/src/vite/discovery/bundle-postprocess.ts +8 -7
- package/src/vite/discovery/discover-routers.ts +95 -82
- package/src/vite/discovery/discovery-errors.ts +194 -0
- package/src/vite/discovery/prerender-collection.ts +26 -34
- package/src/vite/discovery/route-types-writer.ts +40 -84
- package/src/vite/discovery/state.ts +39 -1
- package/src/vite/discovery/virtual-module-codegen.ts +14 -34
- package/src/vite/index.ts +4 -0
- package/src/vite/plugin-types.ts +185 -10
- package/src/vite/plugins/cjs-to-esm.ts +3 -18
- package/src/vite/plugins/client-ref-dedup.ts +0 -11
- package/src/vite/plugins/client-ref-hashing.ts +12 -11
- package/src/vite/plugins/cloudflare-protocol-stub.ts +1 -21
- package/src/vite/plugins/expose-action-id.ts +4 -75
- package/src/vite/plugins/expose-id-utils.ts +3 -54
- package/src/vite/plugins/expose-ids/export-analysis.ts +76 -34
- package/src/vite/plugins/expose-ids/handler-transform.ts +6 -74
- package/src/vite/plugins/expose-ids/loader-transform.ts +3 -20
- package/src/vite/plugins/expose-ids/router-transform.ts +0 -13
- package/src/vite/plugins/expose-internal-ids.ts +57 -67
- package/src/vite/plugins/performance-tracks.ts +9 -16
- package/src/vite/plugins/refresh-cmd.ts +1 -1
- package/src/vite/plugins/use-cache-transform.ts +26 -49
- package/src/vite/plugins/vercel-output.ts +258 -0
- package/src/vite/plugins/version-injector.ts +2 -32
- package/src/vite/plugins/version-plugin.ts +32 -23
- package/src/vite/plugins/virtual-entries.ts +35 -17
- package/src/vite/rango.ts +148 -115
- package/src/vite/router-discovery.ts +220 -68
- package/src/vite/utils/ast-handler-extract.ts +15 -31
- package/src/vite/utils/bundle-analysis.ts +10 -15
- package/src/vite/utils/client-chunks.ts +184 -0
- package/src/vite/utils/forward-user-plugins.ts +171 -0
- package/src/vite/utils/manifest-utils.ts +4 -59
- package/src/vite/utils/package-resolution.ts +1 -73
- package/src/vite/utils/prerender-utils.ts +0 -34
- package/src/vite/utils/shared-utils.ts +95 -43
- package/src/browser/action-response-classifier.ts +0 -99
- package/src/browser/react/use-client-cache.ts +0 -58
- package/src/browser/shallow.ts +0 -40
- package/src/handles/index.ts +0 -7
- package/src/router/middleware-cookies.ts +0 -55
package/src/vite/rango.ts
CHANGED
|
@@ -15,15 +15,27 @@ import {
|
|
|
15
15
|
getPublishedPackageName,
|
|
16
16
|
getVendorAliases,
|
|
17
17
|
} from "./utils/package-resolution.js";
|
|
18
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
findRouterFiles,
|
|
20
|
+
findHostRouterFiles,
|
|
21
|
+
} from "../build/generate-route-types.js";
|
|
19
22
|
import { createVersionPlugin } from "./plugins/version-plugin.js";
|
|
20
23
|
import {
|
|
21
|
-
|
|
24
|
+
sharedRolldownOptions,
|
|
22
25
|
createVirtualEntriesPlugin,
|
|
23
26
|
onwarn,
|
|
24
27
|
getManualChunks,
|
|
25
28
|
} from "./utils/shared-utils.js";
|
|
26
|
-
import
|
|
29
|
+
import {
|
|
30
|
+
resolveClientChunks,
|
|
31
|
+
type ClientChunkContext,
|
|
32
|
+
} from "./utils/client-chunks.js";
|
|
33
|
+
import type {
|
|
34
|
+
RangoOptions,
|
|
35
|
+
RangoNodeOptions,
|
|
36
|
+
RangoVercelOptions,
|
|
37
|
+
} from "./plugin-types.js";
|
|
38
|
+
import { createVercelOutputPlugin } from "./plugins/vercel-output.js";
|
|
27
39
|
import { printBanner, rangoVersion } from "./utils/banner.js";
|
|
28
40
|
import { createVersionInjectorPlugin } from "./plugins/version-injector.js";
|
|
29
41
|
import { createCjsToEsmPlugin } from "./plugins/cjs-to-esm.js";
|
|
@@ -62,6 +74,12 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
62
74
|
const resolvedOptions: RangoOptions = options ?? { preset: "node" };
|
|
63
75
|
const preset = resolvedOptions.preset ?? "node";
|
|
64
76
|
const showBanner = resolvedOptions.banner ?? true;
|
|
77
|
+
const clientChunksOption = resolvedOptions.clientChunks ?? true;
|
|
78
|
+
const useBuiltInClientChunks = clientChunksOption === true;
|
|
79
|
+
const clientChunkCtx: ClientChunkContext | undefined = useBuiltInClientChunks
|
|
80
|
+
? { fallbackRefs: new Set<string>() }
|
|
81
|
+
: undefined;
|
|
82
|
+
const clientChunks = resolveClientChunks(clientChunksOption, clientChunkCtx);
|
|
65
83
|
debugConfig?.("rango(%s) setup start", preset);
|
|
66
84
|
|
|
67
85
|
const plugins: PluginOption[] = [];
|
|
@@ -93,24 +111,28 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
93
111
|
const pkg = getPublishedPackageName();
|
|
94
112
|
const nested = (spec: string) => `${pkg} > ${spec}`;
|
|
95
113
|
|
|
96
|
-
// Mutable ref for
|
|
97
|
-
//
|
|
98
|
-
//
|
|
99
|
-
|
|
114
|
+
// Mutable ref for the served entry path (node/vercel presets only). Populated
|
|
115
|
+
// by the auto-discover config() hook using Vite's resolved root. `kind` selects
|
|
116
|
+
// the RSC entry template: "router" wraps a single createRouter() app in
|
|
117
|
+
// createRSCHandler; "host" wraps a createHostRouter() instance and serves it
|
|
118
|
+
// via hostRouter.match().
|
|
119
|
+
const routerRef: { path: string | undefined; kind: "router" | "host" } = {
|
|
120
|
+
path: undefined,
|
|
121
|
+
kind: "router",
|
|
122
|
+
};
|
|
123
|
+
// Explicit host-router entry (node/vercel `host` option), root-relative.
|
|
124
|
+
const explicitHost =
|
|
125
|
+
preset !== "cloudflare"
|
|
126
|
+
? (resolvedOptions as RangoNodeOptions | RangoVercelOptions).host
|
|
127
|
+
: undefined;
|
|
100
128
|
|
|
101
129
|
// Build-time prerendering is enabled for both presets.
|
|
102
130
|
// Collection runs in-process via the RSC dev environment runner during discoverRouters().
|
|
103
131
|
const prerenderEnabled = true;
|
|
104
132
|
|
|
105
133
|
if (preset === "cloudflare") {
|
|
106
|
-
// Cloudflare preset: configure entries for cloudflare worker setup
|
|
107
|
-
// Router is not needed here - worker.rsc.tsx imports it directly
|
|
108
|
-
|
|
109
|
-
// Dynamically import @vitejs/plugin-rsc
|
|
110
134
|
const { default: rsc } = await import("@vitejs/plugin-rsc");
|
|
111
135
|
|
|
112
|
-
// Only client and ssr entries - rsc entry is handled by cloudflare plugin
|
|
113
|
-
// Always use virtual modules for cloudflare preset
|
|
114
136
|
const finalEntries: { client: string; ssr: string } = {
|
|
115
137
|
client: VIRTUAL_IDS.browser,
|
|
116
138
|
ssr: VIRTUAL_IDS.ssr,
|
|
@@ -121,16 +143,21 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
121
143
|
enforce: "pre",
|
|
122
144
|
|
|
123
145
|
config() {
|
|
124
|
-
// Configure environments for cloudflare deployment
|
|
125
146
|
return {
|
|
126
|
-
// Exclude rsc-router modules from optimization to prevent module duplication
|
|
127
|
-
// This ensures the same Context instance is used by both browser entry and RSC proxy modules
|
|
128
147
|
optimizeDeps: {
|
|
129
148
|
exclude: excludeDeps,
|
|
130
|
-
|
|
149
|
+
rolldownOptions: sharedRolldownOptions,
|
|
131
150
|
},
|
|
132
151
|
resolve: {
|
|
133
152
|
alias: rangoAliases,
|
|
153
|
+
// Force a single React/React-DOM copy across all three RSC
|
|
154
|
+
// environments. RSC requires exactly one react/react-dom instance
|
|
155
|
+
// per environment runtime; consumer install topologies (pnpm
|
|
156
|
+
// strict layout, experimental React pins, third-party "use client"
|
|
157
|
+
// packages) can otherwise resolve duplicate copies, causing
|
|
158
|
+
// "Invalid hook call" / lost context. Child environments inherit
|
|
159
|
+
// this root dedupe, and Vite merges it with any consumer dedupe.
|
|
160
|
+
dedupe: ["react", "react-dom"],
|
|
134
161
|
},
|
|
135
162
|
build: {
|
|
136
163
|
rollupOptions: { onwarn },
|
|
@@ -139,30 +166,22 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
139
166
|
client: {
|
|
140
167
|
build: {
|
|
141
168
|
rollupOptions: {
|
|
169
|
+
onwarn,
|
|
142
170
|
output: {
|
|
143
171
|
manualChunks: getManualChunks,
|
|
144
172
|
},
|
|
145
173
|
},
|
|
146
174
|
},
|
|
147
|
-
// Pre-bundle rsc-html-stream to prevent discovery during first request
|
|
148
|
-
// Exclude rsc-router modules to ensure same Context instance
|
|
149
175
|
optimizeDeps: {
|
|
150
176
|
include: [nested("rsc-html-stream/client")],
|
|
151
177
|
exclude: excludeDeps,
|
|
152
|
-
|
|
178
|
+
rolldownOptions: sharedRolldownOptions,
|
|
153
179
|
},
|
|
154
180
|
},
|
|
155
181
|
ssr: {
|
|
156
|
-
// Build SSR inside RSC directory so wrangler can deploy self-contained dist/rsc
|
|
157
182
|
build: {
|
|
158
183
|
outDir: "./dist/rsc/ssr",
|
|
159
184
|
},
|
|
160
|
-
resolve: {
|
|
161
|
-
// Ensure single React instance in SSR child environment
|
|
162
|
-
dedupe: ["react", "react-dom"],
|
|
163
|
-
},
|
|
164
|
-
// Pre-bundle SSR entry and React for proper module linking with childEnvironments
|
|
165
|
-
// All deps must be listed to avoid late discovery triggering ERR_OUTDATED_OPTIMIZED_DEP
|
|
166
185
|
optimizeDeps: {
|
|
167
186
|
entries: [finalEntries.ssr],
|
|
168
187
|
include: [
|
|
@@ -178,14 +197,11 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
178
197
|
),
|
|
179
198
|
],
|
|
180
199
|
exclude: excludeDeps,
|
|
181
|
-
|
|
200
|
+
rolldownOptions: sharedRolldownOptions,
|
|
182
201
|
},
|
|
183
202
|
},
|
|
184
203
|
rsc: {
|
|
185
|
-
// RSC environment needs exclude list and esbuild options
|
|
186
|
-
// Exclude rsc-router modules to prevent createContext in RSC environment
|
|
187
204
|
optimizeDeps: {
|
|
188
|
-
// Pre-bundle all RSC deps to prevent late discovery triggering ERR_OUTDATED_OPTIMIZED_DEP
|
|
189
205
|
include: [
|
|
190
206
|
"react",
|
|
191
207
|
"react/jsx-runtime",
|
|
@@ -195,7 +211,7 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
195
211
|
),
|
|
196
212
|
],
|
|
197
213
|
exclude: excludeDeps,
|
|
198
|
-
|
|
214
|
+
rolldownOptions: sharedRolldownOptions,
|
|
199
215
|
},
|
|
200
216
|
},
|
|
201
217
|
},
|
|
@@ -216,26 +232,16 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
216
232
|
});
|
|
217
233
|
|
|
218
234
|
plugins.push(createVirtualEntriesPlugin(finalEntries));
|
|
219
|
-
|
|
220
|
-
// Dev-only: RSDW client patch for React Performance Tracks
|
|
221
235
|
plugins.push(performanceTracksPlugin());
|
|
222
|
-
|
|
223
|
-
// Add RSC plugin with cloudflare-specific options
|
|
224
|
-
// Note: loadModuleDevProxy should NOT be used with childEnvironments
|
|
225
|
-
// since SSR runs in workerd alongside RSC
|
|
226
236
|
plugins.push(
|
|
227
237
|
rsc({
|
|
228
238
|
entries: finalEntries,
|
|
229
239
|
serverHandler: false,
|
|
240
|
+
clientChunks,
|
|
230
241
|
}) as PluginOption,
|
|
231
242
|
);
|
|
232
|
-
|
|
233
|
-
// Deduplicate client references from third-party packages in dev mode.
|
|
234
|
-
// Prevents module duplication when server components import "use client"
|
|
235
|
-
// packages that are also imported directly by client components.
|
|
236
243
|
plugins.push(clientRefDedup());
|
|
237
244
|
} else {
|
|
238
|
-
// Auto-discover router using Vite's resolved root (not process.cwd())
|
|
239
245
|
plugins.push({
|
|
240
246
|
name: "@rangojs/router:auto-discover",
|
|
241
247
|
config(userConfig) {
|
|
@@ -243,33 +249,65 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
243
249
|
const root = userConfig.root
|
|
244
250
|
? resolve(process.cwd(), userConfig.root)
|
|
245
251
|
: process.cwd();
|
|
252
|
+
const toRootRelative = (abs: string) =>
|
|
253
|
+
(abs.startsWith(root)
|
|
254
|
+
? "./" + abs.slice(root.length + 1)
|
|
255
|
+
: abs
|
|
256
|
+
).replaceAll("\\", "/");
|
|
257
|
+
|
|
258
|
+
// 1. Explicit host entry wins: serve the createHostRouter() instance.
|
|
259
|
+
if (explicitHost) {
|
|
260
|
+
routerRef.path = explicitHost.replaceAll("\\", "/");
|
|
261
|
+
routerRef.kind = "host";
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
|
|
246
265
|
const candidates = findRouterFiles(root);
|
|
247
266
|
if (candidates.length === 1) {
|
|
248
|
-
|
|
249
|
-
routerRef.
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
267
|
+
routerRef.path = toRootRelative(candidates[0]);
|
|
268
|
+
routerRef.kind = "router";
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// 2. No single createRouter() entry. A multi-app host router has several
|
|
273
|
+
// createRouter() sub-apps and one createHostRouter() entry above them;
|
|
274
|
+
// auto-detect that entry instead of failing.
|
|
275
|
+
if (candidates.length !== 1) {
|
|
276
|
+
const hostCandidates = findHostRouterFiles(root);
|
|
277
|
+
if (hostCandidates.length === 1) {
|
|
278
|
+
routerRef.path = toRootRelative(hostCandidates[0]);
|
|
279
|
+
routerRef.kind = "host";
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
if (hostCandidates.length > 1) {
|
|
283
|
+
const list = hostCandidates
|
|
284
|
+
.map((f) => " - " + toRootRelative(f))
|
|
285
|
+
.join("\n");
|
|
286
|
+
throw new Error(
|
|
287
|
+
`[rango] Multiple host routers found:\n${list}\n\n` +
|
|
288
|
+
`Set the \`host\` option to the entry to serve, e.g. rango({ preset: "${preset}", host: "./src/worker.rsc.tsx" }).`,
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if (candidates.length > 1) {
|
|
253
294
|
const list = candidates
|
|
254
|
-
.map(
|
|
255
|
-
(f) =>
|
|
256
|
-
" - " + (f.startsWith(root) ? f.slice(root.length + 1) : f),
|
|
257
|
-
)
|
|
295
|
+
.map((f) => " - " + toRootRelative(f))
|
|
258
296
|
.join("\n");
|
|
259
|
-
throw new Error(
|
|
297
|
+
throw new Error(
|
|
298
|
+
`[rango] Multiple routers found:\n${list}\n\n` +
|
|
299
|
+
`If this is a multi-app host router, export a createHostRouter() instance and set the \`host\` option (e.g. rango({ preset: "${preset}", host: "./src/worker.rsc.tsx" })), or use preset: "cloudflare" where you own the worker entry.`,
|
|
300
|
+
);
|
|
260
301
|
}
|
|
261
|
-
// 0 found: routerRef.path stays undefined, warn at startup via discovery plugin
|
|
262
302
|
},
|
|
263
303
|
});
|
|
264
304
|
|
|
265
|
-
// Always use virtual entries for client, ssr, and rsc
|
|
266
305
|
const finalEntries = {
|
|
267
306
|
client: VIRTUAL_IDS.browser,
|
|
268
307
|
ssr: VIRTUAL_IDS.ssr,
|
|
269
308
|
rsc: VIRTUAL_IDS.rsc,
|
|
270
309
|
};
|
|
271
310
|
|
|
272
|
-
// Dynamically import @vitejs/plugin-rsc
|
|
273
311
|
const { default: rsc } = await import("@vitejs/plugin-rsc");
|
|
274
312
|
|
|
275
313
|
let hasWarnedDuplicate = false;
|
|
@@ -278,22 +316,50 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
278
316
|
name: "@rangojs/router:rsc-integration",
|
|
279
317
|
enforce: "pre",
|
|
280
318
|
|
|
281
|
-
config() {
|
|
319
|
+
config(_userConfig, configEnv) {
|
|
320
|
+
// Fold NODE_ENV for the vercel preset's build. The cloudflare plugin
|
|
321
|
+
// does this automatically and node apps do it themselves; vercel has no
|
|
322
|
+
// platform plugin, so without this React's CJS dev branch survives and
|
|
323
|
+
// doubles the SSR/RSC bundle (Bundle Hygiene rule #2). Only the exact
|
|
324
|
+
// `process.env.NODE_ENV` token is replaced.
|
|
325
|
+
const vercelDefine =
|
|
326
|
+
preset === "vercel" && configEnv.command === "build"
|
|
327
|
+
? { "process.env.NODE_ENV": JSON.stringify("production") }
|
|
328
|
+
: undefined;
|
|
329
|
+
// The vercel preset's deployed function has no node_modules, so the
|
|
330
|
+
// server bundles must be fully self-contained. Bundle every dependency
|
|
331
|
+
// into the rsc + ssr builds instead of externalizing them (the node
|
|
332
|
+
// default, which only works because `vite preview` runs where
|
|
333
|
+
// node_modules exists). node: builtins stay external automatically.
|
|
334
|
+
const vercelServerEnv =
|
|
335
|
+
preset === "vercel"
|
|
336
|
+
? { resolve: { noExternal: true as const } }
|
|
337
|
+
: undefined;
|
|
282
338
|
return {
|
|
339
|
+
...(vercelDefine ? { define: vercelDefine } : {}),
|
|
283
340
|
optimizeDeps: {
|
|
284
341
|
exclude: excludeDeps,
|
|
285
|
-
|
|
342
|
+
rolldownOptions: sharedRolldownOptions,
|
|
286
343
|
},
|
|
287
344
|
build: {
|
|
288
345
|
rollupOptions: { onwarn },
|
|
289
346
|
},
|
|
290
347
|
resolve: {
|
|
291
348
|
alias: rangoAliases,
|
|
349
|
+
// Force a single React/React-DOM copy across all three RSC
|
|
350
|
+
// environments. RSC requires exactly one react/react-dom instance
|
|
351
|
+
// per environment runtime; consumer install topologies (pnpm
|
|
352
|
+
// strict layout, experimental React pins, third-party "use client"
|
|
353
|
+
// packages) can otherwise resolve duplicate copies, causing
|
|
354
|
+
// "Invalid hook call" / lost context. Child environments inherit
|
|
355
|
+
// this root dedupe, and Vite merges it with any consumer dedupe.
|
|
356
|
+
dedupe: ["react", "react-dom"],
|
|
292
357
|
},
|
|
293
358
|
environments: {
|
|
294
359
|
client: {
|
|
295
360
|
build: {
|
|
296
361
|
rollupOptions: {
|
|
362
|
+
onwarn,
|
|
297
363
|
output: {
|
|
298
364
|
manualChunks: getManualChunks,
|
|
299
365
|
},
|
|
@@ -308,11 +374,12 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
308
374
|
nested("rsc-html-stream/client"),
|
|
309
375
|
],
|
|
310
376
|
exclude: excludeDeps,
|
|
311
|
-
|
|
377
|
+
rolldownOptions: sharedRolldownOptions,
|
|
312
378
|
entries: [VIRTUAL_IDS.browser],
|
|
313
379
|
},
|
|
314
380
|
},
|
|
315
381
|
ssr: {
|
|
382
|
+
...(vercelServerEnv ?? {}),
|
|
316
383
|
optimizeDeps: {
|
|
317
384
|
entries: [VIRTUAL_IDS.ssr],
|
|
318
385
|
include: [
|
|
@@ -327,10 +394,11 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
327
394
|
),
|
|
328
395
|
],
|
|
329
396
|
exclude: excludeDeps,
|
|
330
|
-
|
|
397
|
+
rolldownOptions: sharedRolldownOptions,
|
|
331
398
|
},
|
|
332
399
|
},
|
|
333
400
|
rsc: {
|
|
401
|
+
...(vercelServerEnv ?? {}),
|
|
334
402
|
optimizeDeps: {
|
|
335
403
|
entries: [VIRTUAL_IDS.rsc],
|
|
336
404
|
include: [
|
|
@@ -341,7 +409,7 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
341
409
|
"@vitejs/plugin-rsc/vendor/react-server-dom/server.edge",
|
|
342
410
|
),
|
|
343
411
|
],
|
|
344
|
-
|
|
412
|
+
rolldownOptions: sharedRolldownOptions,
|
|
345
413
|
},
|
|
346
414
|
},
|
|
347
415
|
},
|
|
@@ -356,7 +424,11 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
356
424
|
? "preview"
|
|
357
425
|
: "dev"
|
|
358
426
|
: "build";
|
|
359
|
-
printBanner(
|
|
427
|
+
printBanner(
|
|
428
|
+
mode,
|
|
429
|
+
preset === "vercel" ? "vercel" : "node",
|
|
430
|
+
rangoVersion,
|
|
431
|
+
);
|
|
360
432
|
}
|
|
361
433
|
|
|
362
434
|
const rscMinimalCount = config.plugins.filter(
|
|
@@ -366,42 +438,24 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
366
438
|
if (rscMinimalCount > 1 && !hasWarnedDuplicate) {
|
|
367
439
|
hasWarnedDuplicate = true;
|
|
368
440
|
console.warn(
|
|
369
|
-
"[
|
|
441
|
+
"[rango] Duplicate @vitejs/plugin-rsc detected. " +
|
|
370
442
|
"Remove rsc() from your vite config — rango() includes it automatically.",
|
|
371
443
|
);
|
|
372
444
|
}
|
|
373
445
|
},
|
|
374
446
|
});
|
|
375
447
|
|
|
376
|
-
// Add virtual entries plugin (RSC entry generated lazily from routerRef)
|
|
377
448
|
plugins.push(createVirtualEntriesPlugin(finalEntries, routerRef));
|
|
378
|
-
|
|
379
|
-
// Dev-only: RSDW client patch for React Performance Tracks
|
|
380
449
|
plugins.push(performanceTracksPlugin());
|
|
381
|
-
|
|
382
450
|
plugins.push(
|
|
383
451
|
rsc({
|
|
384
452
|
entries: finalEntries,
|
|
453
|
+
clientChunks,
|
|
385
454
|
}) as PluginOption,
|
|
386
455
|
);
|
|
387
|
-
|
|
388
|
-
// Deduplicate client references from third-party packages in dev mode.
|
|
389
|
-
// Prevents module duplication when server components import "use client"
|
|
390
|
-
// packages that are also imported directly by client components.
|
|
391
456
|
plugins.push(clientRefDedup());
|
|
392
457
|
}
|
|
393
458
|
|
|
394
|
-
// Fix HMR for "use client" components.
|
|
395
|
-
//
|
|
396
|
-
// @vitejs/plugin-rsc's hotUpdate returns undefined for "use client" files
|
|
397
|
-
// in the RSC environment. Vite then tries to propagate through the RSC
|
|
398
|
-
// module graph, but the proxy module has no import.meta.hot.accept()
|
|
399
|
-
// boundary, causing a full page reload. The client env would handle it
|
|
400
|
-
// fine via React Refresh, but the RSC env's full-reload arrives first.
|
|
401
|
-
//
|
|
402
|
-
// Fix: in the RSC env, return [] for "use client" files to signal
|
|
403
|
-
// "handled, nothing to propagate". The client env is left alone so
|
|
404
|
-
// React Refresh processes the update normally.
|
|
405
459
|
plugins.push({
|
|
406
460
|
name: "@rangojs/router:client-component-hmr",
|
|
407
461
|
hotUpdate(ctx) {
|
|
@@ -425,68 +479,47 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
425
479
|
trimmed.startsWith('"use client"') ||
|
|
426
480
|
trimmed.startsWith("'use client'")
|
|
427
481
|
) {
|
|
428
|
-
// Consume the update in RSC/SSR envs. The proxy module was already
|
|
429
|
-
// re-transformed by the RSC plugin's hotUpdate. Without this, Vite
|
|
430
|
-
// tries to propagate through the RSC/SSR module graph where the proxy
|
|
431
|
-
// has no import.meta.hot.accept() boundary, triggering a full reload.
|
|
432
|
-
// The actual component update is handled by React Refresh in the
|
|
433
|
-
// client environment.
|
|
434
482
|
return [];
|
|
435
483
|
}
|
|
436
|
-
} catch {
|
|
437
|
-
// File deleted/moved during HMR, let default handling proceed
|
|
438
|
-
}
|
|
484
|
+
} catch {}
|
|
439
485
|
},
|
|
440
486
|
});
|
|
441
487
|
|
|
442
488
|
plugins.push(exposeActionId());
|
|
443
|
-
|
|
444
|
-
// "use cache" directive transform (enforce: "post"):
|
|
445
|
-
// Wraps exports with registerCachedFunction() for function-level caching.
|
|
446
489
|
plugins.push(useCacheTransform());
|
|
447
|
-
|
|
448
|
-
// Consolidated plugin for create* ID injection (enforce: "post"):
|
|
449
|
-
// loaders, handles, location state, and prerender handlers.
|
|
450
490
|
plugins.push(exposeInternalIds());
|
|
451
|
-
|
|
452
|
-
// Router ID injection runs at normal priority (no enforce) to avoid
|
|
453
|
-
// changing Vite's dep optimization timing.
|
|
454
491
|
plugins.push(exposeRouterId());
|
|
455
|
-
|
|
456
|
-
// Add version virtual module plugin for cache invalidation
|
|
457
492
|
plugins.push(createVersionPlugin());
|
|
458
493
|
|
|
459
|
-
// Entry path for discovery: user-specified value (if any) or undefined.
|
|
460
|
-
// Auto-discovered path is passed separately via routerRef.
|
|
461
|
-
// Cloudflare preset: deferred to configResolved (read from resolved Vite env config).
|
|
462
494
|
const discoveryEntryPath =
|
|
463
495
|
preset !== "cloudflare" ? routerRef.path : undefined;
|
|
464
|
-
// Ref for deferred auto-discovery (node preset only, undefined for cloudflare)
|
|
465
496
|
const discoveryRouterRef = preset !== "cloudflare" ? routerRef : undefined;
|
|
466
497
|
|
|
467
|
-
// Version injector: auto-injects VERSION and routes-manifest into the RSC entry.
|
|
468
|
-
// For cloudflare preset, the entry is resolved lazily in configResolved.
|
|
469
|
-
// For node preset, the virtual entry already includes these imports.
|
|
470
498
|
if (preset === "cloudflare") {
|
|
471
499
|
plugins.push(createVersionInjectorPlugin(undefined));
|
|
472
500
|
}
|
|
473
501
|
|
|
474
|
-
// Transform CJS vendor files to ESM for browser compatibility
|
|
475
|
-
// optimizeDeps.include doesn't work because the file is loaded after initial optimization
|
|
476
502
|
plugins.push(createCjsToEsmPlugin());
|
|
477
|
-
|
|
478
|
-
// Router discovery plugin for build-time manifest generation.
|
|
479
|
-
// For cloudflare, the entry is resolved lazily in configResolved from the RSC environment.
|
|
480
|
-
// For node, discoveryRouterRef provides the auto-discovered path when not user-specified.
|
|
481
503
|
plugins.push(
|
|
482
504
|
createRouterDiscoveryPlugin(discoveryEntryPath, {
|
|
483
505
|
routerPathRef: discoveryRouterRef,
|
|
484
506
|
enableBuildPrerender: prerenderEnabled,
|
|
485
507
|
buildEnv: options?.buildEnv,
|
|
486
508
|
preset,
|
|
509
|
+
discovery: options?.discovery,
|
|
510
|
+
clientChunkCtx,
|
|
487
511
|
}),
|
|
488
512
|
);
|
|
489
513
|
|
|
514
|
+
// Vercel preset: assemble .vercel/output from dist/ after the build. Pushed
|
|
515
|
+
// last so its (ssr-gated) closeBundle runs after the discovery plugin's
|
|
516
|
+
// rsc-env postprocess and after every environment has been written.
|
|
517
|
+
if (preset === "vercel") {
|
|
518
|
+
plugins.push(
|
|
519
|
+
createVercelOutputPlugin(resolvedOptions as RangoVercelOptions),
|
|
520
|
+
);
|
|
521
|
+
}
|
|
522
|
+
|
|
490
523
|
debugConfig?.(
|
|
491
524
|
"rango(%s) setup done: %d plugin(s) (%sms)",
|
|
492
525
|
preset,
|