@rangojs/router 0.22.1 → 0.23.0
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/dist/bin/rango.js +8 -3
- package/dist/testing/vitest.js +31 -1
- package/dist/types/browser/defer.d.ts +48 -0
- package/dist/types/browser/document-revealed.d.ts +17 -0
- package/dist/types/browser/event-controller.d.ts +7 -1
- package/dist/types/browser/navigation-transaction.d.ts +21 -7
- package/dist/types/browser/partial-update.d.ts +34 -5
- package/dist/types/browser/react/NavigationProvider.d.ts +13 -3
- package/dist/types/browser/react/filter-segment-order.d.ts +7 -0
- package/dist/types/browser/response-adapter.d.ts +7 -0
- package/dist/types/browser/types.d.ts +19 -9
- package/dist/types/browser/validate-redirect-origin.d.ts +11 -0
- package/dist/types/build/generate-route-types.d.ts +1 -1
- package/dist/types/build/route-types/router-processing.d.ts +1 -1
- package/dist/types/build/route-types/scan-filter.d.ts +16 -2
- package/dist/types/cache/cf/cf-cache-store.d.ts +16 -1
- package/dist/types/cache/cf/cf-cache-types.d.ts +23 -2
- package/dist/types/client-urls/client-urls.d.ts +1 -1
- package/dist/types/client-urls/hoisted-revalidate.d.ts +13 -0
- package/dist/types/client-urls/navigation.d.ts +0 -37
- package/dist/types/client-urls/revalidate-registry.d.ts +4 -0
- package/dist/types/client-urls/server-projection.d.ts +29 -1
- package/dist/types/client-urls/types.d.ts +34 -69
- package/dist/types/client.d.ts +0 -1
- package/dist/types/errors.d.ts +5 -0
- package/dist/types/handles/deferred-resolution.d.ts +2 -1
- package/dist/types/handles/pushed-by.d.ts +23 -0
- package/dist/types/loader-store.d.ts +8 -0
- package/dist/types/prefetch-markers.d.ts +11 -0
- package/dist/types/route-definition/helpers-types.d.ts +27 -0
- package/dist/types/router/is-action.d.ts +2 -1
- package/dist/types/router/segment-resolution/loader-mask.d.ts +3 -2
- package/dist/types/router/segment-resolution/prefetch-deferral.d.ts +241 -0
- package/dist/types/server/context.d.ts +21 -1
- package/dist/types/server/handle-store.d.ts +9 -1
- package/dist/types/server/request-context.d.ts +14 -1
- package/dist/types/server.d.ts +1 -0
- package/dist/types/testing/flight.entry.d.ts +1 -1
- package/dist/types/testing/index.d.ts +3 -3
- package/dist/types/testing/internal/action-id.d.ts +10 -1
- package/dist/types/testing/internal/client-urls-projection.d.ts +16 -0
- package/dist/types/testing/internal/test-action.d.ts +8 -0
- package/dist/types/testing/run-loader.d.ts +2 -1
- package/dist/types/testing/run-revalidate.d.ts +74 -0
- package/dist/types/testing/run-transition-when.d.ts +2 -3
- package/dist/types/testing/serve-shell-request.d.ts +38 -0
- package/dist/types/testing/vitest.d.ts +11 -0
- package/dist/types/types/boundaries.d.ts +9 -0
- package/dist/types/types/handler-context.d.ts +14 -0
- package/dist/types/types/loader-types.d.ts +30 -0
- package/dist/types/types/segments.d.ts +21 -4
- package/dist/types/urls/path-helper-types.d.ts +25 -4
- package/dist/types/urls/type-extraction.d.ts +6 -2
- package/dist/types/vite/discovery/discover-routers.d.ts +9 -0
- package/dist/types/vite/discovery/state.d.ts +11 -4
- package/dist/types/vite/plugins/client-urls-revalidate-hoist.d.ts +54 -0
- package/dist/types/vite/plugins/hoist/literal.d.ts +83 -0
- package/dist/types/vite/plugins/hoist/scope.d.ts +40 -0
- package/dist/types/vite/plugins/hoist/source.d.ts +41 -0
- package/dist/types/vite/plugins/transition-when-hoist.d.ts +8 -11
- package/dist/types/vite/router-discovery.d.ts +10 -0
- package/dist/vite/index.js +842 -308
- package/package.json +1 -1
- package/skills/caching/SKILL.md +42 -5
- package/skills/catalog.json +2 -2
- package/skills/client-urls/SKILL.md +113 -24
- package/skills/cloudflare/SKILL.md +14 -9
- package/skills/hooks/SKILL.md +11 -3
- package/skills/links/SKILL.md +24 -0
- package/skills/loader/SKILL.md +192 -1
- package/skills/migrate-nextjs/SKILL.md +2 -2
- package/skills/migrate-react-router/SKILL.md +10 -7
- package/skills/migrate-react-router/data-and-actions.md +1 -1
- package/skills/ppr/SKILL.md +13 -0
- package/skills/prerender/SKILL.md +22 -8
- package/skills/rango/SKILL.md +12 -6
- package/skills/route/SKILL.md +139 -0
- package/skills/testing/SKILL.md +3 -2
- package/skills/testing/client-components.md +1 -1
- package/skills/testing/predicates.md +67 -32
- package/skills/testing/serve-shell-request.md +88 -18
- package/skills/testing/setup.md +2 -2
- package/skills/typesafety/route-types.md +2 -2
- package/skills/view-transitions/SKILL.md +26 -0
- package/src/browser/defer.ts +82 -0
- package/src/browser/document-revealed.ts +52 -0
- package/src/browser/event-controller.ts +43 -32
- package/src/browser/navigation-bridge.ts +64 -14
- package/src/browser/navigation-client.ts +48 -36
- package/src/browser/navigation-store.ts +13 -0
- package/src/browser/navigation-transaction.ts +25 -8
- package/src/browser/partial-update.ts +528 -135
- package/src/browser/prefetch/fetch.ts +2 -1
- package/src/browser/react/NavigationProvider.tsx +47 -28
- package/src/browser/react/filter-segment-order.ts +13 -2
- package/src/browser/response-adapter.ts +20 -0
- package/src/browser/rsc-router.tsx +17 -45
- package/src/browser/server-action-bridge.ts +19 -63
- package/src/browser/types.ts +19 -9
- package/src/browser/validate-redirect-origin.ts +16 -0
- package/src/build/generate-route-types.ts +1 -0
- package/src/build/route-types/router-processing.ts +3 -6
- package/src/build/route-types/scan-filter.ts +37 -10
- package/src/cache/cf/cf-cache-store.ts +59 -21
- package/src/cache/cf/cf-cache-types.ts +24 -2
- package/src/cache/document-cache.ts +22 -1
- package/src/client-urls/client-urls.ts +22 -6
- package/src/client-urls/hoisted-revalidate.ts +25 -0
- package/src/client-urls/navigation.ts +0 -96
- package/src/client-urls/revalidate-registry.ts +30 -0
- package/src/client-urls/server-projection.ts +151 -65
- package/src/client-urls/types.ts +39 -71
- package/src/client.tsx +9 -5
- package/src/errors.ts +15 -0
- package/src/handles/deferred-resolution.ts +28 -5
- package/src/handles/pushed-by.ts +122 -0
- package/src/loader-store.ts +18 -7
- package/src/prefetch-markers.ts +13 -0
- package/src/route-content-wrapper.tsx +18 -4
- package/src/route-definition/dsl-helpers.ts +27 -4
- package/src/route-definition/helpers-types.ts +27 -1
- package/src/router/intercept-resolution.ts +6 -4
- package/src/router/is-action.ts +2 -1
- package/src/router/loader-resolution.ts +83 -4
- package/src/router/match-api.ts +36 -1
- package/src/router/match-middleware/background-revalidation.ts +11 -1
- package/src/router/match-middleware/cache-lookup.ts +29 -6
- package/src/router/match-middleware/cache-store.ts +17 -1
- package/src/router/match-result.ts +14 -2
- package/src/router/navigation-snapshot.ts +2 -1
- package/src/router/segment-resolution/fresh.ts +22 -18
- package/src/router/segment-resolution/loader-cache.ts +2 -1
- package/src/router/segment-resolution/loader-mask.ts +5 -3
- package/src/router/segment-resolution/prefetch-deferral.ts +543 -0
- package/src/router/segment-resolution/revalidation.ts +169 -60
- package/src/rsc/rsc-rendering.ts +50 -7
- package/src/rsc/shell-capture.ts +2 -1
- package/src/segment-loader-promise.ts +23 -20
- package/src/segment-system.tsx +60 -26
- package/src/server/context.ts +39 -5
- package/src/server/handle-store.ts +104 -8
- package/src/server/request-context.ts +21 -1
- package/src/server.ts +4 -0
- package/src/testing/action-form.ts +2 -11
- package/src/testing/e2e/page-helpers.ts +3 -1
- package/src/testing/flight.entry.ts +1 -0
- package/src/testing/index.ts +6 -3
- package/src/testing/internal/action-id.ts +16 -1
- package/src/testing/internal/client-urls-projection.ts +70 -0
- package/src/testing/internal/test-action.ts +25 -0
- package/src/testing/run-loader.ts +2 -1
- package/src/testing/run-revalidate.ts +142 -0
- package/src/testing/run-transition-when.ts +7 -8
- package/src/testing/serve-shell-request.ts +116 -6
- package/src/testing/vitest.ts +67 -1
- package/src/types/boundaries.ts +12 -0
- package/src/types/handler-context.ts +14 -0
- package/src/types/loader-types.ts +30 -0
- package/src/types/segments.ts +26 -4
- package/src/urls/path-helper-types.ts +27 -5
- package/src/urls/type-extraction.ts +30 -10
- package/src/use-loader.tsx +18 -13
- package/src/vite/discovery/client-urls-projection.ts +20 -21
- package/src/vite/discovery/discover-routers.ts +94 -26
- package/src/vite/discovery/state.ts +20 -4
- package/src/vite/discovery/virtual-module-codegen.ts +22 -17
- package/src/vite/plugins/client-urls-revalidate-hoist.ts +564 -0
- package/src/vite/plugins/hoist/literal.ts +417 -0
- package/src/vite/plugins/hoist/scope.ts +370 -0
- package/src/vite/plugins/hoist/source.ts +84 -0
- package/src/vite/plugins/transition-when-hoist.ts +113 -779
- package/src/vite/rango.ts +2 -0
- package/src/vite/router-discovery.ts +93 -32
- package/dist/types/client-urls/revalidate-chain.d.ts +0 -33
- package/dist/types/client-urls/revalidation-protocol.d.ts +0 -25
- package/dist/types/testing/run-client-revalidate.d.ts +0 -43
- package/src/client-urls/revalidate-chain.ts +0 -83
- package/src/client-urls/revalidation-protocol.ts +0 -56
- package/src/testing/run-client-revalidate.ts +0 -92
package/dist/vite/index.js
CHANGED
|
@@ -119,10 +119,10 @@ __export(client_ref_hashing_exports, {
|
|
|
119
119
|
hashRefKey: () => hashRefKey,
|
|
120
120
|
transformClientRefs: () => transformClientRefs
|
|
121
121
|
});
|
|
122
|
-
import { relative as
|
|
123
|
-
import { createHash as
|
|
122
|
+
import { relative as relative3 } from "node:path";
|
|
123
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
124
124
|
function hashRefKey(relativeId) {
|
|
125
|
-
return
|
|
125
|
+
return createHash3("sha256").update(relativeId).digest("hex").slice(0, 12);
|
|
126
126
|
}
|
|
127
127
|
function computeProductionHash(projectRoot, refKey) {
|
|
128
128
|
let toHash;
|
|
@@ -132,10 +132,10 @@ function computeProductionHash(projectRoot, refKey) {
|
|
|
132
132
|
const absPath = decodeURIComponent(
|
|
133
133
|
refKey.slice(CLIENT_IN_SERVER_PKG_PROXY_PREFIX.length)
|
|
134
134
|
);
|
|
135
|
-
toHash =
|
|
135
|
+
toHash = relative3(projectRoot, absPath).replaceAll("\\", "/");
|
|
136
136
|
} else if (refKey.startsWith(FS_PREFIX)) {
|
|
137
137
|
const absPath = refKey.slice(FS_PREFIX.length - 1);
|
|
138
|
-
toHash =
|
|
138
|
+
toHash = relative3(projectRoot, absPath).replaceAll("\\", "/");
|
|
139
139
|
} else if (refKey.startsWith("/")) {
|
|
140
140
|
toHash = refKey.slice(1);
|
|
141
141
|
} else {
|
|
@@ -733,6 +733,15 @@ var init_segment_fragments = __esm({
|
|
|
733
733
|
}
|
|
734
734
|
});
|
|
735
735
|
|
|
736
|
+
// src/prefetch-markers.ts
|
|
737
|
+
var PREFETCH_HEADER;
|
|
738
|
+
var init_prefetch_markers = __esm({
|
|
739
|
+
"src/prefetch-markers.ts"() {
|
|
740
|
+
"use strict";
|
|
741
|
+
PREFETCH_HEADER = "X-Rango-Prefetch";
|
|
742
|
+
}
|
|
743
|
+
});
|
|
744
|
+
|
|
736
745
|
// src/browser/prefetch/fetch.ts
|
|
737
746
|
function setPrefetchDecoder(fn) {
|
|
738
747
|
decoder = fn;
|
|
@@ -826,7 +835,7 @@ function executePrefetchFetch(wildcardKey, sourceKey, fetchUrl, forceSourceScope
|
|
|
826
835
|
headers: {
|
|
827
836
|
"X-Rango-State": rangoState,
|
|
828
837
|
"X-RSC-Router-Client-Path": window.location.href,
|
|
829
|
-
|
|
838
|
+
[PREFETCH_HEADER]: "1",
|
|
830
839
|
...isFragmentPassthroughEnabled() && {
|
|
831
840
|
[SEGMENT_FRAGMENT_CAPABILITY_HEADER]: "1"
|
|
832
841
|
}
|
|
@@ -1006,6 +1015,7 @@ var init_fetch = __esm({
|
|
|
1006
1015
|
init_logging();
|
|
1007
1016
|
init_response_adapter();
|
|
1008
1017
|
init_segment_fragments();
|
|
1018
|
+
init_prefetch_markers();
|
|
1009
1019
|
decoder = null;
|
|
1010
1020
|
PREFETCH_FETCH_TIMEOUT_MS = 3e4;
|
|
1011
1021
|
}
|
|
@@ -1633,10 +1643,10 @@ import path4 from "node:path";
|
|
|
1633
1643
|
function isDirectivePrologueStatement(node) {
|
|
1634
1644
|
return node?.type === "ExpressionStatement" && typeof node.directive === "string";
|
|
1635
1645
|
}
|
|
1636
|
-
function findImportInsertionPos(code,
|
|
1646
|
+
function findImportInsertionPos(code, parseAst9) {
|
|
1637
1647
|
let program;
|
|
1638
1648
|
try {
|
|
1639
|
-
program =
|
|
1649
|
+
program = parseAst9(code, { lang: "tsx" });
|
|
1640
1650
|
} catch {
|
|
1641
1651
|
return 0;
|
|
1642
1652
|
}
|
|
@@ -1673,10 +1683,10 @@ function walkNode(node, parent, ancestors, enter) {
|
|
|
1673
1683
|
}
|
|
1674
1684
|
ancestors.pop();
|
|
1675
1685
|
}
|
|
1676
|
-
function findHandlerCalls(code, fnName,
|
|
1686
|
+
function findHandlerCalls(code, fnName, parseAst9) {
|
|
1677
1687
|
let program;
|
|
1678
1688
|
try {
|
|
1679
|
-
program =
|
|
1689
|
+
program = parseAst9(code, { lang: "tsx" });
|
|
1680
1690
|
} catch {
|
|
1681
1691
|
return [];
|
|
1682
1692
|
}
|
|
@@ -1748,18 +1758,18 @@ function getImportedLocalNamesFromProgram(program, importedName) {
|
|
|
1748
1758
|
}
|
|
1749
1759
|
return localNames;
|
|
1750
1760
|
}
|
|
1751
|
-
function getImportedLocalNames(code, importedName,
|
|
1761
|
+
function getImportedLocalNames(code, importedName, parseAst9) {
|
|
1752
1762
|
try {
|
|
1753
|
-
const program =
|
|
1763
|
+
const program = parseAst9(code, { lang: "tsx" });
|
|
1754
1764
|
return getImportedLocalNamesFromProgram(program, importedName);
|
|
1755
1765
|
} catch {
|
|
1756
1766
|
return /* @__PURE__ */ new Set();
|
|
1757
1767
|
}
|
|
1758
1768
|
}
|
|
1759
|
-
function extractImportDeclarations(code,
|
|
1769
|
+
function extractImportDeclarations(code, parseAst9) {
|
|
1760
1770
|
let program;
|
|
1761
1771
|
try {
|
|
1762
|
-
program =
|
|
1772
|
+
program = parseAst9(code, { lang: "tsx" });
|
|
1763
1773
|
} catch {
|
|
1764
1774
|
return [];
|
|
1765
1775
|
}
|
|
@@ -1816,10 +1826,10 @@ function isSafeVariableDeclaration(node, handlerNames) {
|
|
|
1816
1826
|
(d) => isSafeDeclaratorInit(d.init) && !(d.init?.type === "CallExpression" && d.init.callee?.type === "Identifier" && handlerNames.has(d.init.callee.name))
|
|
1817
1827
|
);
|
|
1818
1828
|
}
|
|
1819
|
-
function extractModuleLevelDeclarations(code,
|
|
1829
|
+
function extractModuleLevelDeclarations(code, parseAst9, handlerNames) {
|
|
1820
1830
|
let program;
|
|
1821
1831
|
try {
|
|
1822
|
-
program =
|
|
1832
|
+
program = parseAst9(code, { lang: "tsx" });
|
|
1823
1833
|
} catch {
|
|
1824
1834
|
return [];
|
|
1825
1835
|
}
|
|
@@ -1850,17 +1860,17 @@ function extractModuleLevelDeclarations(code, parseAst8, handlerNames) {
|
|
|
1850
1860
|
}
|
|
1851
1861
|
return declarations;
|
|
1852
1862
|
}
|
|
1853
|
-
function transformInlineHandlers(fnName, virtualPrefix, s, code, filePath, virtualRegistry, moduleId,
|
|
1854
|
-
const sites = findHandlerCalls(code, fnName,
|
|
1863
|
+
function transformInlineHandlers(fnName, virtualPrefix, s, code, filePath, virtualRegistry, moduleId, parseAst9) {
|
|
1864
|
+
const sites = findHandlerCalls(code, fnName, parseAst9);
|
|
1855
1865
|
const inlineSites = sites.filter((site) => site.exportInfo === null);
|
|
1856
1866
|
if (inlineSites.length === 0) return false;
|
|
1857
|
-
const imports = extractImportDeclarations(code,
|
|
1858
|
-
const staticNames = getImportedLocalNames(code, "Static",
|
|
1859
|
-
const prerenderNames = getImportedLocalNames(code, "Prerender",
|
|
1867
|
+
const imports = extractImportDeclarations(code, parseAst9);
|
|
1868
|
+
const staticNames = getImportedLocalNames(code, "Static", parseAst9);
|
|
1869
|
+
const prerenderNames = getImportedLocalNames(code, "Prerender", parseAst9);
|
|
1860
1870
|
const handlerNames = /* @__PURE__ */ new Set([...staticNames, ...prerenderNames]);
|
|
1861
1871
|
const declarations = extractModuleLevelDeclarations(
|
|
1862
1872
|
code,
|
|
1863
|
-
|
|
1873
|
+
parseAst9,
|
|
1864
1874
|
handlerNames
|
|
1865
1875
|
);
|
|
1866
1876
|
const importStatements = [];
|
|
@@ -1883,7 +1893,7 @@ function transformInlineHandlers(fnName, virtualPrefix, s, code, filePath, virtu
|
|
|
1883
1893
|
}
|
|
1884
1894
|
if (importStatements.length > 0) {
|
|
1885
1895
|
const importBlock = importStatements.join("\n") + "\n";
|
|
1886
|
-
const insertionPos = findImportInsertionPos(code,
|
|
1896
|
+
const insertionPos = findImportInsertionPos(code, parseAst9);
|
|
1887
1897
|
if (insertionPos === 0) {
|
|
1888
1898
|
s.prepend(importBlock);
|
|
1889
1899
|
} else {
|
|
@@ -2433,6 +2443,9 @@ function compareStrings(a, b) {
|
|
|
2433
2443
|
// src/vite/discovery/state.ts
|
|
2434
2444
|
var VIRTUAL_ROUTES_MANIFEST_ID = "virtual:rsc-router/routes-manifest";
|
|
2435
2445
|
var VIRTUAL_LOADER_MANIFEST_ID = "virtual:rsc-router/loader-manifest";
|
|
2446
|
+
function canRefreshRuntimeDiscovery(state, hasMainRunner) {
|
|
2447
|
+
return state.perRouterManifests.length > 0 || hasMainRunner && !!state.lastDiscoveryError;
|
|
2448
|
+
}
|
|
2436
2449
|
function createDiscoveryState(entryPath, opts) {
|
|
2437
2450
|
return {
|
|
2438
2451
|
resolvedEntryPath: entryPath,
|
|
@@ -3201,18 +3214,18 @@ async function transformUseCache(code, id, options) {
|
|
|
3201
3214
|
return;
|
|
3202
3215
|
}
|
|
3203
3216
|
}
|
|
3204
|
-
const { hasDirective:
|
|
3217
|
+
const { hasDirective: hasDirective4, transformWrapExport, transformHoistInlineDirective } = rscTransforms;
|
|
3205
3218
|
let ast;
|
|
3206
3219
|
try {
|
|
3207
|
-
const { parseAst:
|
|
3208
|
-
ast =
|
|
3220
|
+
const { parseAst: parseAst9 } = await import("vite");
|
|
3221
|
+
ast = parseAst9(code, { lang: "tsx" });
|
|
3209
3222
|
} catch {
|
|
3210
3223
|
return;
|
|
3211
3224
|
}
|
|
3212
3225
|
stripNullDirectiveFields(ast);
|
|
3213
3226
|
const filePath = normalizePath(path5.relative(options.root, id));
|
|
3214
3227
|
const isLayoutOrTemplate = LAYOUT_TEMPLATE_PATTERN.test(id);
|
|
3215
|
-
if (
|
|
3228
|
+
if (hasDirective4(ast.body, "use cache")) {
|
|
3216
3229
|
return transformFileLevelUseCache(
|
|
3217
3230
|
code,
|
|
3218
3231
|
ast,
|
|
@@ -3221,7 +3234,7 @@ async function transformUseCache(code, id, options) {
|
|
|
3221
3234
|
options.isBuild,
|
|
3222
3235
|
isLayoutOrTemplate,
|
|
3223
3236
|
transformWrapExport,
|
|
3224
|
-
|
|
3237
|
+
hasDirective4
|
|
3225
3238
|
);
|
|
3226
3239
|
}
|
|
3227
3240
|
const functionResult = transformFunctionLevelUseCache(
|
|
@@ -3235,7 +3248,7 @@ async function transformUseCache(code, id, options) {
|
|
|
3235
3248
|
warnOnNearMissDirectives(ast, id, options.warn);
|
|
3236
3249
|
if (functionResult) return functionResult;
|
|
3237
3250
|
}
|
|
3238
|
-
async function transformFileLevelUseCache(code, ast, filePath, sourceId, isBuild, isLayoutOrTemplate, transformWrapExport,
|
|
3251
|
+
async function transformFileLevelUseCache(code, ast, filePath, sourceId, isBuild, isLayoutOrTemplate, transformWrapExport, hasDirective4) {
|
|
3239
3252
|
const unconfirmedExports = [];
|
|
3240
3253
|
const { exportNames, output } = transformWrapExport(code, ast, {
|
|
3241
3254
|
runtime: (value, name) => {
|
|
@@ -3247,7 +3260,7 @@ async function transformFileLevelUseCache(code, ast, filePath, sourceId, isBuild
|
|
|
3247
3260
|
if (name === "default" && isLayoutOrTemplate) return false;
|
|
3248
3261
|
if (name.startsWith("$$hoist_")) return false;
|
|
3249
3262
|
if (isHoistedServerReferenceRebind(meta.valueNode)) return false;
|
|
3250
|
-
if (functionHasUseServerDirective(meta.valueNode,
|
|
3263
|
+
if (functionHasUseServerDirective(meta.valueNode, hasDirective4)) {
|
|
3251
3264
|
return false;
|
|
3252
3265
|
}
|
|
3253
3266
|
if (meta.isFunction !== true) {
|
|
@@ -3264,8 +3277,8 @@ async function transformFileLevelUseCache(code, ast, filePath, sourceId, isBuild
|
|
|
3264
3277
|
);
|
|
3265
3278
|
}
|
|
3266
3279
|
if (exportNames.length === 0) {
|
|
3267
|
-
const { default:
|
|
3268
|
-
const s = new
|
|
3280
|
+
const { default: MagicString6 } = await import("magic-string");
|
|
3281
|
+
const s = new MagicString6(code);
|
|
3269
3282
|
const directive2 = findFileLevelDirective(ast);
|
|
3270
3283
|
if (directive2) {
|
|
3271
3284
|
s.overwrite(
|
|
@@ -3341,13 +3354,13 @@ function isHoistedServerReferenceRebind(valueNode) {
|
|
|
3341
3354
|
const first = valueNode.arguments[0];
|
|
3342
3355
|
return first !== void 0 && first.type === "Identifier" && first.name.startsWith("$$hoist_");
|
|
3343
3356
|
}
|
|
3344
|
-
function functionHasUseServerDirective(valueNode,
|
|
3357
|
+
function functionHasUseServerDirective(valueNode, hasDirective4) {
|
|
3345
3358
|
if (!valueNode || !("body" in valueNode)) return false;
|
|
3346
3359
|
const { body } = valueNode;
|
|
3347
3360
|
if (!body || Array.isArray(body) || body.type !== "BlockStatement") {
|
|
3348
3361
|
return false;
|
|
3349
3362
|
}
|
|
3350
|
-
return
|
|
3363
|
+
return hasDirective4(
|
|
3351
3364
|
body.body,
|
|
3352
3365
|
"use server"
|
|
3353
3366
|
);
|
|
@@ -3390,10 +3403,10 @@ function warnOnNearMissDirectives(ast, fileId, warn) {
|
|
|
3390
3403
|
}
|
|
3391
3404
|
|
|
3392
3405
|
// src/vite/plugins/transition-when-hoist.ts
|
|
3393
|
-
import { normalizePath as
|
|
3406
|
+
import { normalizePath as normalizePath3, parseAst as parseAst3 } from "vite";
|
|
3394
3407
|
import MagicString4 from "magic-string";
|
|
3395
3408
|
import { builtinModules } from "node:module";
|
|
3396
|
-
import {
|
|
3409
|
+
import { hasDirective as hasDirective2 } from "@vitejs/plugin-rsc/transforms";
|
|
3397
3410
|
|
|
3398
3411
|
// src/route-name.ts
|
|
3399
3412
|
var AUTO_GENERATED_ROUTE_PREFIX = "$path_";
|
|
@@ -3424,10 +3437,7 @@ function findTransitionWhenError(error) {
|
|
|
3424
3437
|
return void 0;
|
|
3425
3438
|
}
|
|
3426
3439
|
|
|
3427
|
-
// src/vite/plugins/
|
|
3428
|
-
var TRANSITION_WHEN_QUERY = "rango-when";
|
|
3429
|
-
var EXPORT_NAME = "__rango_when";
|
|
3430
|
-
var LOCAL_PREFIX = "__rango_when_";
|
|
3440
|
+
// src/vite/plugins/hoist/scope.ts
|
|
3431
3441
|
var Scope = class {
|
|
3432
3442
|
constructor(parent, isFunction, node) {
|
|
3433
3443
|
this.parent = parent;
|
|
@@ -3733,29 +3743,23 @@ function collectImports(program) {
|
|
|
3733
3743
|
}
|
|
3734
3744
|
return imports;
|
|
3735
3745
|
}
|
|
3736
|
-
|
|
3746
|
+
|
|
3747
|
+
// src/vite/plugins/hoist/literal.ts
|
|
3748
|
+
function directivePrologueEnd(program) {
|
|
3749
|
+
let end = 0;
|
|
3737
3750
|
for (const statement of program.body) {
|
|
3738
3751
|
if (statement.type !== "ExpressionStatement" || typeof statement.directive !== "string") {
|
|
3739
|
-
|
|
3752
|
+
break;
|
|
3740
3753
|
}
|
|
3741
|
-
|
|
3754
|
+
end = statement.end;
|
|
3742
3755
|
}
|
|
3743
|
-
return
|
|
3756
|
+
return end;
|
|
3744
3757
|
}
|
|
3745
|
-
function
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
if (code[i] === "\n") {
|
|
3750
|
-
line++;
|
|
3751
|
-
column = 1;
|
|
3752
|
-
} else {
|
|
3753
|
-
column++;
|
|
3754
|
-
}
|
|
3755
|
-
}
|
|
3756
|
-
return `${line}:${column}`;
|
|
3758
|
+
function parseLang(file) {
|
|
3759
|
+
if (/\.[cm]?ts$/.test(file)) return "ts";
|
|
3760
|
+
if (/\.[cm]?jsx?$/.test(file)) return "jsx";
|
|
3761
|
+
return "tsx";
|
|
3757
3762
|
}
|
|
3758
|
-
var ROUTER_SOURCE = "@rangojs/router";
|
|
3759
3763
|
var EXPRESSION_WRAPPERS = /* @__PURE__ */ new Set([
|
|
3760
3764
|
"TSAsExpression",
|
|
3761
3765
|
"TSSatisfiesExpression",
|
|
@@ -3773,51 +3777,50 @@ function isFunctionLiteral(node) {
|
|
|
3773
3777
|
function propertyKeyIs(prop, name) {
|
|
3774
3778
|
return prop?.type === "Property" && !prop.computed && (prop.key.type === "Identifier" && prop.key.name === name || prop.key.type === "Literal" && prop.key.value === name);
|
|
3775
3779
|
}
|
|
3776
|
-
function
|
|
3777
|
-
const
|
|
3780
|
+
function findHelperCalls(program, scopeOf, moduleScope, imports, spec) {
|
|
3781
|
+
const calls = [];
|
|
3778
3782
|
const helpers = /* @__PURE__ */ new Map();
|
|
3779
|
-
const
|
|
3780
|
-
const
|
|
3783
|
+
const sourceExport = (callee, scope) => {
|
|
3784
|
+
const sourceImport = (id) => {
|
|
3781
3785
|
if (id?.type !== "Identifier") return null;
|
|
3782
3786
|
if (scope.lookup(id.name) !== moduleScope) return null;
|
|
3783
3787
|
const binding = imports.get(id.name);
|
|
3784
|
-
return binding
|
|
3788
|
+
return binding && spec.sources.has(binding.source) && !binding.typeOnly ? binding : null;
|
|
3785
3789
|
};
|
|
3786
3790
|
if (callee.type === "Identifier") {
|
|
3787
|
-
const imported =
|
|
3791
|
+
const imported = sourceImport(callee)?.imported;
|
|
3788
3792
|
return imported && imported !== "*" && imported !== "default" ? imported : null;
|
|
3789
3793
|
}
|
|
3790
|
-
if (callee.type === "MemberExpression" && !callee.computed && callee.property.type === "Identifier" &&
|
|
3794
|
+
if (callee.type === "MemberExpression" && !callee.computed && callee.property.type === "Identifier" && sourceImport(callee.object)?.imported === "*") {
|
|
3791
3795
|
return callee.property.name;
|
|
3792
3796
|
}
|
|
3793
3797
|
return null;
|
|
3794
3798
|
};
|
|
3795
|
-
const
|
|
3799
|
+
const registerBuilderCallback = (callback) => {
|
|
3796
3800
|
const fnScope = scopeOf.get(callback);
|
|
3797
3801
|
let param = callback.params[0];
|
|
3798
3802
|
if (param?.type === "AssignmentPattern") param = param.left;
|
|
3799
3803
|
if (!fnScope || !param) return;
|
|
3800
|
-
const bindings = {
|
|
3801
|
-
transitions: /* @__PURE__ */ new Set(),
|
|
3802
|
-
objects: /* @__PURE__ */ new Set()
|
|
3803
|
-
};
|
|
3804
|
+
const bindings = { names: /* @__PURE__ */ new Set(), objects: /* @__PURE__ */ new Set() };
|
|
3804
3805
|
if (param.type === "Identifier") bindings.objects.add(param.name);
|
|
3805
3806
|
if (param.type === "ObjectPattern") {
|
|
3806
3807
|
for (const prop of param.properties) {
|
|
3807
|
-
if (!propertyKeyIs(prop,
|
|
3808
|
+
if (!propertyKeyIs(prop, spec.helper)) continue;
|
|
3808
3809
|
const target = prop.value.type === "AssignmentPattern" ? prop.value.left : prop.value;
|
|
3809
|
-
if (target.type === "Identifier") bindings.
|
|
3810
|
+
if (target.type === "Identifier") bindings.names.add(target.name);
|
|
3810
3811
|
}
|
|
3811
3812
|
}
|
|
3812
3813
|
helpers.set(fnScope, bindings);
|
|
3813
3814
|
};
|
|
3814
|
-
const
|
|
3815
|
-
if (
|
|
3815
|
+
const isHelper = (callee, scope) => {
|
|
3816
|
+
if (spec.directImport && sourceExport(callee, scope) === spec.helper) {
|
|
3817
|
+
return true;
|
|
3818
|
+
}
|
|
3816
3819
|
if (callee.type === "Identifier") {
|
|
3817
3820
|
const decl = scope.lookup(callee.name);
|
|
3818
|
-
return !!decl && !!helpers.get(decl)?.
|
|
3821
|
+
return !!decl && !!helpers.get(decl)?.names.has(callee.name);
|
|
3819
3822
|
}
|
|
3820
|
-
if (callee.type === "MemberExpression" && !callee.computed && callee.property.type === "Identifier" && callee.property.name ===
|
|
3823
|
+
if (callee.type === "MemberExpression" && !callee.computed && callee.property.type === "Identifier" && callee.property.name === spec.helper && callee.object.type === "Identifier") {
|
|
3821
3824
|
const decl = scope.lookup(callee.object.name);
|
|
3822
3825
|
return !!decl && !!helpers.get(decl)?.objects.has(callee.object.name);
|
|
3823
3826
|
}
|
|
@@ -3833,20 +3836,10 @@ function findWhenSites(program, scopeOf, moduleScope, imports) {
|
|
|
3833
3836
|
const own = scopeOf.get(node) ?? scope;
|
|
3834
3837
|
if (node.type === "CallExpression") {
|
|
3835
3838
|
const callback = node.arguments[0];
|
|
3836
|
-
if (isFunctionLiteral(callback) &&
|
|
3837
|
-
|
|
3838
|
-
}
|
|
3839
|
-
if (node.arguments[0]?.type === "ObjectExpression" && isRouterTransition(node.callee, own)) {
|
|
3840
|
-
for (const prop of node.arguments[0].properties) {
|
|
3841
|
-
if (propertyKeyIs(prop, "when")) {
|
|
3842
|
-
sites.push({
|
|
3843
|
-
prop,
|
|
3844
|
-
value: unwrapExpression(prop.value),
|
|
3845
|
-
scope: own
|
|
3846
|
-
});
|
|
3847
|
-
}
|
|
3848
|
-
}
|
|
3839
|
+
if (isFunctionLiteral(callback) && sourceExport(node.callee, own) === spec.builder) {
|
|
3840
|
+
registerBuilderCallback(callback);
|
|
3849
3841
|
}
|
|
3842
|
+
if (isHelper(node.callee, own)) calls.push({ call: node, scope: own });
|
|
3850
3843
|
}
|
|
3851
3844
|
for (const key of Object.keys(node)) {
|
|
3852
3845
|
if (key === "type" || key === "start" || key === "end") continue;
|
|
@@ -3854,27 +3847,21 @@ function findWhenSites(program, scopeOf, moduleScope, imports) {
|
|
|
3854
3847
|
}
|
|
3855
3848
|
};
|
|
3856
3849
|
visit(program.body, moduleScope);
|
|
3857
|
-
return
|
|
3850
|
+
return calls;
|
|
3858
3851
|
}
|
|
3859
|
-
|
|
3860
|
-
this: "`this` in an arrow is the enclosing server function's `this`.",
|
|
3861
|
-
arguments: "`arguments` in an arrow is the enclosing server function's `arguments`.",
|
|
3862
|
-
super: "`super` refers to the enclosing server object.",
|
|
3863
|
-
"new.target": "`new.target` in an arrow is the enclosing server function's."
|
|
3864
|
-
};
|
|
3865
|
-
function findLexicalCapture(literal, references, code) {
|
|
3852
|
+
function findLexicalCapture(literal, references, code, messages) {
|
|
3866
3853
|
const ownArguments = [];
|
|
3867
3854
|
let found = null;
|
|
3868
3855
|
const capture = (node, what) => {
|
|
3869
3856
|
found = {
|
|
3870
3857
|
node,
|
|
3871
|
-
detail: `${
|
|
3858
|
+
detail: `${messages.lexical[what]} ${messages.captureHint}`
|
|
3872
3859
|
};
|
|
3873
3860
|
};
|
|
3874
3861
|
const loads = (node, expression, why) => {
|
|
3875
3862
|
found = {
|
|
3876
3863
|
node,
|
|
3877
|
-
detail: `\`${expression}\` ${why}
|
|
3864
|
+
detail: `\`${expression}\` ${why} ${messages.loadsHint}`
|
|
3878
3865
|
};
|
|
3879
3866
|
};
|
|
3880
3867
|
const visit = (node, boundary) => {
|
|
@@ -3907,7 +3894,7 @@ function findLexicalCapture(literal, references, code) {
|
|
|
3907
3894
|
}
|
|
3908
3895
|
case "MetaProperty":
|
|
3909
3896
|
if (node.meta.name === "import") {
|
|
3910
|
-
loads(node, "import.meta",
|
|
3897
|
+
loads(node, "import.meta", messages.importMetaWhy);
|
|
3911
3898
|
} else if (!boundary) {
|
|
3912
3899
|
capture(node, "new.target");
|
|
3913
3900
|
}
|
|
@@ -3919,7 +3906,7 @@ function findLexicalCapture(literal, references, code) {
|
|
|
3919
3906
|
loads(
|
|
3920
3907
|
node,
|
|
3921
3908
|
node.computed ? "import.meta[...]" : `import.meta.${node.property.name}`,
|
|
3922
|
-
|
|
3909
|
+
messages.importMetaMemberWhy
|
|
3923
3910
|
);
|
|
3924
3911
|
return;
|
|
3925
3912
|
}
|
|
@@ -3928,7 +3915,7 @@ function findLexicalCapture(literal, references, code) {
|
|
|
3928
3915
|
loads(
|
|
3929
3916
|
node,
|
|
3930
3917
|
`import(${code.slice(node.source.start, node.source.end)})`,
|
|
3931
|
-
|
|
3918
|
+
messages.dynamicImportWhy
|
|
3932
3919
|
);
|
|
3933
3920
|
return;
|
|
3934
3921
|
}
|
|
@@ -3953,32 +3940,150 @@ function findLexicalCapture(literal, references, code) {
|
|
|
3953
3940
|
}
|
|
3954
3941
|
return null;
|
|
3955
3942
|
}
|
|
3943
|
+
function collectFreeReferences(literal, references, moduleScope, imports) {
|
|
3944
|
+
const used = /* @__PURE__ */ new Map();
|
|
3945
|
+
const bindings = [];
|
|
3946
|
+
const globals = [];
|
|
3947
|
+
for (const ref of references) {
|
|
3948
|
+
if (ref.node.start < literal.start || ref.node.end > literal.end) continue;
|
|
3949
|
+
const decl = ref.scope.lookup(ref.node.name);
|
|
3950
|
+
if (!decl) {
|
|
3951
|
+
if (!ref.typeOnly) globals.push(ref);
|
|
3952
|
+
continue;
|
|
3953
|
+
}
|
|
3954
|
+
if (decl.node.start >= literal.start && decl.node.end <= literal.end && decl !== moduleScope) {
|
|
3955
|
+
continue;
|
|
3956
|
+
}
|
|
3957
|
+
if (decl === moduleScope && imports.has(ref.node.name)) {
|
|
3958
|
+
const valueUse = !ref.typeOnly && !imports.get(ref.node.name).typeOnly;
|
|
3959
|
+
used.set(ref.node.name, (used.get(ref.node.name) ?? false) || valueUse);
|
|
3960
|
+
continue;
|
|
3961
|
+
}
|
|
3962
|
+
if (ref.typeOnly) continue;
|
|
3963
|
+
bindings.push(ref);
|
|
3964
|
+
}
|
|
3965
|
+
return { imports: used, bindings, globals };
|
|
3966
|
+
}
|
|
3967
|
+
async function emitImports(used, imports, checkValueImport) {
|
|
3968
|
+
const bySource = /* @__PURE__ */ new Map();
|
|
3969
|
+
for (const [local, valueUse] of used) {
|
|
3970
|
+
const binding = imports.get(local);
|
|
3971
|
+
if (valueUse) await checkValueImport(local, binding);
|
|
3972
|
+
const lines = bySource.get(binding.source) ?? [];
|
|
3973
|
+
const typePrefix = valueUse ? "" : "type ";
|
|
3974
|
+
if (binding.imported === "*") {
|
|
3975
|
+
lines.push(
|
|
3976
|
+
`import ${typePrefix}* as ${local} from ${JSON.stringify(binding.source)};`
|
|
3977
|
+
);
|
|
3978
|
+
} else if (binding.imported === "default") {
|
|
3979
|
+
lines.push(
|
|
3980
|
+
`import ${typePrefix}${local} from ${JSON.stringify(binding.source)};`
|
|
3981
|
+
);
|
|
3982
|
+
} else {
|
|
3983
|
+
const spec = binding.imported === local ? local : `${JSON.stringify(binding.imported)} as ${local}`;
|
|
3984
|
+
lines.push(
|
|
3985
|
+
`import ${typePrefix}{ ${spec} } from ${JSON.stringify(binding.source)};`
|
|
3986
|
+
);
|
|
3987
|
+
}
|
|
3988
|
+
bySource.set(binding.source, lines);
|
|
3989
|
+
}
|
|
3990
|
+
return [...bySource.values()].flat();
|
|
3991
|
+
}
|
|
3992
|
+
|
|
3993
|
+
// src/vite/plugins/hoist/source.ts
|
|
3994
|
+
import { readFile } from "node:fs/promises";
|
|
3995
|
+
import { normalizePath as normalizePath2 } from "vite";
|
|
3996
|
+
var SOURCE_FILE_RE = /\.[cm]?[jt]sx?$/;
|
|
3997
|
+
async function readSource(file) {
|
|
3998
|
+
try {
|
|
3999
|
+
return await readFile(file, "utf-8");
|
|
4000
|
+
} catch {
|
|
4001
|
+
return null;
|
|
4002
|
+
}
|
|
4003
|
+
}
|
|
4004
|
+
async function resolveSourceTarget(ctx, source, importer, options) {
|
|
4005
|
+
const resolved2 = await ctx.resolve(source, importer);
|
|
4006
|
+
if (!resolved2 || resolved2.external) return null;
|
|
4007
|
+
const target = resolved2.id.split("?", 1)[0];
|
|
4008
|
+
if (target.startsWith("\0")) return null;
|
|
4009
|
+
if (options.skipNodeModules && target.includes("/node_modules/")) {
|
|
4010
|
+
return null;
|
|
4011
|
+
}
|
|
4012
|
+
return target;
|
|
4013
|
+
}
|
|
4014
|
+
async function recordEmitted(emitted, file, value) {
|
|
4015
|
+
emitted.set(file, { disk: await readSource(file), value });
|
|
4016
|
+
}
|
|
4017
|
+
async function loadEmittedOrDisk(emitted, hoistedFile, rehoist) {
|
|
4018
|
+
const disk = await readSource(hoistedFile);
|
|
4019
|
+
const entry = emitted.get(normalizePath2(hoistedFile));
|
|
4020
|
+
if (entry && (disk === null || entry.disk === disk)) return entry.value;
|
|
4021
|
+
return disk === null ? void 0 : rehoist(disk);
|
|
4022
|
+
}
|
|
4023
|
+
|
|
4024
|
+
// src/vite/plugins/transition-when-hoist.ts
|
|
4025
|
+
var TRANSITION_WHEN_QUERY = "rango-when";
|
|
4026
|
+
var EXPORT_NAME = "__rango_when";
|
|
4027
|
+
var LOCAL_PREFIX = "__rango_when_";
|
|
4028
|
+
var ROUTER_SOURCES = /* @__PURE__ */ new Set(["@rangojs/router"]);
|
|
4029
|
+
function findWhenSites(program, scopeOf, moduleScope, imports) {
|
|
4030
|
+
const sites = [];
|
|
4031
|
+
for (const { call, scope } of findHelperCalls(
|
|
4032
|
+
program,
|
|
4033
|
+
scopeOf,
|
|
4034
|
+
moduleScope,
|
|
4035
|
+
imports,
|
|
4036
|
+
{
|
|
4037
|
+
sources: ROUTER_SOURCES,
|
|
4038
|
+
builder: "urls",
|
|
4039
|
+
helper: "transition",
|
|
4040
|
+
directImport: true
|
|
4041
|
+
}
|
|
4042
|
+
)) {
|
|
4043
|
+
if (call.arguments[0]?.type !== "ObjectExpression") continue;
|
|
4044
|
+
for (const prop of call.arguments[0].properties) {
|
|
4045
|
+
if (propertyKeyIs(prop, "when")) {
|
|
4046
|
+
sites.push({ prop, value: unwrapExpression(prop.value), scope });
|
|
4047
|
+
}
|
|
4048
|
+
}
|
|
4049
|
+
}
|
|
4050
|
+
return sites;
|
|
4051
|
+
}
|
|
4052
|
+
var WHEN_CAPTURE_MESSAGES = {
|
|
4053
|
+
lexical: {
|
|
4054
|
+
this: "`this` in an arrow is the enclosing server function's `this`.",
|
|
4055
|
+
arguments: "`arguments` in an arrow is the enclosing server function's `arguments`.",
|
|
4056
|
+
super: "`super` refers to the enclosing server object.",
|
|
4057
|
+
"new.target": "`new.target` in an arrow is the enclosing server function's."
|
|
4058
|
+
},
|
|
4059
|
+
captureHint: 'Read what you need from `to.params`/`to.state`, or export the predicate from a "use client" module.',
|
|
4060
|
+
loadsHint: 'Import client-safe modules statically, or export the predicate from a "use client" module.',
|
|
4061
|
+
importMetaWhy: "is the server module's.",
|
|
4062
|
+
importMetaMemberWhy: "is resolved against the server module; only `import.meta.env` is available to an inline predicate.",
|
|
4063
|
+
dynamicImportWhy: "loads a module at run time, which the build cannot check is client-safe."
|
|
4064
|
+
};
|
|
3956
4065
|
var NODE_BUILTINS = new Set(builtinModules);
|
|
3957
4066
|
function isServerOnlySpecifier(source) {
|
|
3958
4067
|
return source === "server-only" || source.startsWith("node:") || source.startsWith("cloudflare:") || NODE_BUILTINS.has(source);
|
|
3959
4068
|
}
|
|
3960
4069
|
var ROUTER_IMPORT_RE = /["']@rangojs\/router["']/;
|
|
3961
4070
|
var WHEN_RE = /\bwhen\b/;
|
|
3962
|
-
function parseLang(file) {
|
|
3963
|
-
if (/\.[cm]?ts$/.test(file)) return "ts";
|
|
3964
|
-
if (/\.[cm]?jsx?$/.test(file)) return "jsx";
|
|
3965
|
-
return "tsx";
|
|
3966
|
-
}
|
|
3967
4071
|
function whenError(file, code, node, detail) {
|
|
4072
|
+
const { line, column } = offsetToLineColumn(code, node.start);
|
|
3968
4073
|
return new TransitionWhenError(
|
|
3969
|
-
`[rango] transition({ when }) at ${file}:${
|
|
4074
|
+
`[rango] transition({ when }) at ${file}:${line}:${column}: \`when\` runs in the browser; ${detail}`
|
|
3970
4075
|
);
|
|
3971
4076
|
}
|
|
3972
4077
|
async function hoistTransitionWhens(code, id, deps = {}) {
|
|
3973
4078
|
if (!ROUTER_IMPORT_RE.test(code) || !WHEN_RE.test(code)) return null;
|
|
3974
|
-
const file =
|
|
4079
|
+
const file = normalizePath3(id.split("?", 1)[0]);
|
|
3975
4080
|
let program;
|
|
3976
4081
|
try {
|
|
3977
4082
|
program = parseAst3(code, { lang: parseLang(file) });
|
|
3978
4083
|
} catch {
|
|
3979
4084
|
return null;
|
|
3980
4085
|
}
|
|
3981
|
-
if (
|
|
4086
|
+
if (hasDirective2(program.body, "use client")) return null;
|
|
3982
4087
|
const { moduleScope, references, scopeOf } = analyzeScopes(program);
|
|
3983
4088
|
const imports = collectImports(program);
|
|
3984
4089
|
const sites = findWhenSites(program, scopeOf, moduleScope, imports);
|
|
@@ -4009,66 +4114,43 @@ async function hoistTransitionWhens(code, id, deps = {}) {
|
|
|
4009
4114
|
continue;
|
|
4010
4115
|
}
|
|
4011
4116
|
if (!isFunctionLiteral(value)) continue;
|
|
4012
|
-
const lexical = findLexicalCapture(
|
|
4117
|
+
const lexical = findLexicalCapture(
|
|
4118
|
+
value,
|
|
4119
|
+
references,
|
|
4120
|
+
code,
|
|
4121
|
+
WHEN_CAPTURE_MESSAGES
|
|
4122
|
+
);
|
|
4013
4123
|
if (lexical) throw whenError(file, code, lexical.node, lexical.detail);
|
|
4014
|
-
const
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
const decl = ref.scope.lookup(ref.node.name);
|
|
4018
|
-
if (!decl) continue;
|
|
4019
|
-
if (decl.node.start >= value.start && decl.node.end <= value.end && decl !== moduleScope) {
|
|
4020
|
-
continue;
|
|
4021
|
-
}
|
|
4022
|
-
if (decl === moduleScope && imports.has(ref.node.name)) {
|
|
4023
|
-
const valueUse = !ref.typeOnly && !imports.get(ref.node.name).typeOnly;
|
|
4024
|
-
used.set(ref.node.name, (used.get(ref.node.name) ?? false) || valueUse);
|
|
4025
|
-
continue;
|
|
4026
|
-
}
|
|
4027
|
-
if (ref.typeOnly) continue;
|
|
4124
|
+
const free = collectFreeReferences(value, references, moduleScope, imports);
|
|
4125
|
+
const binding = free.bindings[0];
|
|
4126
|
+
if (binding) {
|
|
4028
4127
|
throw whenError(
|
|
4029
4128
|
file,
|
|
4030
4129
|
code,
|
|
4031
|
-
|
|
4032
|
-
`\`${
|
|
4130
|
+
binding.node,
|
|
4131
|
+
`\`${binding.node.name}\` is a server-module binding. Read it from \`to.params\`/\`to.state\`, or export the predicate from a "use client" module.`
|
|
4033
4132
|
);
|
|
4034
4133
|
}
|
|
4035
|
-
const
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
if (isServerOnlySpecifier(
|
|
4134
|
+
const importLines = await emitImports(
|
|
4135
|
+
free.imports,
|
|
4136
|
+
imports,
|
|
4137
|
+
async (local2, imported) => {
|
|
4138
|
+
if (isServerOnlySpecifier(imported.source) || await deps.isServerOnlyImport?.(imported.source)) {
|
|
4040
4139
|
throw whenError(
|
|
4041
4140
|
file,
|
|
4042
4141
|
code,
|
|
4043
4142
|
value,
|
|
4044
|
-
`\`${local2}\` is imported from "${
|
|
4143
|
+
`\`${local2}\` is imported from "${imported.source}", a server-only module. Import only client-safe modules into an inline predicate, or export it from a "use client" module.`
|
|
4045
4144
|
);
|
|
4046
4145
|
}
|
|
4047
4146
|
}
|
|
4048
|
-
|
|
4049
|
-
const typePrefix = valueUse ? "" : "type ";
|
|
4050
|
-
if (binding.imported === "*") {
|
|
4051
|
-
lines.push(
|
|
4052
|
-
`import ${typePrefix}* as ${local2} from ${JSON.stringify(binding.source)};`
|
|
4053
|
-
);
|
|
4054
|
-
} else if (binding.imported === "default") {
|
|
4055
|
-
lines.push(
|
|
4056
|
-
`import ${typePrefix}${local2} from ${JSON.stringify(binding.source)};`
|
|
4057
|
-
);
|
|
4058
|
-
} else {
|
|
4059
|
-
const spec = binding.imported === local2 ? local2 : `${JSON.stringify(binding.imported)} as ${local2}`;
|
|
4060
|
-
lines.push(
|
|
4061
|
-
`import ${typePrefix}{ ${spec} } from ${JSON.stringify(binding.source)};`
|
|
4062
|
-
);
|
|
4063
|
-
}
|
|
4064
|
-
bySource.set(binding.source, lines);
|
|
4065
|
-
}
|
|
4147
|
+
);
|
|
4066
4148
|
const source = prop.method ? `${value.async ? "async " : ""}function${value.generator ? "*" : ""} ` + code.slice(value.start, value.end) : code.slice(value.start, value.end);
|
|
4067
4149
|
const index = modules.length;
|
|
4068
4150
|
modules.push(
|
|
4069
4151
|
[
|
|
4070
4152
|
`"use client";`,
|
|
4071
|
-
...
|
|
4153
|
+
...importLines,
|
|
4072
4154
|
`export const ${EXPORT_NAME} = ${source};`,
|
|
4073
4155
|
""
|
|
4074
4156
|
].join("\n")
|
|
@@ -4086,13 +4168,7 @@ async function hoistTransitionWhens(code, id, deps = {}) {
|
|
|
4086
4168
|
);
|
|
4087
4169
|
}
|
|
4088
4170
|
if (modules.length === 0) return null;
|
|
4089
|
-
|
|
4090
|
-
for (const statement of program.body) {
|
|
4091
|
-
if (statement.type !== "ExpressionStatement" || typeof statement.directive !== "string") {
|
|
4092
|
-
break;
|
|
4093
|
-
}
|
|
4094
|
-
insertAt = statement.end;
|
|
4095
|
-
}
|
|
4171
|
+
const insertAt = directivePrologueEnd(program);
|
|
4096
4172
|
s.appendLeft(insertAt, `${insertAt ? "\n" : ""}${header.join("\n")}
|
|
4097
4173
|
`);
|
|
4098
4174
|
return {
|
|
@@ -4110,13 +4186,6 @@ function parseHoistedWhenId(id) {
|
|
|
4110
4186
|
return { file: id.slice(0, q), index: Number(raw) };
|
|
4111
4187
|
}
|
|
4112
4188
|
var SERVER_ONLY_IMPORT_RE = /\bimport\s+["']server-only["']/;
|
|
4113
|
-
async function readSource(file) {
|
|
4114
|
-
try {
|
|
4115
|
-
return await readFile(file, "utf-8");
|
|
4116
|
-
} catch {
|
|
4117
|
-
return null;
|
|
4118
|
-
}
|
|
4119
|
-
}
|
|
4120
4189
|
function transitionWhenHoistPlugin() {
|
|
4121
4190
|
const emitted = /* @__PURE__ */ new Map();
|
|
4122
4191
|
return {
|
|
@@ -4125,10 +4194,11 @@ function transitionWhenHoistPlugin() {
|
|
|
4125
4194
|
async load(id) {
|
|
4126
4195
|
const hoisted = parseHoistedWhenId(id);
|
|
4127
4196
|
if (!hoisted) return;
|
|
4128
|
-
const
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4197
|
+
const modules = await loadEmittedOrDisk(
|
|
4198
|
+
emitted,
|
|
4199
|
+
hoisted.file,
|
|
4200
|
+
async (disk) => (await hoistTransitionWhens(disk, hoisted.file))?.modules
|
|
4201
|
+
);
|
|
4132
4202
|
const module = modules?.[hoisted.index];
|
|
4133
4203
|
if (module === void 0) {
|
|
4134
4204
|
throw new TransitionWhenError(
|
|
@@ -4140,35 +4210,397 @@ function transitionWhenHoistPlugin() {
|
|
|
4140
4210
|
async transform(code, id) {
|
|
4141
4211
|
if (this.environment?.name !== "rsc") return;
|
|
4142
4212
|
if (id.includes("/node_modules/") || parseHoistedWhenId(id)) return;
|
|
4143
|
-
const file =
|
|
4144
|
-
if (
|
|
4213
|
+
const file = normalizePath3(id.split("?", 1)[0]);
|
|
4214
|
+
if (!SOURCE_FILE_RE.test(file)) return;
|
|
4145
4215
|
emitted.delete(file);
|
|
4146
4216
|
const result = await hoistTransitionWhens(code, id, {
|
|
4147
4217
|
isServerOnlyImport: async (source) => {
|
|
4148
|
-
const
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
if (target
|
|
4152
|
-
return false;
|
|
4153
|
-
}
|
|
4218
|
+
const target = await resolveSourceTarget(this, source, id, {
|
|
4219
|
+
skipNodeModules: true
|
|
4220
|
+
});
|
|
4221
|
+
if (target === null) return false;
|
|
4154
4222
|
const text = await readSource(target);
|
|
4155
4223
|
return text !== null && SERVER_ONLY_IMPORT_RE.test(text);
|
|
4156
4224
|
}
|
|
4157
4225
|
});
|
|
4158
4226
|
if (!result) return;
|
|
4159
|
-
emitted
|
|
4160
|
-
disk: await readSource(file),
|
|
4161
|
-
modules: result.modules
|
|
4162
|
-
});
|
|
4227
|
+
await recordEmitted(emitted, file, result.modules);
|
|
4163
4228
|
return { code: result.code, map: result.map };
|
|
4164
4229
|
}
|
|
4165
4230
|
};
|
|
4166
4231
|
}
|
|
4167
4232
|
|
|
4233
|
+
// src/vite/plugins/client-urls-revalidate-hoist.ts
|
|
4234
|
+
import { normalizePath as normalizePath4, parseAst as parseAst5 } from "vite";
|
|
4235
|
+
import MagicString5 from "magic-string";
|
|
4236
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
4237
|
+
import { relative } from "node:path";
|
|
4238
|
+
import { hasDirective as hasDirective3 } from "@vitejs/plugin-rsc/transforms";
|
|
4239
|
+
|
|
4240
|
+
// src/client-urls/hoisted-revalidate.ts
|
|
4241
|
+
var HOISTED_REVALIDATE_KEY = "$$rangoRevalidate";
|
|
4242
|
+
function isHoistedRevalidateRef(value) {
|
|
4243
|
+
return typeof value === "object" && value !== null && typeof value[HOISTED_REVALIDATE_KEY] === "string";
|
|
4244
|
+
}
|
|
4245
|
+
|
|
4246
|
+
// src/vite/utils/directive-prologue.ts
|
|
4247
|
+
import { parseAst as parseAst4 } from "vite";
|
|
4248
|
+
function hasUseClientDirective(source) {
|
|
4249
|
+
let program;
|
|
4250
|
+
try {
|
|
4251
|
+
program = parseAst4(source, { lang: "tsx" });
|
|
4252
|
+
} catch {
|
|
4253
|
+
return false;
|
|
4254
|
+
}
|
|
4255
|
+
for (const node of program.body ?? []) {
|
|
4256
|
+
if (node?.type === "ExpressionStatement" && node.expression?.type === "Literal" && typeof node.expression.value === "string") {
|
|
4257
|
+
if (node.expression.value === "use client") return true;
|
|
4258
|
+
continue;
|
|
4259
|
+
}
|
|
4260
|
+
break;
|
|
4261
|
+
}
|
|
4262
|
+
return false;
|
|
4263
|
+
}
|
|
4264
|
+
|
|
4265
|
+
// src/vite/plugins/client-urls-revalidate-hoist.ts
|
|
4266
|
+
var CLIENT_URLS_REVALIDATE_QUERY = "rango-revalidate";
|
|
4267
|
+
var REGISTER = "__rango_registerClientUrlRevalidators";
|
|
4268
|
+
var CLIENT_SOURCES = /* @__PURE__ */ new Set(["@rangojs/router/client"]);
|
|
4269
|
+
var BROWSER_GLOBALS = /* @__PURE__ */ new Set([
|
|
4270
|
+
"window",
|
|
4271
|
+
"document",
|
|
4272
|
+
"navigator",
|
|
4273
|
+
"localStorage",
|
|
4274
|
+
"sessionStorage",
|
|
4275
|
+
"location",
|
|
4276
|
+
"history"
|
|
4277
|
+
]);
|
|
4278
|
+
var NOT_A_FUNCTION = /* @__PURE__ */ new Set([
|
|
4279
|
+
"ObjectExpression",
|
|
4280
|
+
"ArrayExpression",
|
|
4281
|
+
"Literal",
|
|
4282
|
+
"TemplateLiteral",
|
|
4283
|
+
"ClassExpression"
|
|
4284
|
+
]);
|
|
4285
|
+
var CAPTURE_MESSAGES = {
|
|
4286
|
+
lexical: {
|
|
4287
|
+
this: "`this` in an arrow is the enclosing function's `this`.",
|
|
4288
|
+
arguments: "`arguments` in an arrow is the enclosing function's.",
|
|
4289
|
+
super: "`super` refers to the enclosing object.",
|
|
4290
|
+
"new.target": "`new.target` in an arrow is the enclosing function's."
|
|
4291
|
+
},
|
|
4292
|
+
captureHint: "Read what you need from the predicate's argument.",
|
|
4293
|
+
loadsHint: "Import server-safe modules statically.",
|
|
4294
|
+
importMetaWhy: `is the "use client" module's.`,
|
|
4295
|
+
importMetaMemberWhy: 'is resolved against the "use client" module; only `import.meta.env` is available to a hoisted predicate.',
|
|
4296
|
+
dynamicImportWhy: "loads a module at run time, which the build cannot check is server-safe."
|
|
4297
|
+
};
|
|
4298
|
+
var CLIENT_URLS_RE = /\bclientUrls\b/;
|
|
4299
|
+
var CLIENT_IMPORT_RE = /["']@rangojs\/router\/client["']/;
|
|
4300
|
+
var REVALIDATE_RE = /\brevalidate\b/;
|
|
4301
|
+
function mayHoist(code) {
|
|
4302
|
+
return code.includes("use client") && CLIENT_URLS_RE.test(code) && CLIENT_IMPORT_RE.test(code) && REVALIDATE_RE.test(code);
|
|
4303
|
+
}
|
|
4304
|
+
function revalidateError(file, code, node, detail) {
|
|
4305
|
+
const { line, column } = offsetToLineColumn(code, node.start);
|
|
4306
|
+
return new Error(
|
|
4307
|
+
`[rango] clientUrls() revalidate() at ${file}:${line}:${column}: revalidate() runs on the server; ${detail}`
|
|
4308
|
+
);
|
|
4309
|
+
}
|
|
4310
|
+
var FINGERPRINT_SKIP = /* @__PURE__ */ new Set([
|
|
4311
|
+
"type",
|
|
4312
|
+
"start",
|
|
4313
|
+
"end",
|
|
4314
|
+
"loc",
|
|
4315
|
+
"range",
|
|
4316
|
+
"raw",
|
|
4317
|
+
"extra",
|
|
4318
|
+
"shorthand",
|
|
4319
|
+
// TS-only flags (`let x!: T`), lost with the types.
|
|
4320
|
+
"definite",
|
|
4321
|
+
...TYPE_KEYS
|
|
4322
|
+
]);
|
|
4323
|
+
function fingerprint(node) {
|
|
4324
|
+
const out = [];
|
|
4325
|
+
const visit = (value) => {
|
|
4326
|
+
if (value === null || value === void 0) return;
|
|
4327
|
+
if (Array.isArray(value)) {
|
|
4328
|
+
out.push("[");
|
|
4329
|
+
for (const item of value) visit(item);
|
|
4330
|
+
out.push("]");
|
|
4331
|
+
return;
|
|
4332
|
+
}
|
|
4333
|
+
if (typeof value !== "object") {
|
|
4334
|
+
out.push(JSON.stringify(typeof value === "bigint" ? `${value}n` : value));
|
|
4335
|
+
return;
|
|
4336
|
+
}
|
|
4337
|
+
let entry = value;
|
|
4338
|
+
if (typeof entry.type === "string") {
|
|
4339
|
+
entry = unwrapExpression(entry);
|
|
4340
|
+
if (entry.type.startsWith("TS")) {
|
|
4341
|
+
visit(entry.expression);
|
|
4342
|
+
return;
|
|
4343
|
+
}
|
|
4344
|
+
out.push(entry.type, "(");
|
|
4345
|
+
if (entry.type === "TemplateElement") {
|
|
4346
|
+
out.push(JSON.stringify(entry.value.raw));
|
|
4347
|
+
}
|
|
4348
|
+
}
|
|
4349
|
+
for (const key of Object.keys(entry)) {
|
|
4350
|
+
if (FINGERPRINT_SKIP.has(key)) continue;
|
|
4351
|
+
if (key === "optional" && entry.type === "Identifier") continue;
|
|
4352
|
+
out.push(key);
|
|
4353
|
+
visit(entry[key]);
|
|
4354
|
+
}
|
|
4355
|
+
if (typeof entry.type === "string") out.push(")");
|
|
4356
|
+
};
|
|
4357
|
+
visit(node);
|
|
4358
|
+
return out.join(" ");
|
|
4359
|
+
}
|
|
4360
|
+
function keyOf(relativeFile, predicate) {
|
|
4361
|
+
return createHash2("sha256").update(relativeFile).update("\0").update(fingerprint(predicate)).digest("hex").slice(0, 12);
|
|
4362
|
+
}
|
|
4363
|
+
async function hoistClientUrlsRevalidates(code, id, deps) {
|
|
4364
|
+
if (!mayHoist(code)) return null;
|
|
4365
|
+
const file = normalizePath4(id.split("?", 1)[0]);
|
|
4366
|
+
let program;
|
|
4367
|
+
try {
|
|
4368
|
+
program = parseAst5(code, { lang: parseLang(file) });
|
|
4369
|
+
} catch {
|
|
4370
|
+
return null;
|
|
4371
|
+
}
|
|
4372
|
+
if (!hasDirective3(program.body, "use client")) return null;
|
|
4373
|
+
const { moduleScope, references, scopeOf } = analyzeScopes(program);
|
|
4374
|
+
const imports = collectImports(program);
|
|
4375
|
+
const calls = findHelperCalls(program, scopeOf, moduleScope, imports, {
|
|
4376
|
+
sources: CLIENT_SOURCES,
|
|
4377
|
+
builder: "clientUrls",
|
|
4378
|
+
helper: "revalidate",
|
|
4379
|
+
directImport: false
|
|
4380
|
+
});
|
|
4381
|
+
if (calls.length === 0) return null;
|
|
4382
|
+
const relativeFile = normalizePath4(relative(deps.root, file));
|
|
4383
|
+
const s = new MagicString5(code);
|
|
4384
|
+
const used = /* @__PURE__ */ new Map();
|
|
4385
|
+
const entries = /* @__PURE__ */ new Map();
|
|
4386
|
+
for (const { call } of calls) {
|
|
4387
|
+
const [arg, extra] = call.arguments;
|
|
4388
|
+
if (!arg || extra || arg.type === "SpreadElement") {
|
|
4389
|
+
throw revalidateError(
|
|
4390
|
+
file,
|
|
4391
|
+
code,
|
|
4392
|
+
call,
|
|
4393
|
+
"`revalidate()` takes exactly one predicate."
|
|
4394
|
+
);
|
|
4395
|
+
}
|
|
4396
|
+
const value = unwrapExpression(arg);
|
|
4397
|
+
if (NOT_A_FUNCTION.has(value.type)) {
|
|
4398
|
+
throw revalidateError(
|
|
4399
|
+
file,
|
|
4400
|
+
code,
|
|
4401
|
+
value,
|
|
4402
|
+
"`revalidate()` expects a predicate function."
|
|
4403
|
+
);
|
|
4404
|
+
}
|
|
4405
|
+
if (isFunctionLiteral(value) && (value.async || value.generator)) {
|
|
4406
|
+
throw revalidateError(
|
|
4407
|
+
file,
|
|
4408
|
+
code,
|
|
4409
|
+
value,
|
|
4410
|
+
`a${value.async ? "n `async`" : " generator"} function returns ${value.async ? "a Promise" : "an iterator"}, which the router ignores: return a boolean, \`{ defaultShouldRevalidate }\`, or nothing.`
|
|
4411
|
+
);
|
|
4412
|
+
}
|
|
4413
|
+
const lexical = findLexicalCapture(
|
|
4414
|
+
value,
|
|
4415
|
+
references,
|
|
4416
|
+
code,
|
|
4417
|
+
CAPTURE_MESSAGES
|
|
4418
|
+
);
|
|
4419
|
+
if (lexical)
|
|
4420
|
+
throw revalidateError(file, code, lexical.node, lexical.detail);
|
|
4421
|
+
const free = collectFreeReferences(value, references, moduleScope, imports);
|
|
4422
|
+
const binding = free.bindings[0];
|
|
4423
|
+
if (binding) {
|
|
4424
|
+
const name = binding.node.name;
|
|
4425
|
+
throw revalidateError(
|
|
4426
|
+
file,
|
|
4427
|
+
code,
|
|
4428
|
+
binding.node,
|
|
4429
|
+
binding.scope.lookup(name) === moduleScope ? `\`${name}\` is declared in this "use client" module. Move the predicate to its own module (without "use client") and import it, or write it inline.` : `\`${name}\` is a binding of the enclosing function. Read what you need from the predicate's argument (\`currentParams\`, \`nextUrl\`, \`context\`, \`actionResult\`, ...).`
|
|
4430
|
+
);
|
|
4431
|
+
}
|
|
4432
|
+
const browserGlobal = free.globals.find(
|
|
4433
|
+
(ref) => BROWSER_GLOBALS.has(ref.node.name)
|
|
4434
|
+
);
|
|
4435
|
+
if (browserGlobal) {
|
|
4436
|
+
throw revalidateError(
|
|
4437
|
+
file,
|
|
4438
|
+
code,
|
|
4439
|
+
browserGlobal.node,
|
|
4440
|
+
`\`${browserGlobal.node.name}\` is a browser global. Put the input on the request (a cookie or a search param) and read it from the predicate's argument, or refresh the loader with useRefreshLoaders.`
|
|
4441
|
+
);
|
|
4442
|
+
}
|
|
4443
|
+
const unchecked = [...free.imports].filter(
|
|
4444
|
+
([local, valueUse]) => valueUse && !used.get(local)
|
|
4445
|
+
);
|
|
4446
|
+
const clientOnly = await Promise.all(
|
|
4447
|
+
unchecked.map(([local]) => isClientOnly(imports.get(local), deps))
|
|
4448
|
+
);
|
|
4449
|
+
const offender = unchecked.find((_, i) => clientOnly[i]);
|
|
4450
|
+
if (offender) {
|
|
4451
|
+
const [local] = offender;
|
|
4452
|
+
throw revalidateError(
|
|
4453
|
+
file,
|
|
4454
|
+
code,
|
|
4455
|
+
value,
|
|
4456
|
+
`\`${local}\` is imported from "${imports.get(local).source}", a client-only module: on the server a "use client" module's exports are client references and cannot be called. Import the predicate's inputs from a module without "use client".`
|
|
4457
|
+
);
|
|
4458
|
+
}
|
|
4459
|
+
for (const [local, valueUse] of free.imports) {
|
|
4460
|
+
used.set(local, (used.get(local) ?? false) || valueUse);
|
|
4461
|
+
}
|
|
4462
|
+
const source = code.slice(value.start, value.end);
|
|
4463
|
+
const key = keyOf(relativeFile, value);
|
|
4464
|
+
entries.set(key, source);
|
|
4465
|
+
s.overwrite(
|
|
4466
|
+
arg.start,
|
|
4467
|
+
arg.end,
|
|
4468
|
+
`{ ${HOISTED_REVALIDATE_KEY}: ${JSON.stringify(key)} }`
|
|
4469
|
+
);
|
|
4470
|
+
}
|
|
4471
|
+
const importLines = await emitImports(used, imports, () => {
|
|
4472
|
+
});
|
|
4473
|
+
const module = [
|
|
4474
|
+
`import { registerClientUrlRevalidators as ${REGISTER} } from "@rangojs/router/server";`,
|
|
4475
|
+
...importLines,
|
|
4476
|
+
`${REGISTER}({`,
|
|
4477
|
+
...[...entries].map(
|
|
4478
|
+
([key, source]) => ` ${JSON.stringify(key)}: ${source},`
|
|
4479
|
+
),
|
|
4480
|
+
`});`,
|
|
4481
|
+
""
|
|
4482
|
+
].join("\n");
|
|
4483
|
+
return {
|
|
4484
|
+
code: s.toString(),
|
|
4485
|
+
map: s.generateMap({ hires: true, source: file }),
|
|
4486
|
+
module,
|
|
4487
|
+
keys: [...entries.keys()]
|
|
4488
|
+
};
|
|
4489
|
+
}
|
|
4490
|
+
async function isClientOnly(binding, deps) {
|
|
4491
|
+
return binding.source === "client-only" || Boolean(await deps.isClientModule?.(binding.source));
|
|
4492
|
+
}
|
|
4493
|
+
function parseHoistedRevalidateId(id) {
|
|
4494
|
+
const q = id.indexOf("?");
|
|
4495
|
+
if (q === -1) return null;
|
|
4496
|
+
const params = new URLSearchParams(id.slice(q + 1));
|
|
4497
|
+
return params.has(CLIENT_URLS_REVALIDATE_QUERY) ? id.slice(0, q) : null;
|
|
4498
|
+
}
|
|
4499
|
+
var HOISTED_ID_RE = new RegExp(
|
|
4500
|
+
`[?&]${CLIENT_URLS_REVALIDATE_QUERY}(?:[=&]|$)`
|
|
4501
|
+
);
|
|
4502
|
+
var SOURCE_ID_RE = /\.[cm]?[jt]sx?(?:\?|$)/;
|
|
4503
|
+
var NODE_MODULES_RE = /\/node_modules\//;
|
|
4504
|
+
function clientUrlsRevalidateHoistPlugin() {
|
|
4505
|
+
const emitted = /* @__PURE__ */ new Map();
|
|
4506
|
+
const clientModules = /* @__PURE__ */ new Map();
|
|
4507
|
+
let root = process.cwd();
|
|
4508
|
+
const isClientFile = (file) => {
|
|
4509
|
+
let known = clientModules.get(file);
|
|
4510
|
+
if (!known) {
|
|
4511
|
+
known = readSource(file).then(
|
|
4512
|
+
(text) => text !== null && text.includes("use client") && hasUseClientDirective(text)
|
|
4513
|
+
);
|
|
4514
|
+
clientModules.set(file, known);
|
|
4515
|
+
}
|
|
4516
|
+
return known;
|
|
4517
|
+
};
|
|
4518
|
+
return [
|
|
4519
|
+
{
|
|
4520
|
+
name: "@rangojs/router:client-urls-revalidate-hoist",
|
|
4521
|
+
enforce: "pre",
|
|
4522
|
+
configResolved(config) {
|
|
4523
|
+
root = config.root;
|
|
4524
|
+
},
|
|
4525
|
+
buildStart() {
|
|
4526
|
+
clientModules.clear();
|
|
4527
|
+
},
|
|
4528
|
+
watchChange(id) {
|
|
4529
|
+
const file = normalizePath4(id);
|
|
4530
|
+
clientModules.delete(file);
|
|
4531
|
+
emitted.delete(file);
|
|
4532
|
+
},
|
|
4533
|
+
load: {
|
|
4534
|
+
filter: { id: HOISTED_ID_RE },
|
|
4535
|
+
async handler(id) {
|
|
4536
|
+
const hoistedFile = parseHoistedRevalidateId(id);
|
|
4537
|
+
if (hoistedFile === null) return;
|
|
4538
|
+
const module = await loadEmittedOrDisk(
|
|
4539
|
+
emitted,
|
|
4540
|
+
hoistedFile,
|
|
4541
|
+
async (disk) => (await hoistClientUrlsRevalidates(disk, hoistedFile, { root }))?.module
|
|
4542
|
+
);
|
|
4543
|
+
return module ?? "export {};\n";
|
|
4544
|
+
}
|
|
4545
|
+
},
|
|
4546
|
+
transform: {
|
|
4547
|
+
filter: {
|
|
4548
|
+
id: {
|
|
4549
|
+
include: SOURCE_ID_RE,
|
|
4550
|
+
exclude: [NODE_MODULES_RE, HOISTED_ID_RE]
|
|
4551
|
+
},
|
|
4552
|
+
code: CLIENT_URLS_RE
|
|
4553
|
+
},
|
|
4554
|
+
async handler(code, id) {
|
|
4555
|
+
if (id.includes("/node_modules/") || parseHoistedRevalidateId(id)) {
|
|
4556
|
+
return;
|
|
4557
|
+
}
|
|
4558
|
+
const file = normalizePath4(id.split("?", 1)[0]);
|
|
4559
|
+
if (!SOURCE_FILE_RE.test(file)) return;
|
|
4560
|
+
const rsc = this.environment?.name === "rsc";
|
|
4561
|
+
if (rsc) emitted.delete(file);
|
|
4562
|
+
const result = await hoistClientUrlsRevalidates(code, id, {
|
|
4563
|
+
root,
|
|
4564
|
+
isClientModule: rsc ? async (source) => {
|
|
4565
|
+
const target = await resolveSourceTarget(this, source, id, {
|
|
4566
|
+
skipNodeModules: false
|
|
4567
|
+
});
|
|
4568
|
+
return target !== null && await isClientFile(target);
|
|
4569
|
+
} : void 0
|
|
4570
|
+
});
|
|
4571
|
+
if (!result) return;
|
|
4572
|
+
if (rsc) await recordEmitted(emitted, file, result.module);
|
|
4573
|
+
return { code: result.code, map: result.map };
|
|
4574
|
+
}
|
|
4575
|
+
}
|
|
4576
|
+
},
|
|
4577
|
+
{
|
|
4578
|
+
name: "@rangojs/router:client-urls-revalidate-register",
|
|
4579
|
+
enforce: "post",
|
|
4580
|
+
applyToEnvironment: (env) => env.name === "rsc",
|
|
4581
|
+
transform: {
|
|
4582
|
+
filter: { code: "registerClientReference" },
|
|
4583
|
+
handler(code, id) {
|
|
4584
|
+
if (parseHoistedRevalidateId(id)) return;
|
|
4585
|
+
const file = normalizePath4(id.split("?", 1)[0]);
|
|
4586
|
+
if (!emitted.has(file)) return;
|
|
4587
|
+
const s = new MagicString5(code);
|
|
4588
|
+
s.append(
|
|
4589
|
+
`
|
|
4590
|
+
import ${JSON.stringify(`${file}?${CLIENT_URLS_REVALIDATE_QUERY}`)};
|
|
4591
|
+
`
|
|
4592
|
+
);
|
|
4593
|
+
return { code: s.toString(), map: s.generateMap({ hires: true }) };
|
|
4594
|
+
}
|
|
4595
|
+
}
|
|
4596
|
+
}
|
|
4597
|
+
];
|
|
4598
|
+
}
|
|
4599
|
+
|
|
4168
4600
|
// src/vite/plugins/client-ref-dedup.ts
|
|
4169
4601
|
init_debug();
|
|
4170
4602
|
import { existsSync, readFileSync } from "node:fs";
|
|
4171
|
-
import { isAbsolute, join, normalize, relative } from "node:path";
|
|
4603
|
+
import { isAbsolute, join, normalize, relative as relative2 } from "node:path";
|
|
4172
4604
|
var debug4 = createRangoDebugger(NS.transform);
|
|
4173
4605
|
var CLIENT_IN_SERVER_PROXY_PREFIX = "virtual:vite-rsc/client-in-server-package-proxy/";
|
|
4174
4606
|
var DEDUP_PREFIX = "\0rango:dedup/";
|
|
@@ -4254,7 +4686,7 @@ function getPublicSpecifierCandidates(metadata, packageSpecifier, source) {
|
|
|
4254
4686
|
return [];
|
|
4255
4687
|
}
|
|
4256
4688
|
const candidates = /* @__PURE__ */ new Set();
|
|
4257
|
-
const sourceRelative = `./${
|
|
4689
|
+
const sourceRelative = `./${relative2(metadata.root, source).replaceAll("\\", "/")}`;
|
|
4258
4690
|
if (sourceRelative.startsWith("./../") || isAbsolute(sourceRelative.slice(2))) {
|
|
4259
4691
|
return [];
|
|
4260
4692
|
}
|
|
@@ -4411,12 +4843,12 @@ function clientRefDedup() {
|
|
|
4411
4843
|
}
|
|
4412
4844
|
|
|
4413
4845
|
// src/vite/plugins/stable-rsc-output.ts
|
|
4414
|
-
import { parseAst as
|
|
4846
|
+
import { parseAst as parseAst6 } from "vite";
|
|
4415
4847
|
|
|
4416
4848
|
// src/vite/discovery/build-versions.ts
|
|
4417
|
-
import { createHash as
|
|
4849
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
4418
4850
|
import { isBuiltin } from "node:module";
|
|
4419
|
-
import { posix, relative as
|
|
4851
|
+
import { posix, relative as relative4 } from "node:path";
|
|
4420
4852
|
|
|
4421
4853
|
// src/router-versions.ts
|
|
4422
4854
|
var DEFAULT_ROUTER_VERSIONS_KEY = "*";
|
|
@@ -4990,7 +5422,7 @@ function resolveRouterMembers(server, client, routers) {
|
|
|
4990
5422
|
return members;
|
|
4991
5423
|
}
|
|
4992
5424
|
function sha256(value) {
|
|
4993
|
-
return
|
|
5425
|
+
return createHash4("sha256").update(value).digest("hex");
|
|
4994
5426
|
}
|
|
4995
5427
|
var baseName = posix.basename;
|
|
4996
5428
|
function isAbsolutePath(path6) {
|
|
@@ -5011,7 +5443,7 @@ function portableModuleId(id, projectRoot) {
|
|
|
5011
5443
|
return path6.slice(nodeModules + 1).replace(PNPM_PEER_SUFFIX, "$1");
|
|
5012
5444
|
}
|
|
5013
5445
|
if (isAbsolutePath(path6)) {
|
|
5014
|
-
return
|
|
5446
|
+
return relative4(projectRoot, path6).replaceAll("\\", "/");
|
|
5015
5447
|
}
|
|
5016
5448
|
return withoutWorkingDirectory(path6).replace(
|
|
5017
5449
|
/([?&][^=&]+=)([^&]+)/g,
|
|
@@ -5372,7 +5804,7 @@ function literalProperties(object) {
|
|
|
5372
5804
|
function defaultExportProperties(code) {
|
|
5373
5805
|
let program;
|
|
5374
5806
|
try {
|
|
5375
|
-
program =
|
|
5807
|
+
program = parseAst6(code);
|
|
5376
5808
|
} catch {
|
|
5377
5809
|
return void 0;
|
|
5378
5810
|
}
|
|
@@ -5428,7 +5860,7 @@ import { resolve } from "node:path";
|
|
|
5428
5860
|
// package.json
|
|
5429
5861
|
var package_default = {
|
|
5430
5862
|
name: "@rangojs/router",
|
|
5431
|
-
version: "0.
|
|
5863
|
+
version: "0.23.0",
|
|
5432
5864
|
description: "Django-inspired RSC router with composable URL patterns",
|
|
5433
5865
|
keywords: [
|
|
5434
5866
|
"react",
|
|
@@ -5888,7 +6320,7 @@ declare global {
|
|
|
5888
6320
|
}
|
|
5889
6321
|
|
|
5890
6322
|
// src/build/route-types/scan-filter.ts
|
|
5891
|
-
import { join as join2, relative as
|
|
6323
|
+
import { isAbsolute as isAbsolute2, join as join2, relative as relative5 } from "node:path";
|
|
5892
6324
|
import { readdirSync } from "node:fs";
|
|
5893
6325
|
import picomatch from "picomatch";
|
|
5894
6326
|
var DEFAULT_EXCLUDE_PATTERNS = [
|
|
@@ -5908,12 +6340,22 @@ function createScanFilter(root, opts) {
|
|
|
5908
6340
|
const includeMatcher = hasInclude ? picomatch(include) : null;
|
|
5909
6341
|
const excludeMatcher = effectiveExclude.length > 0 ? picomatch(effectiveExclude) : null;
|
|
5910
6342
|
return (absolutePath) => {
|
|
5911
|
-
const rel =
|
|
6343
|
+
const rel = relative5(root, absolutePath);
|
|
5912
6344
|
if (excludeMatcher && excludeMatcher(rel)) return false;
|
|
5913
6345
|
if (includeMatcher) return includeMatcher(rel);
|
|
5914
6346
|
return true;
|
|
5915
6347
|
};
|
|
5916
6348
|
}
|
|
6349
|
+
function isUniversallySkippedScanDir(name) {
|
|
6350
|
+
return name === "node_modules" || name === "dist" || name === "coverage" || name.startsWith(".");
|
|
6351
|
+
}
|
|
6352
|
+
function isInSkippedScanDir(root, absolutePath) {
|
|
6353
|
+
const rel = relative5(root, absolutePath);
|
|
6354
|
+
if (isAbsolute2(rel)) return false;
|
|
6355
|
+
const dirs = rel.split(/[\\/]/).slice(0, -1);
|
|
6356
|
+
if (dirs[0] === "..") return false;
|
|
6357
|
+
return dirs.some(isUniversallySkippedScanDir);
|
|
6358
|
+
}
|
|
5917
6359
|
function findTsFiles(dir, filter) {
|
|
5918
6360
|
const results = [];
|
|
5919
6361
|
let entries;
|
|
@@ -5928,8 +6370,9 @@ function findTsFiles(dir, filter) {
|
|
|
5928
6370
|
for (const entry of entries) {
|
|
5929
6371
|
const fullPath = join2(dir, entry.name);
|
|
5930
6372
|
if (entry.isDirectory()) {
|
|
5931
|
-
if (entry.name
|
|
6373
|
+
if (isUniversallySkippedScanDir(entry.name) || entry.name === "build") {
|
|
5932
6374
|
continue;
|
|
6375
|
+
}
|
|
5933
6376
|
results.push(...findTsFiles(fullPath, filter));
|
|
5934
6377
|
} else if ((entry.name.endsWith(".ts") || entry.name.endsWith(".tsx") || entry.name.endsWith(".js") || entry.name.endsWith(".jsx")) && !entry.name.includes(".gen.")) {
|
|
5935
6378
|
if (filter && !filter(fullPath)) continue;
|
|
@@ -6513,7 +6956,7 @@ function isRoutableSourceFile(name) {
|
|
|
6513
6956
|
return (name.endsWith(".ts") || name.endsWith(".tsx") || name.endsWith(".js") || name.endsWith(".jsx")) && !name.includes(".gen.") && !name.includes(".test.") && !name.includes(".spec.");
|
|
6514
6957
|
}
|
|
6515
6958
|
function isExcludedScanDir(name) {
|
|
6516
|
-
return name
|
|
6959
|
+
return isUniversallySkippedScanDir(name) || name === "__tests__" || name === "__mocks__";
|
|
6517
6960
|
}
|
|
6518
6961
|
function findCallSiteFilesRecursive(dir, pattern, patternG, stopAtMatchDir, filter, results) {
|
|
6519
6962
|
let entries;
|
|
@@ -6896,28 +7339,7 @@ function writeCombinedRouteTypes(root, knownRouterFiles, opts) {
|
|
|
6896
7339
|
}
|
|
6897
7340
|
|
|
6898
7341
|
// src/vite/plugins/version-plugin.ts
|
|
6899
|
-
import { parseAst as
|
|
6900
|
-
|
|
6901
|
-
// src/vite/utils/directive-prologue.ts
|
|
6902
|
-
import { parseAst as parseAst5 } from "vite";
|
|
6903
|
-
function hasUseClientDirective2(source) {
|
|
6904
|
-
let program;
|
|
6905
|
-
try {
|
|
6906
|
-
program = parseAst5(source, { lang: "tsx" });
|
|
6907
|
-
} catch {
|
|
6908
|
-
return false;
|
|
6909
|
-
}
|
|
6910
|
-
for (const node of program.body ?? []) {
|
|
6911
|
-
if (node?.type === "ExpressionStatement" && node.expression?.type === "Literal" && typeof node.expression.value === "string") {
|
|
6912
|
-
if (node.expression.value === "use client") return true;
|
|
6913
|
-
continue;
|
|
6914
|
-
}
|
|
6915
|
-
break;
|
|
6916
|
-
}
|
|
6917
|
-
return false;
|
|
6918
|
-
}
|
|
6919
|
-
|
|
6920
|
-
// src/vite/plugins/version-plugin.ts
|
|
7342
|
+
import { parseAst as parseAst7 } from "vite";
|
|
6921
7343
|
function isCodeModule(id) {
|
|
6922
7344
|
return /\.(tsx?|jsx?)($|\?)/.test(id);
|
|
6923
7345
|
}
|
|
@@ -6925,10 +7347,10 @@ function normalizeModuleId(id) {
|
|
|
6925
7347
|
return id.split("?", 1)[0];
|
|
6926
7348
|
}
|
|
6927
7349
|
function getClientModuleSignature(source) {
|
|
6928
|
-
if (!
|
|
7350
|
+
if (!hasUseClientDirective(source)) return void 0;
|
|
6929
7351
|
let program;
|
|
6930
7352
|
try {
|
|
6931
|
-
program =
|
|
7353
|
+
program = parseAst7(source, { lang: "tsx" });
|
|
6932
7354
|
} catch {
|
|
6933
7355
|
return void 0;
|
|
6934
7356
|
}
|
|
@@ -7103,7 +7525,7 @@ function isViteDepCachePath(filePath, cacheDir) {
|
|
|
7103
7525
|
|
|
7104
7526
|
// src/vite/utils/shared-utils.ts
|
|
7105
7527
|
import * as Vite from "vite";
|
|
7106
|
-
import { isAbsolute as
|
|
7528
|
+
import { isAbsolute as isAbsolute3, resolve as resolve4 } from "node:path";
|
|
7107
7529
|
|
|
7108
7530
|
// src/vite/plugins/performance-tracks.ts
|
|
7109
7531
|
init_debug();
|
|
@@ -7190,7 +7612,7 @@ var sharedRolldownOptions = {
|
|
|
7190
7612
|
function normalizeHostRouterEntry(rawInput, root, exists) {
|
|
7191
7613
|
const raw = rawInput.replaceAll("\\", "/");
|
|
7192
7614
|
const isRelative = raw.startsWith("./") || raw.startsWith("../");
|
|
7193
|
-
const isRooted = raw.startsWith("/") ||
|
|
7615
|
+
const isRooted = raw.startsWith("/") || isAbsolute3(rawInput);
|
|
7194
7616
|
if (isRooted) return raw;
|
|
7195
7617
|
if (isRelative) {
|
|
7196
7618
|
if (!exists(resolve4(root, raw))) {
|
|
@@ -7680,7 +8102,7 @@ function createCjsToEsmPlugin() {
|
|
|
7680
8102
|
}
|
|
7681
8103
|
|
|
7682
8104
|
// src/vite/router-discovery.ts
|
|
7683
|
-
import { createServer as createViteServer } from "vite";
|
|
8105
|
+
import { createServer as createViteServer, normalizePath as normalizePath8 } from "vite";
|
|
7684
8106
|
import { dirname as dirname7, join as join10, resolve as resolve13 } from "node:path";
|
|
7685
8107
|
import { existsSync as existsSync12, readFileSync as readFileSync11 } from "node:fs";
|
|
7686
8108
|
import { createRequire as createRequire3, register } from "node:module";
|
|
@@ -8073,10 +8495,10 @@ function evictHandlerCode(code, exports, fnName, brand) {
|
|
|
8073
8495
|
}
|
|
8074
8496
|
|
|
8075
8497
|
// src/vite/discovery/self-gen-tracking.ts
|
|
8076
|
-
import { createHash as
|
|
8498
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
8077
8499
|
import { readFileSync as readFileSync4 } from "node:fs";
|
|
8078
8500
|
function markSelfGenWrite(state, filePath, content) {
|
|
8079
|
-
const hash =
|
|
8501
|
+
const hash = createHash5("sha256").update(content).digest("hex");
|
|
8080
8502
|
state.selfWrittenGenFiles.set(filePath, { at: Date.now(), hash });
|
|
8081
8503
|
}
|
|
8082
8504
|
function consumeSelfGenWrite(state, filePath) {
|
|
@@ -8094,7 +8516,7 @@ function checkSelfGenWrite(state, filePath, consume) {
|
|
|
8094
8516
|
}
|
|
8095
8517
|
try {
|
|
8096
8518
|
const current = readFileSync4(filePath, "utf-8");
|
|
8097
|
-
const currentHash =
|
|
8519
|
+
const currentHash = createHash5("sha256").update(current).digest("hex");
|
|
8098
8520
|
if (currentHash === info.hash) {
|
|
8099
8521
|
if (consume) state.selfWrittenGenFiles.delete(filePath);
|
|
8100
8522
|
return true;
|
|
@@ -8595,7 +9017,7 @@ function contextSet(variables, keyOrVar, value, options) {
|
|
|
8595
9017
|
}
|
|
8596
9018
|
|
|
8597
9019
|
// src/vite/utils/prerender-utils.ts
|
|
8598
|
-
import { createHash as
|
|
9020
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
8599
9021
|
import {
|
|
8600
9022
|
copyFileSync,
|
|
8601
9023
|
existsSync as existsSync6,
|
|
@@ -8768,7 +9190,7 @@ function resetStagedBuildAssets(projectRoot) {
|
|
|
8768
9190
|
}
|
|
8769
9191
|
function writeBuildAssetModule(dir, prefix, exportValue) {
|
|
8770
9192
|
mkdirSync(dir, { recursive: true });
|
|
8771
|
-
const contentHash =
|
|
9193
|
+
const contentHash = createHash6("sha256").update(exportValue).digest("hex").slice(0, 8);
|
|
8772
9194
|
const fileName = `${prefix}-${contentHash}.js`;
|
|
8773
9195
|
const filePath = resolve7(dir, fileName);
|
|
8774
9196
|
if (!existsSync6(filePath)) {
|
|
@@ -9303,8 +9725,8 @@ init_client_ref_hashing();
|
|
|
9303
9725
|
|
|
9304
9726
|
// src/vite/discovery/client-urls-projection.ts
|
|
9305
9727
|
import { existsSync as existsSync7, readFileSync as readFileSync5 } from "node:fs";
|
|
9306
|
-
import { isAbsolute as
|
|
9307
|
-
import { normalizePath as
|
|
9728
|
+
import { isAbsolute as isAbsolute4, relative as relative6, resolve as resolve8 } from "node:path";
|
|
9729
|
+
import { normalizePath as normalizePath7, parseAst as parseAst8 } from "vite";
|
|
9308
9730
|
|
|
9309
9731
|
// src/client-urls/server-projection.ts
|
|
9310
9732
|
import * as React5 from "react";
|
|
@@ -9614,7 +10036,7 @@ import { createContext as createContext4 } from "react";
|
|
|
9614
10036
|
var OutletContext = createContext4(null);
|
|
9615
10037
|
|
|
9616
10038
|
// src/route-content-wrapper.tsx
|
|
9617
|
-
import { Component, Suspense, use, useMemo as useMemo3 } from "react";
|
|
10039
|
+
import { Component, Suspense, use as use2, useMemo as useMemo3 } from "react";
|
|
9618
10040
|
|
|
9619
10041
|
// src/outlet-provider.tsx
|
|
9620
10042
|
import {
|
|
@@ -9666,6 +10088,15 @@ function getAppVersion() {
|
|
|
9666
10088
|
init_validate_redirect_origin();
|
|
9667
10089
|
init_redirect_origin();
|
|
9668
10090
|
|
|
10091
|
+
// src/browser/defer.ts
|
|
10092
|
+
import { use } from "react";
|
|
10093
|
+
|
|
10094
|
+
// src/thenable-status.ts
|
|
10095
|
+
var SETTLED_THENABLE = Object.assign(
|
|
10096
|
+
Promise.resolve(void 0),
|
|
10097
|
+
{ status: "fulfilled", value: void 0, _debugInfo: [] }
|
|
10098
|
+
);
|
|
10099
|
+
|
|
9669
10100
|
// src/route-content-wrapper.tsx
|
|
9670
10101
|
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
9671
10102
|
import { createElement as createElement3 } from "react";
|
|
@@ -9674,7 +10105,7 @@ import { createElement as createElement3 } from "react";
|
|
|
9674
10105
|
import {
|
|
9675
10106
|
isValidElement,
|
|
9676
10107
|
startTransition as startTransition2,
|
|
9677
|
-
use as
|
|
10108
|
+
use as use3,
|
|
9678
10109
|
useCallback,
|
|
9679
10110
|
useContext as useContext7,
|
|
9680
10111
|
useEffect as useEffect5,
|
|
@@ -9684,12 +10115,6 @@ import {
|
|
|
9684
10115
|
useState as useState3
|
|
9685
10116
|
} from "react";
|
|
9686
10117
|
|
|
9687
|
-
// src/thenable-status.ts
|
|
9688
|
-
var SETTLED_THENABLE = Object.assign(
|
|
9689
|
-
Promise.resolve(void 0),
|
|
9690
|
-
{ status: "fulfilled", value: void 0, _debugInfo: [] }
|
|
9691
|
-
);
|
|
9692
|
-
|
|
9693
10118
|
// src/loader-store.ts
|
|
9694
10119
|
var EMPTY_SNAPSHOT = Object.freeze({
|
|
9695
10120
|
value: void 0,
|
|
@@ -9751,7 +10176,7 @@ import {
|
|
|
9751
10176
|
useCallback as useCallback4,
|
|
9752
10177
|
useMemo as useMemo7,
|
|
9753
10178
|
useRef as useRef11,
|
|
9754
|
-
use as
|
|
10179
|
+
use as use4,
|
|
9755
10180
|
startTransition as startTransition5
|
|
9756
10181
|
} from "react";
|
|
9757
10182
|
|
|
@@ -10395,6 +10820,9 @@ var THEME_READ = {
|
|
|
10395
10820
|
}
|
|
10396
10821
|
};
|
|
10397
10822
|
|
|
10823
|
+
// src/router/segment-resolution/prefetch-deferral.ts
|
|
10824
|
+
init_prefetch_markers();
|
|
10825
|
+
|
|
10398
10826
|
// src/cache/invalidation-order.ts
|
|
10399
10827
|
var order = globalThis[/* @__PURE__ */ Symbol.for("rangojs-router:tag-invalidation-order")] ??= { seq: 0, tags: /* @__PURE__ */ new Map(), forgotten: 0 };
|
|
10400
10828
|
var responseStarts = globalThis[/* @__PURE__ */ Symbol.for("rangojs-router:response-execution-start")] ??= /* @__PURE__ */ new WeakMap();
|
|
@@ -10542,7 +10970,10 @@ function serializeTransition(route2) {
|
|
|
10542
10970
|
}
|
|
10543
10971
|
return Object.freeze(config);
|
|
10544
10972
|
}
|
|
10545
|
-
function
|
|
10973
|
+
function indicesWhere(items, pred) {
|
|
10974
|
+
return items.flatMap((item, index) => pred(item) ? [index] : []);
|
|
10975
|
+
}
|
|
10976
|
+
function serializeRoute(route2, options) {
|
|
10546
10977
|
const loaderIds = route2.loaders.map(({ loader: loader2 }, index) => {
|
|
10547
10978
|
if (typeof loader2.$$id !== "string" || loader2.$$id.length === 0) {
|
|
10548
10979
|
throw projectionError(
|
|
@@ -10552,7 +10983,25 @@ function serializeRoute(route2) {
|
|
|
10552
10983
|
}
|
|
10553
10984
|
return loader2.$$id;
|
|
10554
10985
|
});
|
|
10555
|
-
const
|
|
10986
|
+
const loaderRevalidate = route2.loaders.map(
|
|
10987
|
+
({ loader: loader2, revalidate: revalidate2 }) => revalidate2.flatMap((entry) => {
|
|
10988
|
+
if (isHoistedRevalidateRef(entry)) return [entry.$$rangoRevalidate];
|
|
10989
|
+
if (options.hoisted) {
|
|
10990
|
+
throw new Error(
|
|
10991
|
+
`clientUrls() revalidate() on loader "${loader2.$$id}" of route "${route2.pattern}" was not hoisted to the server: call the builder's revalidate() helper with an inline function or an imported predicate.`
|
|
10992
|
+
);
|
|
10993
|
+
}
|
|
10994
|
+
return [];
|
|
10995
|
+
})
|
|
10996
|
+
);
|
|
10997
|
+
const awaitedLoaderIndices = indicesWhere(
|
|
10998
|
+
route2.loaders,
|
|
10999
|
+
({ ssr }) => ssr === false
|
|
11000
|
+
);
|
|
11001
|
+
const deferrableLoaderIndices = indicesWhere(
|
|
11002
|
+
route2.loaders,
|
|
11003
|
+
({ prefetch }) => prefetch === false
|
|
11004
|
+
);
|
|
10556
11005
|
const transition2 = serializeTransition(route2);
|
|
10557
11006
|
return Object.freeze({
|
|
10558
11007
|
id: route2.id,
|
|
@@ -10562,6 +11011,12 @@ function serializeRoute(route2) {
|
|
|
10562
11011
|
loaderIds: Object.freeze(loaderIds),
|
|
10563
11012
|
hasLoading: route2.loading !== void 0,
|
|
10564
11013
|
...awaitedLoaderIndices.length > 0 ? { awaitedLoaderIndices: Object.freeze(awaitedLoaderIndices) } : {},
|
|
11014
|
+
...deferrableLoaderIndices.length > 0 ? { deferrableLoaderIndices: Object.freeze(deferrableLoaderIndices) } : {},
|
|
11015
|
+
...loaderRevalidate.some((keys) => keys.length > 0) ? {
|
|
11016
|
+
loaderRevalidate: Object.freeze(
|
|
11017
|
+
loaderRevalidate.map((keys) => Object.freeze(keys))
|
|
11018
|
+
)
|
|
11019
|
+
} : {},
|
|
10565
11020
|
...transition2 ? { transition: transition2 } : {},
|
|
10566
11021
|
...typeof route2.transition?.when === "function" ? { transitionWhen: true } : {}
|
|
10567
11022
|
});
|
|
@@ -10582,15 +11037,24 @@ function serializeIntercept(record, index) {
|
|
|
10582
11037
|
hasLoading: record.loading !== void 0
|
|
10583
11038
|
});
|
|
10584
11039
|
}
|
|
10585
|
-
function serializeClientUrlPatterns(patterns) {
|
|
11040
|
+
function serializeClientUrlPatterns(patterns, options = {}) {
|
|
10586
11041
|
return Object.freeze({
|
|
10587
11042
|
version: 1,
|
|
10588
|
-
routes: Object.freeze(
|
|
11043
|
+
routes: Object.freeze(
|
|
11044
|
+
patterns.routes.map((route2) => serializeRoute(route2, options))
|
|
11045
|
+
),
|
|
10589
11046
|
intercepts: Object.freeze(
|
|
10590
11047
|
(patterns.intercepts ?? []).map(serializeIntercept)
|
|
10591
11048
|
)
|
|
10592
11049
|
});
|
|
10593
11050
|
}
|
|
11051
|
+
function projectClientUrlsModule(namespace, options = {}) {
|
|
11052
|
+
const definition = namespace.default;
|
|
11053
|
+
if (typeof definition !== "object" && typeof definition !== "function" || definition === null || definition.__brand !== "client-urls") {
|
|
11054
|
+
return void 0;
|
|
11055
|
+
}
|
|
11056
|
+
return serializeClientUrlPatterns(definition, options);
|
|
11057
|
+
}
|
|
10594
11058
|
|
|
10595
11059
|
// src/vite/discovery/client-urls-projection.ts
|
|
10596
11060
|
init_client_ref_hashing();
|
|
@@ -10599,7 +11063,7 @@ var debug10 = createRangoDebugger(NS.discovery);
|
|
|
10599
11063
|
function hasDefaultExport(code) {
|
|
10600
11064
|
let program;
|
|
10601
11065
|
try {
|
|
10602
|
-
program =
|
|
11066
|
+
program = parseAst8(code, { lang: "tsx" });
|
|
10603
11067
|
} catch {
|
|
10604
11068
|
return false;
|
|
10605
11069
|
}
|
|
@@ -10615,20 +11079,20 @@ function hasDefaultExport(code) {
|
|
|
10615
11079
|
}
|
|
10616
11080
|
function normalizeSource(state, id) {
|
|
10617
11081
|
const cleanId = id.split("?", 1)[0];
|
|
10618
|
-
const absoluteId =
|
|
10619
|
-
return
|
|
11082
|
+
const absoluteId = isAbsolute4(cleanId) ? cleanId : resolve8(state.projectRoot, cleanId);
|
|
11083
|
+
return normalizePath7(absoluteId);
|
|
10620
11084
|
}
|
|
10621
11085
|
function referenceId(referenceKey) {
|
|
10622
11086
|
return `${referenceKey}#default`;
|
|
10623
11087
|
}
|
|
10624
11088
|
function recordClientUrlsModule(state, code, id) {
|
|
10625
|
-
if (!code.includes("clientUrls(") || !
|
|
11089
|
+
if (!code.includes("clientUrls(") || !hasUseClientDirective(code) || !hasDefaultExport(code)) {
|
|
10626
11090
|
return;
|
|
10627
11091
|
}
|
|
10628
11092
|
const source = normalizeSource(state, id);
|
|
10629
|
-
const projectRoot =
|
|
10630
|
-
const relativeId =
|
|
10631
|
-
const outsideProject = relativeId === ".." || relativeId.startsWith("../") ||
|
|
11093
|
+
const projectRoot = normalizePath7(resolve8(state.projectRoot));
|
|
11094
|
+
const relativeId = normalizePath7(relative6(projectRoot, source));
|
|
11095
|
+
const outsideProject = relativeId === ".." || relativeId.startsWith("../") || isAbsolute4(relativeId);
|
|
10632
11096
|
const devReferenceKey = outsideProject ? `/@fs${source}` : `/${relativeId}`;
|
|
10633
11097
|
const sourceByReferenceId = state.clientUrlSourceByReferenceId ??= /* @__PURE__ */ new Map();
|
|
10634
11098
|
sourceByReferenceId.set(referenceId(devReferenceKey), source);
|
|
@@ -10672,18 +11136,19 @@ async function refreshRecordedClientUrlProjections(state, ssrEnv, serverMod) {
|
|
|
10672
11136
|
}
|
|
10673
11137
|
}
|
|
10674
11138
|
for (const [source, referenceIds] of referenceIdsBySource) {
|
|
10675
|
-
let
|
|
11139
|
+
let module;
|
|
10676
11140
|
try {
|
|
10677
|
-
|
|
11141
|
+
module = await ssrEnv.runner.import(source);
|
|
10678
11142
|
} catch {
|
|
10679
11143
|
continue;
|
|
10680
11144
|
}
|
|
10681
|
-
|
|
11145
|
+
let projection;
|
|
11146
|
+
try {
|
|
11147
|
+
projection = projectClientUrlsModule(module, { hoisted: true });
|
|
11148
|
+
} catch {
|
|
10682
11149
|
continue;
|
|
10683
11150
|
}
|
|
10684
|
-
|
|
10685
|
-
definition
|
|
10686
|
-
);
|
|
11151
|
+
if (!projection) continue;
|
|
10687
11152
|
debug10?.(
|
|
10688
11153
|
"pre-entry refresh %s -> [%s]",
|
|
10689
11154
|
source,
|
|
@@ -10738,17 +11203,24 @@ async function discoverClientUrlProjections(state, ssrEnv, serverMod) {
|
|
|
10738
11203
|
cause
|
|
10739
11204
|
);
|
|
10740
11205
|
}
|
|
10741
|
-
|
|
10742
|
-
|
|
11206
|
+
let projection;
|
|
11207
|
+
try {
|
|
11208
|
+
projection = projectClientUrlsModule(module, { hoisted: true });
|
|
11209
|
+
} catch (cause) {
|
|
11210
|
+
throw projectionError2(
|
|
11211
|
+
referenceIds[0],
|
|
11212
|
+
source,
|
|
11213
|
+
cause instanceof Error ? cause.message : String(cause),
|
|
11214
|
+
cause
|
|
11215
|
+
);
|
|
11216
|
+
}
|
|
11217
|
+
if (!projection) {
|
|
10743
11218
|
throw projectionError2(
|
|
10744
11219
|
referenceIds[0],
|
|
10745
11220
|
source,
|
|
10746
11221
|
'the module default export must be created by clientUrls() and have __brand === "client-urls"'
|
|
10747
11222
|
);
|
|
10748
11223
|
}
|
|
10749
|
-
const projection = serializeClientUrlPatterns(
|
|
10750
|
-
definition
|
|
10751
|
-
);
|
|
10752
11224
|
for (const referenceId2 of referenceIds) {
|
|
10753
11225
|
nextProjections.set(referenceId2, projection);
|
|
10754
11226
|
}
|
|
@@ -10767,13 +11239,51 @@ async function discoverClientUrlProjections(state, ssrEnv, serverMod) {
|
|
|
10767
11239
|
|
|
10768
11240
|
// src/vite/discovery/discover-routers.ts
|
|
10769
11241
|
var debug11 = createRangoDebugger(NS.discovery);
|
|
11242
|
+
var SERVER_MODULE_ID = "@rangojs/router/server";
|
|
11243
|
+
var MAX_DISCOVERY_PASSES = 3;
|
|
11244
|
+
var RUNNER_RELOADED = /* @__PURE__ */ Symbol("rango.discovery.runnerReloaded");
|
|
11245
|
+
async function runnerReloadedSince(rscEnv, serverMod) {
|
|
11246
|
+
try {
|
|
11247
|
+
return await rscEnv.runner.import(SERVER_MODULE_ID) !== serverMod;
|
|
11248
|
+
} catch {
|
|
11249
|
+
return false;
|
|
11250
|
+
}
|
|
11251
|
+
}
|
|
10770
11252
|
async function discoverRouters(state, rscEnv, ssrEnv) {
|
|
10771
|
-
|
|
10772
|
-
|
|
10773
|
-
|
|
10774
|
-
|
|
10775
|
-
|
|
10776
|
-
|
|
11253
|
+
const entryPath = state.resolvedEntryPath;
|
|
11254
|
+
if (!entryPath) return;
|
|
11255
|
+
for (let pass = 1; ; pass++) {
|
|
11256
|
+
const serverMod = await timed(
|
|
11257
|
+
debug11,
|
|
11258
|
+
"inner: import @rangojs/router/server",
|
|
11259
|
+
() => rscEnv.runner.import(SERVER_MODULE_ID)
|
|
11260
|
+
);
|
|
11261
|
+
let result;
|
|
11262
|
+
try {
|
|
11263
|
+
result = await discoverRoutersPass(
|
|
11264
|
+
state,
|
|
11265
|
+
rscEnv,
|
|
11266
|
+
ssrEnv,
|
|
11267
|
+
entryPath,
|
|
11268
|
+
serverMod
|
|
11269
|
+
);
|
|
11270
|
+
} catch (error) {
|
|
11271
|
+
if (!await runnerReloadedSince(rscEnv, serverMod)) throw error;
|
|
11272
|
+
result = RUNNER_RELOADED;
|
|
11273
|
+
}
|
|
11274
|
+
if (result !== RUNNER_RELOADED) return result;
|
|
11275
|
+
if (pass === MAX_DISCOVERY_PASSES) {
|
|
11276
|
+
throw new Error(
|
|
11277
|
+
`[rango] Route discovery did not settle: the RSC module runner reloaded during ${MAX_DISCOVERY_PASSES} consecutive discovery passes.`
|
|
11278
|
+
);
|
|
11279
|
+
}
|
|
11280
|
+
debug11?.(
|
|
11281
|
+
"inner: module runner reloaded mid-pass, redoing discovery (pass %d)",
|
|
11282
|
+
pass + 1
|
|
11283
|
+
);
|
|
11284
|
+
}
|
|
11285
|
+
}
|
|
11286
|
+
async function discoverRoutersPass(state, rscEnv, ssrEnv, entryPath, serverMod) {
|
|
10777
11287
|
await timed(
|
|
10778
11288
|
debug11,
|
|
10779
11289
|
"inner: refresh recorded client URL projections",
|
|
@@ -10782,9 +11292,10 @@ async function discoverRouters(state, rscEnv, ssrEnv) {
|
|
|
10782
11292
|
await timed(
|
|
10783
11293
|
debug11,
|
|
10784
11294
|
"inner: import entry",
|
|
10785
|
-
() => rscEnv.runner.import(
|
|
11295
|
+
() => rscEnv.runner.import(entryPath)
|
|
10786
11296
|
);
|
|
10787
|
-
|
|
11297
|
+
if (await runnerReloadedSince(rscEnv, serverMod)) return RUNNER_RELOADED;
|
|
11298
|
+
const registry = serverMod.RouterRegistry;
|
|
10788
11299
|
if (!registry || registry.size === 0) {
|
|
10789
11300
|
const discoveryErrors = [];
|
|
10790
11301
|
try {
|
|
@@ -10798,20 +11309,15 @@ async function discoverRouters(state, rscEnv, ssrEnv) {
|
|
|
10798
11309
|
for (const { context, error } of handlerErrors) {
|
|
10799
11310
|
debug11?.("caught error while resolving %s: %O", context, error);
|
|
10800
11311
|
}
|
|
10801
|
-
|
|
10802
|
-
|
|
10803
|
-
);
|
|
10804
|
-
const freshRegistry = freshServerMod.RouterRegistry;
|
|
10805
|
-
if (freshRegistry && freshRegistry.size > 0) {
|
|
10806
|
-
Object.assign(serverMod, freshServerMod);
|
|
10807
|
-
registry = freshRegistry;
|
|
11312
|
+
if (await runnerReloadedSince(rscEnv, serverMod)) {
|
|
11313
|
+
return RUNNER_RELOADED;
|
|
10808
11314
|
}
|
|
10809
11315
|
}
|
|
10810
11316
|
} catch (error) {
|
|
10811
11317
|
discoveryErrors.push({ context: "host-router discovery", error });
|
|
10812
11318
|
}
|
|
10813
11319
|
if (!registry || registry.size === 0) {
|
|
10814
|
-
throw new DiscoveryError(
|
|
11320
|
+
throw new DiscoveryError(entryPath, discoveryErrors);
|
|
10815
11321
|
}
|
|
10816
11322
|
}
|
|
10817
11323
|
await timed(
|
|
@@ -10960,6 +11466,7 @@ async function discoverRouters(state, rscEnv, ssrEnv) {
|
|
|
10960
11466
|
}
|
|
10961
11467
|
}
|
|
10962
11468
|
}
|
|
11469
|
+
if (await runnerReloadedSince(rscEnv, serverMod)) return RUNNER_RELOADED;
|
|
10963
11470
|
state.mergedRouteManifest = newMergedRouteManifest;
|
|
10964
11471
|
state.perRouterManifests = newPerRouterManifests;
|
|
10965
11472
|
state.perRouterManifestDataMap = newPerRouterManifestDataMap;
|
|
@@ -10997,7 +11504,7 @@ import { dirname as dirname4, join as join6, resolve as resolve9 } from "node:pa
|
|
|
10997
11504
|
init_debug();
|
|
10998
11505
|
|
|
10999
11506
|
// src/vite/discovery/installed-packages.ts
|
|
11000
|
-
import { createHash as
|
|
11507
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
11001
11508
|
import {
|
|
11002
11509
|
existsSync as existsSync8,
|
|
11003
11510
|
readdirSync as readdirSync3,
|
|
@@ -11014,7 +11521,7 @@ function linkTarget(path6) {
|
|
|
11014
11521
|
}
|
|
11015
11522
|
}
|
|
11016
11523
|
function digestDirectory(dir) {
|
|
11017
|
-
const hash =
|
|
11524
|
+
const hash = createHash7("sha256");
|
|
11018
11525
|
const entered = /* @__PURE__ */ new Set();
|
|
11019
11526
|
const visit = (current, prefix) => {
|
|
11020
11527
|
const real = realpathSync(current);
|
|
@@ -11727,6 +12234,17 @@ function devDiscoveryBootstrap(state) {
|
|
|
11727
12234
|
const epoch = state.devDiscoveryEpoch;
|
|
11728
12235
|
return [`globalThis.__RANGO_DEV_DISCOVERY_EPOCH = ${epoch};`];
|
|
11729
12236
|
}
|
|
12237
|
+
function clientUrlProjectionReplay(state) {
|
|
12238
|
+
const projections = [...state.clientUrlProjectionMap ?? []].sort(
|
|
12239
|
+
([a], [b]) => compareStrings(a, b)
|
|
12240
|
+
);
|
|
12241
|
+
return [
|
|
12242
|
+
`clearClientUrlProjections();`,
|
|
12243
|
+
...projections.map(
|
|
12244
|
+
([referenceId2, projection]) => `setClientUrlProjection(${JSON.stringify(referenceId2)}, ${jsonParseExpression(projection)});`
|
|
12245
|
+
)
|
|
12246
|
+
];
|
|
12247
|
+
}
|
|
11730
12248
|
function generateRoutesManifestModule(state) {
|
|
11731
12249
|
const hasManifest = state.mergedRouteManifest && Object.keys(state.mergedRouteManifest).length > 0;
|
|
11732
12250
|
const hasClientUrlModules = Boolean(state.clientUrlSourceByReferenceId?.size);
|
|
@@ -11773,17 +12291,7 @@ function generateRoutesManifestModule(state) {
|
|
|
11773
12291
|
`clearAllRouterData();`,
|
|
11774
12292
|
TRANSITION_WHEN_VALIDATION
|
|
11775
12293
|
];
|
|
11776
|
-
if (hasClientUrlModules)
|
|
11777
|
-
lines2.push(`clearClientUrlProjections();`);
|
|
11778
|
-
const projections = [...state.clientUrlProjectionMap ?? []].sort(
|
|
11779
|
-
([a], [b]) => compareStrings(a, b)
|
|
11780
|
-
);
|
|
11781
|
-
for (const [referenceId2, projection] of projections) {
|
|
11782
|
-
lines2.push(
|
|
11783
|
-
`setClientUrlProjection(${JSON.stringify(referenceId2)}, ${jsonParseExpression(projection)});`
|
|
11784
|
-
);
|
|
11785
|
-
}
|
|
11786
|
-
}
|
|
12294
|
+
if (hasClientUrlModules) lines2.push(...clientUrlProjectionReplay(state));
|
|
11787
12295
|
if (varIdx > 0) {
|
|
11788
12296
|
lines2.push(
|
|
11789
12297
|
`function __flat(r) { const o = {}; for (const [k, v] of Object.entries(r)) o[k] = typeof v === "string" ? v : v.path; return o; }`
|
|
@@ -11825,12 +12333,10 @@ function generateRoutesManifestModule(state) {
|
|
|
11825
12333
|
return lines2.join("\n");
|
|
11826
12334
|
}
|
|
11827
12335
|
const lines = [
|
|
11828
|
-
`import { ${hasClientUrlModules ? "clearClientUrlProjections, " : ""}enableTransitionWhenValidation } from "@rangojs/router/server";`,
|
|
12336
|
+
`import { ${hasClientUrlModules ? "clearClientUrlProjections, setClientUrlProjection, " : ""}enableTransitionWhenValidation } from "@rangojs/router/server";`,
|
|
11829
12337
|
TRANSITION_WHEN_VALIDATION
|
|
11830
12338
|
];
|
|
11831
|
-
if (hasClientUrlModules)
|
|
11832
|
-
lines.push(`clearClientUrlProjections();`);
|
|
11833
|
-
}
|
|
12339
|
+
if (hasClientUrlModules) lines.push(...clientUrlProjectionReplay(state));
|
|
11834
12340
|
if (!state.isBuildMode) {
|
|
11835
12341
|
const origin = state.devServerOrigin || state.devServer?.resolvedUrls?.local?.[0]?.replace(/\/$/, "") || state.devServer && `http://localhost:${state.devServer.config.server.port || 5173}`;
|
|
11836
12342
|
if (origin) {
|
|
@@ -12169,6 +12675,12 @@ var debugDiscovery = createRangoDebugger(NS.discovery);
|
|
|
12169
12675
|
var debugRoutes = createRangoDebugger(NS.routes);
|
|
12170
12676
|
var debugBuild = createRangoDebugger(NS.build);
|
|
12171
12677
|
var debugDev = createRangoDebugger(NS.dev);
|
|
12678
|
+
function modulesForFile(graph, file) {
|
|
12679
|
+
return graph.getModulesByFile(normalizePath8(file));
|
|
12680
|
+
}
|
|
12681
|
+
function isFileOutsideApp(root, file, rscGraph) {
|
|
12682
|
+
return isInSkippedScanDir(root, file) && !(rscGraph && modulesForFile(rscGraph, file)?.size);
|
|
12683
|
+
}
|
|
12172
12684
|
var loaderHookRegistered = false;
|
|
12173
12685
|
function ensureCloudflareProtocolLoaderRegistered() {
|
|
12174
12686
|
if (loaderHookRegistered) return;
|
|
@@ -12261,6 +12773,10 @@ async function createTempRscServer(state, options = {}) {
|
|
|
12261
12773
|
// Inline transition({ when }) literals become client references here
|
|
12262
12774
|
// too, or discovery would see (and reject) the plain function.
|
|
12263
12775
|
transitionWhenHoistPlugin(),
|
|
12776
|
+
// clientUrls() revalidate() predicates move to the server here too:
|
|
12777
|
+
// discovery serializes the SSR copy's markers and the RSC realm
|
|
12778
|
+
// registers the predicates the materialized stubs call.
|
|
12779
|
+
...clientUrlsRevalidateHoistPlugin(),
|
|
12264
12780
|
// Dev prerender must use dev-mode IDs (path-based) to match the workerd
|
|
12265
12781
|
// runtime. forceBuild produces hashed IDs for production bundle consistency.
|
|
12266
12782
|
exposeInternalIds(options.forceBuild ? { forceBuild: true } : void 0),
|
|
@@ -12761,6 +13277,10 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
12761
13277
|
() => propagateDiscoveryState(rscEnv)
|
|
12762
13278
|
);
|
|
12763
13279
|
} catch (err) {
|
|
13280
|
+
s.lastDiscoveryError = {
|
|
13281
|
+
message: err?.message ?? String(err),
|
|
13282
|
+
at: Date.now()
|
|
13283
|
+
};
|
|
12764
13284
|
emitDiscoveryFailure(
|
|
12765
13285
|
err,
|
|
12766
13286
|
optimizerHashBefore,
|
|
@@ -13117,6 +13637,11 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
13117
13637
|
});
|
|
13118
13638
|
if (opts?.staticRouteTypesGeneration !== false) {
|
|
13119
13639
|
const isGeneratedRouteFile = (filePath) => filePath.endsWith(".gen.ts") && (filePath.includes("named-routes.gen.ts") || filePath.includes("urls.gen.ts"));
|
|
13640
|
+
const isOutsideApp = (filePath) => isFileOutsideApp(
|
|
13641
|
+
s.projectRoot,
|
|
13642
|
+
filePath,
|
|
13643
|
+
server.environments?.rsc?.moduleGraph
|
|
13644
|
+
);
|
|
13120
13645
|
const regenerateGeneratedRouteFiles = () => {
|
|
13121
13646
|
if (s.perRouterManifests.length > 0) {
|
|
13122
13647
|
writeRouteTypesFiles(s);
|
|
@@ -13148,6 +13673,15 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
13148
13673
|
return true;
|
|
13149
13674
|
};
|
|
13150
13675
|
let routeChangeTimer;
|
|
13676
|
+
const invalidateRoutesManifestModule = (rscEnv) => {
|
|
13677
|
+
for (const virtualId of [
|
|
13678
|
+
VIRTUAL_ROUTES_MANIFEST_ID,
|
|
13679
|
+
`\0${VIRTUAL_ROUTES_MANIFEST_ID}`
|
|
13680
|
+
]) {
|
|
13681
|
+
const virtualMod = rscEnv.moduleGraph?.getModuleById?.(virtualId);
|
|
13682
|
+
if (virtualMod) rscEnv.moduleGraph.invalidateModule(virtualMod);
|
|
13683
|
+
}
|
|
13684
|
+
};
|
|
13151
13685
|
const refreshRuntimeDiscovery = async () => {
|
|
13152
13686
|
const rscEnv = server.environments?.rsc;
|
|
13153
13687
|
const hasMainRunner = !!rscEnv?.runner;
|
|
@@ -13157,6 +13691,7 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
13157
13691
|
const hmrStart = performance.now();
|
|
13158
13692
|
try {
|
|
13159
13693
|
if (hasMainRunner) {
|
|
13694
|
+
const recoveringColdStart = s.perRouterManifests.length === 0;
|
|
13160
13695
|
await timed(
|
|
13161
13696
|
debugDiscovery,
|
|
13162
13697
|
"hmr discoverRouters",
|
|
@@ -13172,6 +13707,7 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
13172
13707
|
"hmr propagateDiscoveryState",
|
|
13173
13708
|
() => propagateDiscoveryState(rscEnv)
|
|
13174
13709
|
);
|
|
13710
|
+
if (recoveringColdStart) invalidateRoutesManifestModule(rscEnv);
|
|
13175
13711
|
} else {
|
|
13176
13712
|
const tempRscEnv = await timed(
|
|
13177
13713
|
debugDiscovery,
|
|
@@ -13317,15 +13853,7 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
13317
13853
|
server.environments?.ssr,
|
|
13318
13854
|
serverMod
|
|
13319
13855
|
);
|
|
13320
|
-
|
|
13321
|
-
VIRTUAL_ROUTES_MANIFEST_ID,
|
|
13322
|
-
`\0${VIRTUAL_ROUTES_MANIFEST_ID}`
|
|
13323
|
-
]) {
|
|
13324
|
-
const virtualMod = rscEnv.moduleGraph?.getModuleById?.(virtualId);
|
|
13325
|
-
if (virtualMod) {
|
|
13326
|
-
rscEnv.moduleGraph.invalidateModule(virtualMod);
|
|
13327
|
-
}
|
|
13328
|
-
}
|
|
13856
|
+
invalidateRoutesManifestModule(rscEnv);
|
|
13329
13857
|
} catch (err) {
|
|
13330
13858
|
debugDiscovery?.(
|
|
13331
13859
|
"watcher: clientUrls projection pre-refresh failed: %s",
|
|
@@ -13351,7 +13879,7 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
13351
13879
|
"watcher: regenerated gen files (%sms)",
|
|
13352
13880
|
(performance.now() - regenStart).toFixed(1)
|
|
13353
13881
|
);
|
|
13354
|
-
if (s
|
|
13882
|
+
if (canRefreshRuntimeDiscovery(s, !!rscEnv?.runner)) {
|
|
13355
13883
|
refreshRuntimeDiscovery().catch((err) => {
|
|
13356
13884
|
console.warn(
|
|
13357
13885
|
`[rango] Runtime re-discovery error: ${err.message}`
|
|
@@ -13362,6 +13890,13 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
13362
13890
|
}, 100);
|
|
13363
13891
|
};
|
|
13364
13892
|
const handleRouteFileChange = (filePath) => {
|
|
13893
|
+
if (isOutsideApp(filePath)) {
|
|
13894
|
+
debugDiscovery?.(
|
|
13895
|
+
"watcher: skip %s (outside the discovery scan)",
|
|
13896
|
+
filePath
|
|
13897
|
+
);
|
|
13898
|
+
return;
|
|
13899
|
+
}
|
|
13365
13900
|
if (maybeHandleGeneratedRouteFileMutation(filePath)) return;
|
|
13366
13901
|
if (!filePath.endsWith(".ts") && !filePath.endsWith(".tsx") && !filePath.endsWith(".js") && !filePath.endsWith(".jsx")) {
|
|
13367
13902
|
if (s.lastDiscoveryError) {
|
|
@@ -13436,9 +13971,7 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
13436
13971
|
}
|
|
13437
13972
|
const seen = /* @__PURE__ */ new Set();
|
|
13438
13973
|
for (const file of routerSourceFiles) {
|
|
13439
|
-
const mods = rscGraph
|
|
13440
|
-
file.replaceAll("\\", "/")
|
|
13441
|
-
);
|
|
13974
|
+
const mods = modulesForFile(rscGraph, file);
|
|
13442
13975
|
if (!mods) {
|
|
13443
13976
|
debugDiscovery?.(
|
|
13444
13977
|
"watcher: clientUrls invalidation found no rsc modules for %s",
|
|
@@ -13470,7 +14003,7 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
13470
14003
|
}
|
|
13471
14004
|
s.cachedRouterFiles = void 0;
|
|
13472
14005
|
}
|
|
13473
|
-
if (s
|
|
14006
|
+
if (canRefreshRuntimeDiscovery(s, !!mainRscEnv?.runner)) {
|
|
13474
14007
|
gate.noteRouteEvent();
|
|
13475
14008
|
}
|
|
13476
14009
|
scheduleRouteRegeneration();
|
|
@@ -13488,7 +14021,7 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
13488
14021
|
server.watcher.on("add", handleRouteFileChange);
|
|
13489
14022
|
server.watcher.on("change", handleRouteFileChange);
|
|
13490
14023
|
server.watcher.on("unlink", (filePath) => {
|
|
13491
|
-
if (!isGeneratedRouteFile(filePath)) return;
|
|
14024
|
+
if (!isGeneratedRouteFile(filePath) || isOutsideApp(filePath)) return;
|
|
13492
14025
|
const hasRunner = !!server.environments?.rsc?.runner;
|
|
13493
14026
|
if (!hasRunner) return;
|
|
13494
14027
|
regenerateGeneratedRouteFiles();
|
|
@@ -14166,7 +14699,7 @@ If this is a multi-app host router, export a createHostRouter() instance and set
|
|
|
14166
14699
|
return;
|
|
14167
14700
|
try {
|
|
14168
14701
|
const source = readFileSync12(file, "utf-8");
|
|
14169
|
-
if (
|
|
14702
|
+
if (hasUseClientDirective(source)) {
|
|
14170
14703
|
return [];
|
|
14171
14704
|
}
|
|
14172
14705
|
} catch {
|
|
@@ -14175,6 +14708,7 @@ If this is a multi-app host router, export a createHostRouter() instance and set
|
|
|
14175
14708
|
});
|
|
14176
14709
|
plugins.push(createLoaderDirectiveGuardPlugin());
|
|
14177
14710
|
plugins.push(transitionWhenHoistPlugin());
|
|
14711
|
+
plugins.push(...clientUrlsRevalidateHoistPlugin());
|
|
14178
14712
|
plugins.push(createLoaderScanStubPlugin());
|
|
14179
14713
|
plugins.push(exposeActionId());
|
|
14180
14714
|
plugins.push(
|