@farm.js/core 0.1.0-beta.3 → 0.1.0-beta.5
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/agent-runtime.d.mts +2 -1
- package/dist/agent-runtime.d.ts +2 -1
- package/dist/api/route-manager.cjs +313 -10
- package/dist/api/route-manager.cjs.map +1 -1
- package/dist/api/route-manager.d.mts +3 -2
- package/dist/api/route-manager.d.ts +3 -2
- package/dist/api/route-manager.mjs +6 -5
- package/dist/api/runtime.cjs +313 -10
- package/dist/api/runtime.cjs.map +1 -1
- package/dist/api/runtime.d.mts +2 -1
- package/dist/api/runtime.d.ts +2 -1
- package/dist/api/runtime.mjs +4 -3
- package/dist/api.cjs +642 -57
- package/dist/api.cjs.map +1 -1
- package/dist/api.d.mts +3 -2
- package/dist/api.d.ts +3 -2
- package/dist/api.mjs +29 -9
- package/dist/{app-DOKxo-LH.d.ts → app-BjN-da13.d.ts} +38 -3
- package/dist/{app-BB3Iu3xh.d.mts → app-CakAr8Be.d.mts} +38 -3
- package/dist/app-markdown.d.mts +2 -1
- package/dist/app-markdown.d.ts +2 -1
- package/dist/cache.cjs +395 -12
- package/dist/cache.cjs.map +1 -1
- package/dist/cache.d.mts +100 -6
- package/dist/cache.d.ts +100 -6
- package/dist/cache.mjs +8 -2
- package/dist/{chunk-XUBZ7JI4.mjs → chunk-2CUKEMVR.mjs} +187 -16
- package/dist/chunk-2CUKEMVR.mjs.map +1 -0
- package/dist/{chunk-OHC6VCDI.mjs → chunk-2NHCNRF6.mjs} +521 -42
- package/dist/chunk-2NHCNRF6.mjs.map +1 -0
- package/dist/{chunk-6WXJ54TC.mjs → chunk-65A7QIKI.mjs} +5 -5
- package/dist/{chunk-6WXJ54TC.mjs.map → chunk-65A7QIKI.mjs.map} +1 -1
- package/dist/{chunk-5QH4IKY3.mjs → chunk-7N62DNSO.mjs} +2 -2
- package/dist/{chunk-XJSHJN4M.mjs → chunk-A2LUXHD2.mjs} +593 -49
- package/dist/chunk-A2LUXHD2.mjs.map +1 -0
- package/dist/chunk-ALCLXXTY.mjs +187 -0
- package/dist/chunk-ALCLXXTY.mjs.map +1 -0
- package/dist/{chunk-CSU4KJJF.mjs → chunk-C2ROET2V.mjs} +2 -2
- package/dist/{chunk-JNYVN7YP.mjs → chunk-EEABSBKK.mjs} +2 -2
- package/dist/{chunk-JNYVN7YP.mjs.map → chunk-EEABSBKK.mjs.map} +1 -1
- package/dist/{chunk-BIOIOWXZ.mjs → chunk-HNIQFZKB.mjs} +2 -2
- package/dist/{chunk-MH6FKW2I.mjs → chunk-J5YWQVI5.mjs} +4 -4
- package/dist/chunk-J5YWQVI5.mjs.map +1 -0
- package/dist/{chunk-G5I34UA6.mjs → chunk-JDEOUK5V.mjs} +4 -4
- package/dist/{chunk-T543TMFY.mjs → chunk-NM3CRAAL.mjs} +3 -2
- package/dist/chunk-NM3CRAAL.mjs.map +1 -0
- package/dist/{chunk-LWMGIEJA.mjs → chunk-PFE6GMNE.mjs} +47 -37
- package/dist/chunk-PFE6GMNE.mjs.map +1 -0
- package/dist/{chunk-6VS6CKAV.mjs → chunk-QM746KUO.mjs} +8 -1
- package/dist/chunk-QM746KUO.mjs.map +1 -0
- package/dist/{chunk-5FW6PQ3J.mjs → chunk-QTZZ2ISQ.mjs} +41 -16
- package/dist/chunk-QTZZ2ISQ.mjs.map +1 -0
- package/dist/{chunk-SHRJG6OG.mjs → chunk-RBRLLZL5.mjs} +18 -3
- package/dist/chunk-RBRLLZL5.mjs.map +1 -0
- package/dist/{chunk-NRRFGX45.mjs → chunk-TQAEEJB4.mjs} +3 -3
- package/dist/{chunk-45LKHSHJ.mjs → chunk-UB5UOSHB.mjs} +24 -12
- package/dist/chunk-UB5UOSHB.mjs.map +1 -0
- package/dist/chunk-V3XURYJO.mjs +756 -0
- package/dist/chunk-V3XURYJO.mjs.map +1 -0
- package/dist/{chunk-HZYXGV4K.mjs → chunk-VY2UYN5R.mjs} +24 -4
- package/dist/chunk-VY2UYN5R.mjs.map +1 -0
- package/dist/{chunk-C33RALN7.mjs → chunk-W2CRQFF6.mjs} +79 -15
- package/dist/chunk-W2CRQFF6.mjs.map +1 -0
- package/dist/{chunk-LG3YINQN.mjs → chunk-Z5CQMP54.mjs} +3 -3
- package/dist/{client-DiViK9yK.d.mts → client-BT1mFQas.d.mts} +23 -4
- package/dist/{client-DpEBJbts.d.ts → client-Nn0q4eO4.d.ts} +23 -4
- package/dist/{client-plugins-CTnsZz_A.d.ts → client-plugins-Cw4qUGsw.d.ts} +6 -0
- package/dist/{client-plugins-Cnr0D3kk.d.mts → client-plugins-DQQ1adXM.d.mts} +6 -0
- package/dist/client-plugins.d.mts +2 -1
- package/dist/client-plugins.d.ts +2 -1
- package/dist/client.cjs +665 -82
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.mts +71 -5
- package/dist/client.d.ts +71 -5
- package/dist/client.mjs +10 -7
- package/dist/config.d.mts +2 -1
- package/dist/config.d.ts +2 -1
- package/dist/{devtools-HE4FTUDN.mjs → devtools-LVC3VB5P.mjs} +4 -4
- package/dist/docs.cjs +11 -1
- package/dist/docs.cjs.map +1 -1
- package/dist/docs.mjs +4 -4
- package/dist/index.cjs +2113 -198
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +16 -16
- package/dist/index.d.ts +16 -16
- package/dist/index.mjs +49 -21
- package/dist/index.mjs.map +1 -1
- package/dist/integrations.d.mts +2 -1
- package/dist/integrations.d.ts +2 -1
- package/dist/internal/build-runtime.cjs +1455 -90
- package/dist/internal/build-runtime.cjs.map +1 -1
- package/dist/internal/build-runtime.d.mts +4 -3
- package/dist/internal/build-runtime.d.ts +4 -3
- package/dist/internal/build-runtime.mjs +15 -14
- package/dist/internal/config-runtime.cjs +12 -1
- package/dist/internal/config-runtime.cjs.map +1 -1
- package/dist/internal/config-runtime.d.mts +3 -2
- package/dist/internal/config-runtime.d.ts +3 -2
- package/dist/internal/config-runtime.mjs +3 -3
- package/dist/internal/production-runtime.cjs +282 -6
- package/dist/internal/production-runtime.cjs.map +1 -1
- package/dist/internal/production-runtime.d.mts +4 -4
- package/dist/internal/production-runtime.d.ts +4 -4
- package/dist/internal/production-runtime.mjs +4 -2
- package/dist/{metadata-eoVmHoyv.d.ts → metadata-BAPg_Nmo.d.ts} +1 -1
- package/dist/{metadata-Dp8AdvsB.d.mts → metadata-_6i9oFG3.d.mts} +1 -1
- package/dist/middleware.d.mts +4 -3
- package/dist/middleware.d.ts +4 -3
- package/dist/navigation.cjs +40 -15
- package/dist/navigation.cjs.map +1 -1
- package/dist/navigation.mjs +2 -2
- package/dist/plugin.cjs +913 -53
- package/dist/plugin.cjs.map +1 -1
- package/dist/plugin.d.mts +2 -1
- package/dist/plugin.d.ts +2 -1
- package/dist/plugin.mjs +11 -10
- package/dist/{production-runtime-BqTnUTai.d.ts → production-runtime-BoJDc5mc.d.ts} +1 -1
- package/dist/{production-runtime-DtDdG9fc.d.mts → production-runtime-DPfgMV9Y.d.mts} +1 -1
- package/dist/routes.cjs +276 -6
- package/dist/routes.cjs.map +1 -1
- package/dist/routes.d.mts +1 -1
- package/dist/routes.d.ts +1 -1
- package/dist/routes.mjs +3 -3
- package/dist/{runtime-C1B7pSGT.d.mts → runtime-9nQjVM7X.d.mts} +8 -9
- package/dist/{runtime-CdPHt0bv.d.ts → runtime-DgeS2skB.d.ts} +8 -9
- package/dist/server-action-security.cjs +28 -10
- package/dist/server-action-security.cjs.map +1 -1
- package/dist/server-action-security.d.mts +2 -1
- package/dist/server-action-security.d.ts +2 -1
- package/dist/server-action-security.mjs +2 -2
- package/dist/server-fn-client.d.mts +1 -0
- package/dist/server-fn-client.d.ts +1 -0
- package/dist/server-fn.cjs +785 -3
- package/dist/server-fn.cjs.map +1 -1
- package/dist/server-fn.d.mts +10 -1
- package/dist/server-fn.d.ts +10 -1
- package/dist/server-fn.mjs +6 -3
- package/dist/server-plugins.d.mts +3 -2
- package/dist/server-plugins.d.ts +3 -2
- package/dist/server-query-client.cjs +279 -8
- package/dist/server-query-client.cjs.map +1 -1
- package/dist/server-query-client.mjs +4 -4
- package/dist/server-query.cjs +381 -10
- package/dist/server-query.cjs.map +1 -1
- package/dist/server-query.mjs +5 -5
- package/dist/server.cjs +1086 -76
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.mts +8 -7
- package/dist/server.d.ts +8 -7
- package/dist/server.mjs +31 -16
- package/dist/server.mjs.map +1 -1
- package/dist/testing.cjs +341 -20
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.mts +3 -2
- package/dist/testing.d.ts +3 -2
- package/dist/testing.mjs +7 -6
- package/dist/testing.mjs.map +1 -1
- package/dist/transport-BmbGTXA5.d.mts +49 -0
- package/dist/transport-BmbGTXA5.d.ts +49 -0
- package/dist/{utils-8USa5BiY.d.mts → utils-CHXlMDkg.d.mts} +1 -1
- package/dist/{utils-DKJb6K6G.d.ts → utils-Drsyz1Vj.d.ts} +1 -1
- package/dist/version.cjs +1 -1
- package/dist/version.cjs.map +1 -1
- package/dist/version.mjs +1 -1
- package/dist/vite.cjs +914 -54
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.d.mts +2 -1
- package/dist/vite.d.ts +2 -1
- package/dist/vite.mjs +11 -10
- package/package.json +1 -1
- package/types/api.d.ts +44 -0
- package/types/client.d.ts +85 -4
- package/dist/chunk-45LKHSHJ.mjs.map +0 -1
- package/dist/chunk-5FW6PQ3J.mjs.map +0 -1
- package/dist/chunk-6VS6CKAV.mjs.map +0 -1
- package/dist/chunk-C33RALN7.mjs.map +0 -1
- package/dist/chunk-GZWT6VI5.mjs +0 -382
- package/dist/chunk-GZWT6VI5.mjs.map +0 -1
- package/dist/chunk-HZYXGV4K.mjs.map +0 -1
- package/dist/chunk-LWMGIEJA.mjs.map +0 -1
- package/dist/chunk-MH6FKW2I.mjs.map +0 -1
- package/dist/chunk-OHC6VCDI.mjs.map +0 -1
- package/dist/chunk-SHRJG6OG.mjs.map +0 -1
- package/dist/chunk-T543TMFY.mjs.map +0 -1
- package/dist/chunk-XJSHJN4M.mjs.map +0 -1
- package/dist/chunk-XUBZ7JI4.mjs.map +0 -1
- /package/dist/{chunk-5QH4IKY3.mjs.map → chunk-7N62DNSO.mjs.map} +0 -0
- /package/dist/{chunk-CSU4KJJF.mjs.map → chunk-C2ROET2V.mjs.map} +0 -0
- /package/dist/{chunk-BIOIOWXZ.mjs.map → chunk-HNIQFZKB.mjs.map} +0 -0
- /package/dist/{chunk-G5I34UA6.mjs.map → chunk-JDEOUK5V.mjs.map} +0 -0
- /package/dist/{chunk-NRRFGX45.mjs.map → chunk-TQAEEJB4.mjs.map} +0 -0
- /package/dist/{chunk-LG3YINQN.mjs.map → chunk-Z5CQMP54.mjs.map} +0 -0
- /package/dist/{devtools-HE4FTUDN.mjs.map → devtools-LVC3VB5P.mjs.map} +0 -0
|
@@ -42,7 +42,7 @@ import {
|
|
|
42
42
|
} from "./chunk-GY2STC2S.mjs";
|
|
43
43
|
import {
|
|
44
44
|
resolveServerActionsConfig
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-UB5UOSHB.mjs";
|
|
46
46
|
import {
|
|
47
47
|
createMarkdownMirrorResponse,
|
|
48
48
|
resolveMarkdownConfig
|
|
@@ -91,7 +91,7 @@ import {
|
|
|
91
91
|
discoverProgrammaticRoutePaths,
|
|
92
92
|
findProgrammaticRouteFiles,
|
|
93
93
|
loadProgrammaticRouteManifests
|
|
94
|
-
} from "./chunk-
|
|
94
|
+
} from "./chunk-Z5CQMP54.mjs";
|
|
95
95
|
import {
|
|
96
96
|
_runWithFarmI18nRequest,
|
|
97
97
|
_setDefaultFarmI18nRuntime,
|
|
@@ -115,7 +115,7 @@ import {
|
|
|
115
115
|
parseProgrammaticRouteModuleId,
|
|
116
116
|
parseProgrammaticRoutePath,
|
|
117
117
|
scanProgrammaticPagePaths
|
|
118
|
-
} from "./chunk-
|
|
118
|
+
} from "./chunk-C2ROET2V.mjs";
|
|
119
119
|
import {
|
|
120
120
|
resolveFarmRouteContext,
|
|
121
121
|
withFarmRouteContext
|
|
@@ -142,7 +142,7 @@ import {
|
|
|
142
142
|
} from "./chunk-RHIFZZUI.mjs";
|
|
143
143
|
import {
|
|
144
144
|
FARM_VERSION
|
|
145
|
-
} from "./chunk-
|
|
145
|
+
} from "./chunk-EEABSBKK.mjs";
|
|
146
146
|
import {
|
|
147
147
|
FARM_DEPLOYMENT_ID_HEADER,
|
|
148
148
|
createFarmDeploymentCookie,
|
|
@@ -161,10 +161,11 @@ import {
|
|
|
161
161
|
stripFarmLocaleFromPathname
|
|
162
162
|
} from "./chunk-44ZCFSKE.mjs";
|
|
163
163
|
import {
|
|
164
|
+
configureFarmCache,
|
|
164
165
|
createFarmCacheKey,
|
|
165
166
|
getFarmDataCache,
|
|
166
167
|
normalizeRevalidatePath
|
|
167
|
-
} from "./chunk-
|
|
168
|
+
} from "./chunk-V3XURYJO.mjs";
|
|
168
169
|
import {
|
|
169
170
|
configureFarmObservability,
|
|
170
171
|
emitFarmEvent
|
|
@@ -778,6 +779,76 @@ async function readAltText(filePath) {
|
|
|
778
779
|
}
|
|
779
780
|
__name(readAltText, "readAltText");
|
|
780
781
|
|
|
782
|
+
// src/routing/route-slots.ts
|
|
783
|
+
var SLOT_SEGMENT = /^@([A-Za-z][A-Za-z0-9_-]*)$/;
|
|
784
|
+
function parseRouteSlotFile(filePath) {
|
|
785
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
786
|
+
const parts = normalized.split("/").filter(Boolean);
|
|
787
|
+
const fileName = parts.at(-1) ?? "";
|
|
788
|
+
const baseName = fileName.replace(/\.(tsx?|jsx?)$/, "");
|
|
789
|
+
if (baseName !== "page" && baseName !== "default") return null;
|
|
790
|
+
const slotIndex = parts.findIndex((part) => SLOT_SEGMENT.test(part));
|
|
791
|
+
if (slotIndex < 0) return null;
|
|
792
|
+
if (parts.slice(slotIndex + 1, -1).some((part) => SLOT_SEGMENT.test(part))) {
|
|
793
|
+
throw new Error(`Nested route slots are not supported in "${filePath}"`);
|
|
794
|
+
}
|
|
795
|
+
const slotMatch = parts[slotIndex].match(SLOT_SEGMENT);
|
|
796
|
+
const name = slotMatch?.[1];
|
|
797
|
+
if (!name) return null;
|
|
798
|
+
const ownerParts = parts.slice(0, slotIndex);
|
|
799
|
+
const contentParts = parts.slice(slotIndex + 1, -1);
|
|
800
|
+
const marker = parseInterceptionMarker(contentParts[0]);
|
|
801
|
+
let targetBase = ownerParts;
|
|
802
|
+
let targetParts = contentParts;
|
|
803
|
+
if (marker) {
|
|
804
|
+
targetBase = marker.root === true ? [] : ownerParts.slice(0, Math.max(0, ownerParts.length - marker.up));
|
|
805
|
+
targetParts = [...marker.remainder ? [marker.remainder] : [], ...contentParts.slice(1)];
|
|
806
|
+
}
|
|
807
|
+
const ownerFile = [...ownerParts, "layout.tsx"].join("/");
|
|
808
|
+
const routeFile = [
|
|
809
|
+
...baseName === "default" ? ownerParts : targetBase,
|
|
810
|
+
...baseName === "default" ? [] : targetParts,
|
|
811
|
+
"page.tsx"
|
|
812
|
+
].join("/");
|
|
813
|
+
return {
|
|
814
|
+
name,
|
|
815
|
+
ownerRoute: parseRoutePath(ownerFile || "layout.tsx"),
|
|
816
|
+
route: parseRoutePath(routeFile || "page.tsx"),
|
|
817
|
+
interception: marker !== null,
|
|
818
|
+
fallback: baseName === "default"
|
|
819
|
+
};
|
|
820
|
+
}
|
|
821
|
+
__name(parseRouteSlotFile, "parseRouteSlotFile");
|
|
822
|
+
function createRouteSlotContainerId(name, ownerPattern) {
|
|
823
|
+
const owner = ownerPattern === "/" ? "root" : ownerPattern.replace(/^\//, "").replace(/[^A-Za-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
824
|
+
return `__farm_slot_${name}_${owner || "root"}__`;
|
|
825
|
+
}
|
|
826
|
+
__name(createRouteSlotContainerId, "createRouteSlotContainerId");
|
|
827
|
+
function parseInterceptionMarker(segment) {
|
|
828
|
+
if (!segment) return null;
|
|
829
|
+
if (segment.startsWith("(...)")) {
|
|
830
|
+
return {
|
|
831
|
+
up: 0,
|
|
832
|
+
root: true,
|
|
833
|
+
remainder: segment.slice(5)
|
|
834
|
+
};
|
|
835
|
+
}
|
|
836
|
+
if (segment.startsWith("(.)")) {
|
|
837
|
+
return {
|
|
838
|
+
up: 0,
|
|
839
|
+
remainder: segment.slice(3)
|
|
840
|
+
};
|
|
841
|
+
}
|
|
842
|
+
let remainder = segment;
|
|
843
|
+
let up = 0;
|
|
844
|
+
while (remainder.startsWith("(..)")) {
|
|
845
|
+
up += 1;
|
|
846
|
+
remainder = remainder.slice(4);
|
|
847
|
+
}
|
|
848
|
+
return up > 0 ? { up, remainder } : null;
|
|
849
|
+
}
|
|
850
|
+
__name(parseInterceptionMarker, "parseInterceptionMarker");
|
|
851
|
+
|
|
781
852
|
// src/routing/route-manager.ts
|
|
782
853
|
function routeSpecificity(entry) {
|
|
783
854
|
return entry.route.segments.reduce((score, segment) => {
|
|
@@ -791,6 +862,7 @@ var _RouteManager = class _RouteManager {
|
|
|
791
862
|
constructor(config, viteServer) {
|
|
792
863
|
this.routes = /* @__PURE__ */ new Map();
|
|
793
864
|
this.layouts = /* @__PURE__ */ new Map();
|
|
865
|
+
this.routeSlots = /* @__PURE__ */ new Map();
|
|
794
866
|
this.loadings = /* @__PURE__ */ new Map();
|
|
795
867
|
this.errors = /* @__PURE__ */ new Map();
|
|
796
868
|
this.metadataImages = /* @__PURE__ */ new Map();
|
|
@@ -806,6 +878,7 @@ var _RouteManager = class _RouteManager {
|
|
|
806
878
|
async discoverRoutes() {
|
|
807
879
|
this.routes.clear();
|
|
808
880
|
this.layouts.clear();
|
|
881
|
+
this.routeSlots.clear();
|
|
809
882
|
this.loadings.clear();
|
|
810
883
|
this.errors.clear();
|
|
811
884
|
this.metadataImages.clear();
|
|
@@ -816,6 +889,13 @@ var _RouteManager = class _RouteManager {
|
|
|
816
889
|
await this.discoverFileRoutes(source);
|
|
817
890
|
await this.discoverProgrammaticRoutes(source);
|
|
818
891
|
}
|
|
892
|
+
for (const slot of this.routeSlots.values()) {
|
|
893
|
+
if (slot.interception && !this.routes.has(slot.pattern)) {
|
|
894
|
+
throw new Error(
|
|
895
|
+
`Intercepting route slot "${slot.name}" targets "${slot.pattern}", but no canonical page exists for that URL`
|
|
896
|
+
);
|
|
897
|
+
}
|
|
898
|
+
}
|
|
819
899
|
this.routes = new Map(
|
|
820
900
|
Array.from(this.routes.entries()).sort(
|
|
821
901
|
([, left], [, right]) => routeSpecificity(right) - routeSpecificity(left)
|
|
@@ -831,7 +911,7 @@ var _RouteManager = class _RouteManager {
|
|
|
831
911
|
/**
|
|
832
912
|
* Find matching route for a given URL path
|
|
833
913
|
*/
|
|
834
|
-
matchRoute(pathname) {
|
|
914
|
+
matchRoute(pathname, options = {}) {
|
|
835
915
|
const routePathname = this.toRoutePathname(pathname);
|
|
836
916
|
const normalizedPath = routePathname === "/" ? "/" : routePathname.replace(/\/$/, "");
|
|
837
917
|
let matchedRoute = null;
|
|
@@ -845,10 +925,12 @@ var _RouteManager = class _RouteManager {
|
|
|
845
925
|
}
|
|
846
926
|
}
|
|
847
927
|
const layouts = this.findMatchingLayouts(normalizedPath);
|
|
928
|
+
const slots = this.findMatchingRouteSlots(normalizedPath, options.interceptFrom);
|
|
848
929
|
return {
|
|
849
930
|
route: matchedRoute,
|
|
850
931
|
params,
|
|
851
|
-
layouts
|
|
932
|
+
layouts,
|
|
933
|
+
slots
|
|
852
934
|
};
|
|
853
935
|
}
|
|
854
936
|
/**
|
|
@@ -863,6 +945,9 @@ var _RouteManager = class _RouteManager {
|
|
|
863
945
|
getLayouts() {
|
|
864
946
|
return new Map(this.layouts);
|
|
865
947
|
}
|
|
948
|
+
getRouteSlots() {
|
|
949
|
+
return new Map(this.routeSlots);
|
|
950
|
+
}
|
|
866
951
|
/** Resolve route rules, inherited layouts, and the page export in precedence order. */
|
|
867
952
|
async resolveRouteRuntimeConfig(pattern) {
|
|
868
953
|
const routeEntry = this.routes.get(pattern);
|
|
@@ -1021,7 +1106,22 @@ var _RouteManager = class _RouteManager {
|
|
|
1021
1106
|
pattern: entry.pattern,
|
|
1022
1107
|
modulePath: toUrlPath(entry.modulePath)
|
|
1023
1108
|
}));
|
|
1024
|
-
|
|
1109
|
+
const slots = Array.from(this.routeSlots.values()).map((entry) => {
|
|
1110
|
+
const metadata = getClientModuleMetadata(entry.modulePath, projectRoot);
|
|
1111
|
+
return {
|
|
1112
|
+
name: entry.name,
|
|
1113
|
+
ownerPattern: entry.ownerPattern,
|
|
1114
|
+
pattern: entry.pattern,
|
|
1115
|
+
modulePath: toUrlPath(entry.modulePath),
|
|
1116
|
+
containerId: entry.containerId,
|
|
1117
|
+
interception: entry.interception,
|
|
1118
|
+
fallback: entry.fallback,
|
|
1119
|
+
shouldHydrate: metadata.shouldHydrate,
|
|
1120
|
+
isClientComponent: metadata.isClientComponent,
|
|
1121
|
+
segments: entry.route.segments
|
|
1122
|
+
};
|
|
1123
|
+
});
|
|
1124
|
+
return { routes, layouts, slots };
|
|
1025
1125
|
}
|
|
1026
1126
|
/**
|
|
1027
1127
|
* Load a route module dynamically
|
|
@@ -1098,6 +1198,7 @@ var _RouteManager = class _RouteManager {
|
|
|
1098
1198
|
async discoverFileRoutes(source) {
|
|
1099
1199
|
const appDir = resolveAppPath(source.root, source.srcDir, "app");
|
|
1100
1200
|
const pageFiles = await safeGlobFiles("**/page.{ts,tsx,js,jsx,md,mdx}", appDir);
|
|
1201
|
+
const slotDefaultFiles = await safeGlobFiles("**/@*/**/default.{ts,tsx,js,jsx}", appDir);
|
|
1101
1202
|
const layoutFiles = await safeGlobFiles("**/layout.{ts,tsx,js,jsx}", appDir);
|
|
1102
1203
|
const loadingFiles = await safeGlobFiles("**/loading.{ts,tsx,js,jsx}", appDir);
|
|
1103
1204
|
const errorFiles = await safeGlobFiles("**/error.{ts,tsx,js,jsx}", appDir);
|
|
@@ -1106,7 +1207,7 @@ var _RouteManager = class _RouteManager {
|
|
|
1106
1207
|
appDir
|
|
1107
1208
|
);
|
|
1108
1209
|
for (const [kind, files, target] of [
|
|
1109
|
-
["page", pageFiles, this.routes],
|
|
1210
|
+
["page", pageFiles.filter((file) => parseRouteSlotFile(file) === null), this.routes],
|
|
1110
1211
|
["layout", layoutFiles, this.layouts],
|
|
1111
1212
|
["loading", loadingFiles, this.loadings],
|
|
1112
1213
|
["error", errorFiles, this.errors]
|
|
@@ -1130,6 +1231,32 @@ var _RouteManager = class _RouteManager {
|
|
|
1130
1231
|
});
|
|
1131
1232
|
}
|
|
1132
1233
|
}
|
|
1234
|
+
for (const file of [...pageFiles, ...slotDefaultFiles]) {
|
|
1235
|
+
const slot = parseRouteSlotFile(file);
|
|
1236
|
+
if (!slot) continue;
|
|
1237
|
+
const modulePath = path3.join(appDir, file);
|
|
1238
|
+
const pattern = this.createRoutePattern(slot.route);
|
|
1239
|
+
const ownerPattern = this.createRoutePattern(slot.ownerRoute);
|
|
1240
|
+
const key = `${ownerPattern}:${slot.name}:${slot.interception ? "intercept" : "slot"}:${slot.fallback ? "default" : pattern}`;
|
|
1241
|
+
const existing = this.routeSlots.get(key);
|
|
1242
|
+
if (existing?.sourceRoot === source.root) {
|
|
1243
|
+
throw new Error(
|
|
1244
|
+
`Duplicate route slot "${slot.name}" for "${pattern}". Found both ${existing.modulePath} and ${modulePath}.`
|
|
1245
|
+
);
|
|
1246
|
+
}
|
|
1247
|
+
this.routeSlots.set(key, {
|
|
1248
|
+
route: slot.route,
|
|
1249
|
+
modulePath,
|
|
1250
|
+
pattern,
|
|
1251
|
+
source: "file",
|
|
1252
|
+
sourceRoot: source.root,
|
|
1253
|
+
name: slot.name,
|
|
1254
|
+
ownerPattern,
|
|
1255
|
+
interception: slot.interception,
|
|
1256
|
+
fallback: slot.fallback,
|
|
1257
|
+
containerId: createRouteSlotContainerId(slot.name, ownerPattern)
|
|
1258
|
+
});
|
|
1259
|
+
}
|
|
1133
1260
|
for (const file of metadataImageFiles) {
|
|
1134
1261
|
const fileBase = path3.basename(file, path3.extname(file));
|
|
1135
1262
|
const kind = fileBase === "twitter-image" ? "twitter" : "opengraph";
|
|
@@ -1255,6 +1382,71 @@ var _RouteManager = class _RouteManager {
|
|
|
1255
1382
|
}
|
|
1256
1383
|
return matchingLayouts;
|
|
1257
1384
|
}
|
|
1385
|
+
findMatchingRouteSlots(pathname, interceptFrom) {
|
|
1386
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1387
|
+
for (const entry of this.routeSlots.values()) {
|
|
1388
|
+
if (!this.matchesRoutePrefix(pathname, entry.ownerPattern)) continue;
|
|
1389
|
+
const key = `${entry.ownerPattern}:${entry.name}`;
|
|
1390
|
+
const entries = groups.get(key) ?? [];
|
|
1391
|
+
entries.push(entry);
|
|
1392
|
+
groups.set(key, entries);
|
|
1393
|
+
}
|
|
1394
|
+
const normalizedFrom = interceptFrom ? this.toRoutePathname(new URL(interceptFrom, "http://farm.local").pathname) : void 0;
|
|
1395
|
+
const matches = [];
|
|
1396
|
+
for (const entries of groups.values()) {
|
|
1397
|
+
const candidates = entries.filter((entry) => !entry.fallback).filter(
|
|
1398
|
+
(entry) => !entry.interception || normalizedFrom !== void 0 && this.matchesRoutePrefix(normalizedFrom, entry.ownerPattern)
|
|
1399
|
+
).map((entry) => ({
|
|
1400
|
+
entry,
|
|
1401
|
+
match: matchRoute(pathname, entry.route.segments)
|
|
1402
|
+
})).filter((candidate) => candidate.match.matches).sort((left, right) => {
|
|
1403
|
+
if (left.entry.interception !== right.entry.interception) {
|
|
1404
|
+
return left.entry.interception ? -1 : 1;
|
|
1405
|
+
}
|
|
1406
|
+
return routeSpecificity(right.entry) - routeSpecificity(left.entry);
|
|
1407
|
+
});
|
|
1408
|
+
const selected = candidates[0];
|
|
1409
|
+
if (selected) {
|
|
1410
|
+
matches.push({
|
|
1411
|
+
name: selected.entry.name,
|
|
1412
|
+
ownerPattern: selected.entry.ownerPattern,
|
|
1413
|
+
containerId: selected.entry.containerId,
|
|
1414
|
+
interception: selected.entry.interception,
|
|
1415
|
+
fallback: false,
|
|
1416
|
+
route: selected.entry,
|
|
1417
|
+
params: selected.match.params
|
|
1418
|
+
});
|
|
1419
|
+
continue;
|
|
1420
|
+
}
|
|
1421
|
+
const fallback = entries.find((entry) => entry.fallback);
|
|
1422
|
+
if (fallback) {
|
|
1423
|
+
matches.push({
|
|
1424
|
+
name: fallback.name,
|
|
1425
|
+
ownerPattern: fallback.ownerPattern,
|
|
1426
|
+
containerId: fallback.containerId,
|
|
1427
|
+
interception: false,
|
|
1428
|
+
fallback: true,
|
|
1429
|
+
route: fallback,
|
|
1430
|
+
params: {}
|
|
1431
|
+
});
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
return matches.sort((left, right) => {
|
|
1435
|
+
const ownerDifference = left.route.route.segments.length - right.route.route.segments.length;
|
|
1436
|
+
return ownerDifference || left.name.localeCompare(right.name);
|
|
1437
|
+
});
|
|
1438
|
+
}
|
|
1439
|
+
matchesRoutePrefix(pathname, pattern) {
|
|
1440
|
+
if (pattern === "/") return true;
|
|
1441
|
+
const patternSegments = parseRoutePath(`${pattern}/page.tsx`).segments;
|
|
1442
|
+
const pathSegments = pathname.split("/").filter(Boolean);
|
|
1443
|
+
if (patternSegments.length > pathSegments.length) return false;
|
|
1444
|
+
for (let index = 0; index < patternSegments.length; index++) {
|
|
1445
|
+
const segment = patternSegments[index];
|
|
1446
|
+
if (!segment.isDynamic && segment.segment !== pathSegments[index]) return false;
|
|
1447
|
+
}
|
|
1448
|
+
return true;
|
|
1449
|
+
}
|
|
1258
1450
|
findNearestBoundary(pathname, boundaries) {
|
|
1259
1451
|
const normalizedPath = pathname === "/" ? "/" : pathname.replace(/\/$/, "");
|
|
1260
1452
|
const pathSegments = normalizedPath.split("/").filter(Boolean);
|
|
@@ -1659,7 +1851,9 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
1659
1851
|
async runWithRequestContext(request, fn) {
|
|
1660
1852
|
return _runWithCurrentRequest(
|
|
1661
1853
|
request,
|
|
1662
|
-
() => this.i18nRuntime?.config.enabled ? _runWithFarmI18nRequest(this.i18nRuntime, request, fn, {
|
|
1854
|
+
() => this.i18nRuntime?.config.enabled ? _runWithFarmI18nRequest(this.i18nRuntime, request, fn, {
|
|
1855
|
+
redirect: false
|
|
1856
|
+
}) : fn()
|
|
1663
1857
|
);
|
|
1664
1858
|
}
|
|
1665
1859
|
async resolveRouteContext(input) {
|
|
@@ -1682,11 +1876,11 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
1682
1876
|
/**
|
|
1683
1877
|
* Check if a path should be served from SSG cache
|
|
1684
1878
|
*/
|
|
1685
|
-
shouldServeSSG(pathname) {
|
|
1879
|
+
async shouldServeSSG(pathname) {
|
|
1686
1880
|
const ssgPage = matchSSGPage(pathname, this.ssgManifest);
|
|
1687
1881
|
if (!ssgPage) return null;
|
|
1688
|
-
const cached = this.getCachedSSGPage(pathname);
|
|
1689
|
-
if (cached && this.dataCache.
|
|
1882
|
+
const cached = await this.getCachedSSGPage(pathname);
|
|
1883
|
+
if (cached && await this.dataCache.isStaleAsync(cached)) {
|
|
1690
1884
|
this.regenerateSSGPage(ssgPage);
|
|
1691
1885
|
}
|
|
1692
1886
|
return ssgPage;
|
|
@@ -1698,12 +1892,12 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
1698
1892
|
return createFarmCacheKey(["ppr", normalizeRevalidatePath(pathname), search]);
|
|
1699
1893
|
}
|
|
1700
1894
|
getCachedSSGPage(urlPath) {
|
|
1701
|
-
return this.dataCache.
|
|
1895
|
+
return this.dataCache.getEntryAsync(this.getSSGCacheKey(urlPath), {
|
|
1702
1896
|
allowStale: true
|
|
1703
1897
|
});
|
|
1704
1898
|
}
|
|
1705
|
-
cacheSSGPage(page, html, options) {
|
|
1706
|
-
this.dataCache.
|
|
1899
|
+
async cacheSSGPage(page, html, options) {
|
|
1900
|
+
await this.dataCache.setAsync(
|
|
1707
1901
|
this.getSSGCacheKey(page.urlPath),
|
|
1708
1902
|
{ html, document: options.document },
|
|
1709
1903
|
{
|
|
@@ -1715,11 +1909,11 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
1715
1909
|
);
|
|
1716
1910
|
}
|
|
1717
1911
|
getCachedPPRShell(pathname, search) {
|
|
1718
|
-
return this.dataCache.
|
|
1912
|
+
return this.dataCache.getEntryAsync(this.getPPRCacheKey(pathname, search));
|
|
1719
1913
|
}
|
|
1720
|
-
cachePPRShell(options, html) {
|
|
1914
|
+
async cachePPRShell(options, html) {
|
|
1721
1915
|
const key = this.getPPRCacheKey(options.pathname, options.search);
|
|
1722
|
-
this.dataCache.
|
|
1916
|
+
await this.dataCache.setAsync(
|
|
1723
1917
|
key,
|
|
1724
1918
|
{ html },
|
|
1725
1919
|
{
|
|
@@ -1817,7 +2011,7 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
1817
2011
|
}
|
|
1818
2012
|
const { renderToString } = await import("react-dom/server");
|
|
1819
2013
|
const html = renderToString(await this.wrapWithIntegrationProviders(pageElement));
|
|
1820
|
-
this.cacheSSGPage(page, html, { document: false });
|
|
2014
|
+
await this.cacheSSGPage(page, html, { document: false });
|
|
1821
2015
|
logger.info(`ISR: Regenerated ${page.urlPath}`);
|
|
1822
2016
|
} catch (error) {
|
|
1823
2017
|
logger.error(`ISR regeneration failed for ${page.urlPath}: ${error}`);
|
|
@@ -1831,7 +2025,7 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
1831
2025
|
* Serve a pre-rendered SSG page
|
|
1832
2026
|
*/
|
|
1833
2027
|
async serveSSGPage(req, res, page) {
|
|
1834
|
-
const cached = this.getCachedSSGPage(page.urlPath);
|
|
2028
|
+
const cached = await this.getCachedSSGPage(page.urlPath);
|
|
1835
2029
|
if (cached) {
|
|
1836
2030
|
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
1837
2031
|
res.setHeader("X-Farm-SSG", "cached");
|
|
@@ -1849,9 +2043,12 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
1849
2043
|
if (fs2.existsSync(htmlPath)) {
|
|
1850
2044
|
const stat = fs2.statSync(htmlPath);
|
|
1851
2045
|
const html = fs2.readFileSync(htmlPath, "utf-8");
|
|
1852
|
-
this.cacheSSGPage(page, html, {
|
|
1853
|
-
|
|
1854
|
-
|
|
2046
|
+
await this.cacheSSGPage(page, html, {
|
|
2047
|
+
document: true,
|
|
2048
|
+
createdAt: stat.mtimeMs
|
|
2049
|
+
});
|
|
2050
|
+
const fileCacheEntry = await this.getCachedSSGPage(page.urlPath);
|
|
2051
|
+
if (fileCacheEntry && await this.dataCache.isStaleAsync(fileCacheEntry)) {
|
|
1855
2052
|
this.regenerateSSGPage(page);
|
|
1856
2053
|
}
|
|
1857
2054
|
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
@@ -1897,6 +2094,7 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
1897
2094
|
let pathname = "/";
|
|
1898
2095
|
let params = {};
|
|
1899
2096
|
let layouts = [];
|
|
2097
|
+
let routeSlots = [];
|
|
1900
2098
|
let searchParamsObject = {};
|
|
1901
2099
|
let middlewareMap = /* @__PURE__ */ new Map();
|
|
1902
2100
|
let middlewareContext = /* @__PURE__ */ new Map();
|
|
@@ -1929,7 +2127,7 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
1929
2127
|
}
|
|
1930
2128
|
this.applyDeploymentHeaders(req, res);
|
|
1931
2129
|
if (process.env.NODE_ENV === "production") {
|
|
1932
|
-
const ssgPage = this.shouldServeSSG(pathname);
|
|
2130
|
+
const ssgPage = await this.shouldServeSSG(pathname);
|
|
1933
2131
|
if (ssgPage) {
|
|
1934
2132
|
const served = await this.serveSSGPage(req, res, ssgPage);
|
|
1935
2133
|
if (served) {
|
|
@@ -1942,6 +2140,7 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
1942
2140
|
const route = match.route;
|
|
1943
2141
|
params = match.params;
|
|
1944
2142
|
layouts = match.layouts;
|
|
2143
|
+
routeSlots = match.slots ?? [];
|
|
1945
2144
|
if (!route) {
|
|
1946
2145
|
emitFarmEvent({ type: "route.notFound", pathname });
|
|
1947
2146
|
await this.render404(req, res);
|
|
@@ -1958,7 +2157,9 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
1958
2157
|
errorBoundaryEntry = this.routeManager.getMatchingError(pathname);
|
|
1959
2158
|
middlewareMap = toMiddlewareMap(req.__FARM_MIDDLEWARE_DATA__);
|
|
1960
2159
|
middlewareContext = toMiddlewareMap(req.__FARM_MIDDLEWARE_CONTEXT__);
|
|
1961
|
-
pluginExposedContext = getRequestContextSnapshot(req, {
|
|
2160
|
+
pluginExposedContext = getRequestContextSnapshot(req, {
|
|
2161
|
+
exposedOnly: true
|
|
2162
|
+
});
|
|
1962
2163
|
const currentRequest = createWebRequestFromFarmRequest(req);
|
|
1963
2164
|
const routeContext = await this.resolveRouteContext({
|
|
1964
2165
|
request: currentRequest,
|
|
@@ -2022,8 +2223,16 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
2022
2223
|
revalidate: renderingConfig.revalidate
|
|
2023
2224
|
} : void 0;
|
|
2024
2225
|
if (renderingConfig.ppr && pprBypassReason) {
|
|
2025
|
-
emitFarmEvent({
|
|
2026
|
-
|
|
2226
|
+
emitFarmEvent({
|
|
2227
|
+
type: "ppr.shell.bypass",
|
|
2228
|
+
route: pathname,
|
|
2229
|
+
reason: pprBypassReason
|
|
2230
|
+
});
|
|
2231
|
+
emitFarmEvent({
|
|
2232
|
+
type: "cache.bypass",
|
|
2233
|
+
route: pathname,
|
|
2234
|
+
reason: pprBypassReason
|
|
2235
|
+
});
|
|
2027
2236
|
if (pprBypassReason === "refresh") {
|
|
2028
2237
|
pprRefreshRoute = pathname;
|
|
2029
2238
|
emitFarmEvent({ type: "ppr.refresh.start", route: pathname });
|
|
@@ -2031,14 +2240,22 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
2031
2240
|
}
|
|
2032
2241
|
if (pprShellOptions) {
|
|
2033
2242
|
const pprCacheKey = this.getPPRCacheKey(pathname, url.search);
|
|
2034
|
-
const cachedPPRShell = this.getCachedPPRShell(pathname, url.search);
|
|
2243
|
+
const cachedPPRShell = await this.getCachedPPRShell(pathname, url.search);
|
|
2035
2244
|
if (cachedPPRShell) {
|
|
2036
|
-
emitFarmEvent({
|
|
2245
|
+
emitFarmEvent({
|
|
2246
|
+
type: "ppr.shell.hit",
|
|
2247
|
+
route: pathname,
|
|
2248
|
+
key: pprCacheKey
|
|
2249
|
+
});
|
|
2037
2250
|
this.serveCachedPPRShell(res, cachedPPRShell.value, renderingConfig.revalidate);
|
|
2038
2251
|
completeRender(res.statusCode || 200, pathname);
|
|
2039
2252
|
return;
|
|
2040
2253
|
}
|
|
2041
|
-
emitFarmEvent({
|
|
2254
|
+
emitFarmEvent({
|
|
2255
|
+
type: "ppr.shell.miss",
|
|
2256
|
+
route: pathname,
|
|
2257
|
+
key: pprCacheKey
|
|
2258
|
+
});
|
|
2042
2259
|
}
|
|
2043
2260
|
let LoadingFallbackComponent = null;
|
|
2044
2261
|
if (loadingBoundaryEntry) {
|
|
@@ -2062,14 +2279,77 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
2062
2279
|
);
|
|
2063
2280
|
const moduleMetadata = routeManifestEntry || getClientModuleMetadata(route.modulePath, this.config.root);
|
|
2064
2281
|
const isClientComponent = moduleMetadata.isClientComponent;
|
|
2282
|
+
const renderedRouteSlots = await Promise.all(
|
|
2283
|
+
routeSlots.map(async (slot) => {
|
|
2284
|
+
const slotModule = await this.routeManager.loadRouteModule(slot.route.modulePath);
|
|
2285
|
+
if (!slotModule.default) {
|
|
2286
|
+
throw new Error(
|
|
2287
|
+
`Route slot "${slot.name}" module ${slot.route.modulePath} does not export a default component`
|
|
2288
|
+
);
|
|
2289
|
+
}
|
|
2290
|
+
const slotContext = await this.resolveRouteContext({
|
|
2291
|
+
request: currentRequest,
|
|
2292
|
+
rawRequest: req,
|
|
2293
|
+
params: slot.params,
|
|
2294
|
+
search: searchParamsObject,
|
|
2295
|
+
path: pathname
|
|
2296
|
+
});
|
|
2297
|
+
const rawSlotProps = withFarmRouteContext(
|
|
2298
|
+
{
|
|
2299
|
+
params: slot.params,
|
|
2300
|
+
searchParams: Promise.resolve(searchParamsObject),
|
|
2301
|
+
path: pathname,
|
|
2302
|
+
middleware: middlewareMap.size > 0 ? { data: middlewareMap } : void 0,
|
|
2303
|
+
context: pluginExposedContext.size > 0 ? { data: pluginExposedContext } : void 0
|
|
2304
|
+
},
|
|
2305
|
+
slotContext
|
|
2306
|
+
);
|
|
2307
|
+
const slotProps = await parseRouteModuleProps(slotModule, {
|
|
2308
|
+
props: rawSlotProps,
|
|
2309
|
+
search: searchParamsObject,
|
|
2310
|
+
routePath: slot.route.pattern
|
|
2311
|
+
});
|
|
2312
|
+
const metadata = getClientModuleMetadata(slot.route.modulePath, this.config.root);
|
|
2313
|
+
return {
|
|
2314
|
+
...slot,
|
|
2315
|
+
module: slotModule,
|
|
2316
|
+
props: slotProps,
|
|
2317
|
+
isClientComponent: metadata.isClientComponent,
|
|
2318
|
+
shouldHydrate: metadata.shouldHydrate
|
|
2319
|
+
};
|
|
2320
|
+
})
|
|
2321
|
+
);
|
|
2065
2322
|
const shouldHydrate = moduleMetadata.shouldHydrate;
|
|
2323
|
+
const hasHydratableRouteSlots = renderedRouteSlots.some(
|
|
2324
|
+
(slot) => slot.isClientComponent || slot.shouldHydrate
|
|
2325
|
+
);
|
|
2066
2326
|
req.__FARM_PAGE_PATH__ = route.modulePath;
|
|
2067
2327
|
req.__FARM_ROUTE__ = pathname;
|
|
2068
2328
|
req.__FARM_IS_CLIENT_COMPONENT__ = isClientComponent;
|
|
2069
2329
|
req.__FARM_SHOULD_HYDRATE__ = shouldHydrate;
|
|
2330
|
+
req.__FARM_HAS_HYDRATABLE_ROUTE_SLOTS__ = hasHydratableRouteSlots;
|
|
2070
2331
|
req.__FARM_LOADING_MODULE_PATH__ = loadingBoundaryEntry?.modulePath ? loadingBoundaryEntry.modulePath.substring(
|
|
2071
2332
|
loadingBoundaryEntry.modulePath.indexOf("/src/app/")
|
|
2072
2333
|
) : null;
|
|
2334
|
+
req.__FARM_ROUTE_SLOTS__ = renderedRouteSlots.map((slot) => ({
|
|
2335
|
+
name: slot.name,
|
|
2336
|
+
ownerPattern: slot.ownerPattern,
|
|
2337
|
+
containerId: slot.containerId,
|
|
2338
|
+
interception: slot.interception,
|
|
2339
|
+
fallback: slot.fallback,
|
|
2340
|
+
modulePath: slot.route.modulePath,
|
|
2341
|
+
isClientComponent: slot.isClientComponent,
|
|
2342
|
+
shouldHydrate: slot.shouldHydrate,
|
|
2343
|
+
props: {
|
|
2344
|
+
params: slot.props.params,
|
|
2345
|
+
search: slot.props.search,
|
|
2346
|
+
searchParams: slot.props.search,
|
|
2347
|
+
..."data" in slot.props ? { data: slot.props.data } : {},
|
|
2348
|
+
...slot.props.__farmCanonicalPath ? { __farmCanonicalPath: slot.props.__farmCanonicalPath } : {},
|
|
2349
|
+
...slot.props.__farmRoutePropsResolved ? { __farmRoutePropsResolved: true } : {},
|
|
2350
|
+
path: pathname
|
|
2351
|
+
}
|
|
2352
|
+
}));
|
|
2073
2353
|
req.__FARM_PROPS__ = {
|
|
2074
2354
|
params: pageProps.params,
|
|
2075
2355
|
search: pageProps.search,
|
|
@@ -2129,12 +2409,32 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
2129
2409
|
let wrappedElement = pageElement;
|
|
2130
2410
|
for (let i = layoutModules.length - 1; i >= 0; i--) {
|
|
2131
2411
|
const layoutModule = layoutModules[i];
|
|
2412
|
+
const layoutEntry = layouts[i];
|
|
2132
2413
|
const LayoutComponent = layoutModule.default;
|
|
2414
|
+
const slotProps = {};
|
|
2415
|
+
for (const slot of renderedRouteSlots) {
|
|
2416
|
+
if (slot.ownerPattern !== layoutEntry.pattern) continue;
|
|
2417
|
+
let slotElement = React.createElement(
|
|
2418
|
+
slot.module.default,
|
|
2419
|
+
slot.props
|
|
2420
|
+
);
|
|
2421
|
+
slotElement = React.createElement(
|
|
2422
|
+
"div",
|
|
2423
|
+
{
|
|
2424
|
+
id: slot.containerId,
|
|
2425
|
+
"data-farm-route-slot": slot.name,
|
|
2426
|
+
"data-farm-slot-owner": slot.ownerPattern
|
|
2427
|
+
},
|
|
2428
|
+
slotElement
|
|
2429
|
+
);
|
|
2430
|
+
slotProps[slot.name] = slotElement;
|
|
2431
|
+
}
|
|
2133
2432
|
wrappedElement = React.createElement(
|
|
2134
2433
|
LayoutComponent,
|
|
2135
2434
|
{
|
|
2136
2435
|
children: wrappedElement,
|
|
2137
|
-
params
|
|
2436
|
+
params,
|
|
2437
|
+
...slotProps
|
|
2138
2438
|
}
|
|
2139
2439
|
);
|
|
2140
2440
|
}
|
|
@@ -2171,7 +2471,10 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
2171
2471
|
routeManifest,
|
|
2172
2472
|
captureStaticShell: Boolean(pprShellOptions),
|
|
2173
2473
|
observabilityRoute: pathname,
|
|
2174
|
-
onSuspenseHoleDetected: pprShellOptions ? () => emitFarmEvent({
|
|
2474
|
+
onSuspenseHoleDetected: pprShellOptions ? () => emitFarmEvent({
|
|
2475
|
+
type: "ppr.suspense.holeDetected",
|
|
2476
|
+
route: pathname
|
|
2477
|
+
}) : void 0,
|
|
2175
2478
|
onComplete: pprShellOptions && req.method !== "HEAD" ? (html) => this.cachePPRShell(pprShellOptions, html) : void 0
|
|
2176
2479
|
}
|
|
2177
2480
|
);
|
|
@@ -2219,7 +2522,11 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
2219
2522
|
}
|
|
2220
2523
|
emitFarmEvent({ type: "render.error", route: pathname, error });
|
|
2221
2524
|
if (pprRefreshRoute) {
|
|
2222
|
-
emitFarmEvent({
|
|
2525
|
+
emitFarmEvent({
|
|
2526
|
+
type: "ppr.refresh.error",
|
|
2527
|
+
route: pprRefreshRoute,
|
|
2528
|
+
error
|
|
2529
|
+
});
|
|
2223
2530
|
}
|
|
2224
2531
|
logger.error(`Error rendering page: ${error}`);
|
|
2225
2532
|
if (res.headersSent || res.writableEnded) {
|
|
@@ -2272,7 +2579,9 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
2272
2579
|
if (typeof layoutModule.generateMetadata === "function") {
|
|
2273
2580
|
metadata = mergeMetadata(
|
|
2274
2581
|
metadata,
|
|
2275
|
-
await layoutModule.generateMetadata({
|
|
2582
|
+
await layoutModule.generateMetadata({
|
|
2583
|
+
params: options.pageProps.params
|
|
2584
|
+
})
|
|
2276
2585
|
);
|
|
2277
2586
|
}
|
|
2278
2587
|
}
|
|
@@ -2503,7 +2812,13 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
2503
2812
|
clientEntry: "/@farm/client.js",
|
|
2504
2813
|
routes: {},
|
|
2505
2814
|
layouts: {},
|
|
2506
|
-
|
|
2815
|
+
slots: [],
|
|
2816
|
+
sharedAssets: [
|
|
2817
|
+
{
|
|
2818
|
+
tag: "link",
|
|
2819
|
+
attrs: { rel: "stylesheet", href: "/src/app/globals.css" }
|
|
2820
|
+
}
|
|
2821
|
+
]
|
|
2507
2822
|
};
|
|
2508
2823
|
for (const routeEntry of manifest.routes) {
|
|
2509
2824
|
clientManifest.routes[routeEntry.pattern] = {
|
|
@@ -2525,9 +2840,26 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
2525
2840
|
assets: []
|
|
2526
2841
|
};
|
|
2527
2842
|
}
|
|
2528
|
-
const
|
|
2843
|
+
for (const slotEntry of manifest.slots ?? []) {
|
|
2844
|
+
clientManifest.slots.push({
|
|
2845
|
+
...slotEntry,
|
|
2846
|
+
preloads: [slotEntry.modulePath],
|
|
2847
|
+
assets: []
|
|
2848
|
+
});
|
|
2849
|
+
}
|
|
2850
|
+
const routeSlotPayload = (req.__FARM_ROUTE_SLOTS__ || []).map(
|
|
2851
|
+
(slot) => ({
|
|
2852
|
+
...slot,
|
|
2853
|
+
modulePath: typeof slot.modulePath === "string" && slot.modulePath.startsWith(this.config.root) ? slot.modulePath.slice(this.config.root.length) : slot.modulePath
|
|
2854
|
+
})
|
|
2855
|
+
);
|
|
2856
|
+
const deferredProps = prepareDeferredData({
|
|
2857
|
+
page: req.__FARM_PROPS__ || {},
|
|
2858
|
+
slots: routeSlotPayload
|
|
2859
|
+
});
|
|
2529
2860
|
const propsScript = `<script>
|
|
2530
|
-
window.__FARM_PROPS__ = ${serializeInlineValue(deferredProps.data)};
|
|
2861
|
+
window.__FARM_PROPS__ = ${serializeInlineValue(deferredProps.data.page)};
|
|
2862
|
+
window.__FARM_ROUTE_SLOTS__ = ${serializeInlineValue(deferredProps.data.slots)};
|
|
2531
2863
|
window.__FARM_DEPLOYMENT_ID__ = ${serializeInlineValue(deploymentId)};
|
|
2532
2864
|
window.__FARM_PATH__ = ${JSON.stringify(req.__FARM_ROUTE__ || req.url || "/")};
|
|
2533
2865
|
window.__FARM_IS_CLIENT__ = ${JSON.stringify(isClientComponent)};
|
|
@@ -2540,7 +2872,7 @@ window.__FARM_MANIFEST__ = ${JSON.stringify(clientManifest)};
|
|
|
2540
2872
|
window.__FARM_INTEGRATION_API_MANIFEST__ = ${JSON.stringify(getRegisteredIntegrationAPIManifest())};
|
|
2541
2873
|
${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue(getFarmI18nClientSnapshot())};` : ""}
|
|
2542
2874
|
</script>`;
|
|
2543
|
-
const hydrationClickQueueScript = isClientComponent || req.__FARM_SHOULD_HYDRATE__ === true ? createPreHydrationClickQueueScript() : "";
|
|
2875
|
+
const hydrationClickQueueScript = isClientComponent || req.__FARM_SHOULD_HYDRATE__ === true || req.__FARM_HAS_HYDRATABLE_ROUTE_SLOTS__ === true ? createPreHydrationClickQueueScript() : "";
|
|
2544
2876
|
const {
|
|
2545
2877
|
title,
|
|
2546
2878
|
tags: metaTags,
|
|
@@ -2651,7 +2983,11 @@ ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue(g
|
|
|
2651
2983
|
didError = true;
|
|
2652
2984
|
if (!isFarmRedirectError(error) && !isFarmNotFoundError(error)) {
|
|
2653
2985
|
logger.error(`SSR shell error: ${error}`);
|
|
2654
|
-
emitFarmEvent({
|
|
2986
|
+
emitFarmEvent({
|
|
2987
|
+
type: "render.error",
|
|
2988
|
+
route: observabilityRoute,
|
|
2989
|
+
error
|
|
2990
|
+
});
|
|
2655
2991
|
}
|
|
2656
2992
|
if (clearMiddlewareData) {
|
|
2657
2993
|
clearMiddlewareData();
|
|
@@ -2662,7 +2998,11 @@ ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue(g
|
|
|
2662
2998
|
didError = true;
|
|
2663
2999
|
if (!isFarmRedirectError(error) && !isFarmNotFoundError(error)) {
|
|
2664
3000
|
logger.error(`SSR streaming error: ${error}`);
|
|
2665
|
-
emitFarmEvent({
|
|
3001
|
+
emitFarmEvent({
|
|
3002
|
+
type: "render.error",
|
|
3003
|
+
route: observabilityRoute,
|
|
3004
|
+
error
|
|
3005
|
+
});
|
|
2666
3006
|
}
|
|
2667
3007
|
}
|
|
2668
3008
|
});
|
|
@@ -2836,6 +3176,7 @@ var _FarmApp = class _FarmApp {
|
|
|
2836
3176
|
logger.info("Initializing Farm.js application...");
|
|
2837
3177
|
}
|
|
2838
3178
|
await initStorage(this.config.storage);
|
|
3179
|
+
await configureFarmCache(this.config.cache);
|
|
2839
3180
|
await this.i18nRuntime.initialize();
|
|
2840
3181
|
await this.verifyAppStructure();
|
|
2841
3182
|
await this.routeManager.discoverRoutes();
|
|
@@ -2867,6 +3208,7 @@ var _FarmApp = class _FarmApp {
|
|
|
2867
3208
|
preset: config.preset ?? "node-server",
|
|
2868
3209
|
deploy: config.deploy || {},
|
|
2869
3210
|
storage: config.storage || {},
|
|
3211
|
+
cache: config.cache || {},
|
|
2870
3212
|
integrations: config.integrations || {},
|
|
2871
3213
|
plugins: config.plugins || [],
|
|
2872
3214
|
migrations: config.migrations || { commands: [] },
|
|
@@ -3339,6 +3681,7 @@ async function generateRouteTypes(options) {
|
|
|
3339
3681
|
absolute: false
|
|
3340
3682
|
});
|
|
3341
3683
|
for (const file of pageFiles) {
|
|
3684
|
+
if (parseRouteSlotFile(file)) continue;
|
|
3342
3685
|
const route = parseRoutePath(file);
|
|
3343
3686
|
if (route.type === "page") {
|
|
3344
3687
|
const pattern = createRoutePattern(route);
|
|
@@ -3665,7 +4008,7 @@ function loadFarmWorkflowsDevRuntime() {
|
|
|
3665
4008
|
}
|
|
3666
4009
|
__name(loadFarmWorkflowsDevRuntime, "loadFarmWorkflowsDevRuntime");
|
|
3667
4010
|
function loadFarmDevtoolsSnapshotRuntime() {
|
|
3668
|
-
return import("./devtools-
|
|
4011
|
+
return import("./devtools-LVC3VB5P.mjs");
|
|
3669
4012
|
}
|
|
3670
4013
|
__name(loadFarmDevtoolsSnapshotRuntime, "loadFarmDevtoolsSnapshotRuntime");
|
|
3671
4014
|
function loadFarmDevtoolsUIRuntime() {
|
|
@@ -4071,7 +4414,7 @@ function farmPlugin(options = {}, initialPluginManager) {
|
|
|
4071
4414
|
}, "isProgrammaticRouteSourceFile");
|
|
4072
4415
|
const isAppRuntimeFile = /* @__PURE__ */ __name((file) => {
|
|
4073
4416
|
const normalized = file.replace(/\\/g, "/");
|
|
4074
|
-
return appDirSlugs.some((appDir) => normalized.startsWith(`${appDir}/`)) && /\/(?:page|layout|loading|error|middleware|route)\.(?:ts|tsx|js|jsx|md|mdx)$|\/(?:opengraph-image|twitter-image)(?:\.(?:ts|tsx|js|jsx|png|jpg|jpeg|gif|webp)|\.alt\.txt)$/.test(
|
|
4417
|
+
return appDirSlugs.some((appDir) => normalized.startsWith(`${appDir}/`)) && /\/(?:page|default|layout|loading|error|middleware|route)\.(?:ts|tsx|js|jsx|md|mdx)$|\/(?:opengraph-image|twitter-image)(?:\.(?:ts|tsx|js|jsx|png|jpg|jpeg|gif|webp)|\.alt\.txt)$/.test(
|
|
4075
4418
|
normalized
|
|
4076
4419
|
);
|
|
4077
4420
|
}, "isAppRuntimeFile");
|
|
@@ -4762,7 +5105,10 @@ function farmPlugin(options = {}, initialPluginManager) {
|
|
|
4762
5105
|
method: req.method || "GET"
|
|
4763
5106
|
});
|
|
4764
5107
|
}
|
|
4765
|
-
const
|
|
5108
|
+
const interceptFromHeader = request.headers.get("x-farm-intercept-from") || void 0;
|
|
5109
|
+
const match = routeManager3.matchRoute(targetRequestUrl.pathname, {
|
|
5110
|
+
interceptFrom: interceptFromHeader
|
|
5111
|
+
});
|
|
4766
5112
|
if (pm) {
|
|
4767
5113
|
await pm.runHookParallel("afterRouteMatch", {
|
|
4768
5114
|
pathname: targetPath,
|
|
@@ -4778,7 +5124,7 @@ function farmPlugin(options = {}, initialPluginManager) {
|
|
|
4778
5124
|
res.end(JSON.stringify({ error: "Route not found" }));
|
|
4779
5125
|
return;
|
|
4780
5126
|
}
|
|
4781
|
-
const { route, params, layouts } = match;
|
|
5127
|
+
const { route, params, layouts, slots } = match;
|
|
4782
5128
|
if (!route) {
|
|
4783
5129
|
res.statusCode = 404;
|
|
4784
5130
|
res.setHeader("Content-Type", "application/json");
|
|
@@ -4833,6 +5179,54 @@ function farmPlugin(options = {}, initialPluginManager) {
|
|
|
4833
5179
|
search: searchParams,
|
|
4834
5180
|
routePath: route.pattern
|
|
4835
5181
|
});
|
|
5182
|
+
const routeSlots = await Promise.all(
|
|
5183
|
+
slots.map(async (slot) => {
|
|
5184
|
+
const slotModule = await routeManager3.loadRouteModule(slot.route.modulePath);
|
|
5185
|
+
const slotMetadata = getClientModuleMetadata(
|
|
5186
|
+
slot.route.modulePath,
|
|
5187
|
+
server.config.root
|
|
5188
|
+
);
|
|
5189
|
+
const slotContext = await resolveFarmRouteContext(farmApp.getConfig(), {
|
|
5190
|
+
request,
|
|
5191
|
+
params: slot.params,
|
|
5192
|
+
search: searchParams,
|
|
5193
|
+
path: targetUrl.pathname
|
|
5194
|
+
});
|
|
5195
|
+
const slotProps = await parseRouteModuleProps2(slotModule, {
|
|
5196
|
+
props: withFarmRouteContext(
|
|
5197
|
+
{
|
|
5198
|
+
params: slot.params,
|
|
5199
|
+
searchParams: Promise.resolve(searchParams),
|
|
5200
|
+
path: targetUrl.pathname
|
|
5201
|
+
},
|
|
5202
|
+
slotContext
|
|
5203
|
+
),
|
|
5204
|
+
search: searchParams,
|
|
5205
|
+
routePath: slot.route.pattern
|
|
5206
|
+
});
|
|
5207
|
+
return {
|
|
5208
|
+
name: slot.name,
|
|
5209
|
+
ownerPattern: slot.ownerPattern,
|
|
5210
|
+
containerId: slot.containerId,
|
|
5211
|
+
interception: slot.interception,
|
|
5212
|
+
fallback: slot.fallback,
|
|
5213
|
+
modulePath: slot.route.modulePath,
|
|
5214
|
+
isClientComponent: slotMetadata.isClientComponent,
|
|
5215
|
+
shouldHydrate: slotMetadata.shouldHydrate,
|
|
5216
|
+
props: {
|
|
5217
|
+
params: slotProps.params,
|
|
5218
|
+
search: slotProps.search,
|
|
5219
|
+
searchParams: slotProps.search,
|
|
5220
|
+
..."data" in slotProps ? { data: slotProps.data } : {},
|
|
5221
|
+
...slotProps.__farmCanonicalPath ? {
|
|
5222
|
+
__farmCanonicalPath: slotProps.__farmCanonicalPath
|
|
5223
|
+
} : {},
|
|
5224
|
+
...slotProps.__farmRoutePropsResolved ? { __farmRoutePropsResolved: true } : {},
|
|
5225
|
+
path: targetUrl.pathname
|
|
5226
|
+
}
|
|
5227
|
+
};
|
|
5228
|
+
})
|
|
5229
|
+
);
|
|
4836
5230
|
const projectRoot = server.config.root;
|
|
4837
5231
|
const toUrlPath = /* @__PURE__ */ __name((absolutePath) => {
|
|
4838
5232
|
if (absolutePath.startsWith(projectRoot)) {
|
|
@@ -4853,13 +5247,21 @@ function farmPlugin(options = {}, initialPluginManager) {
|
|
|
4853
5247
|
},
|
|
4854
5248
|
canonicalPath: routeProps.__farmCanonicalPath,
|
|
4855
5249
|
modulePath: toUrlPath(route.modulePath),
|
|
4856
|
-
isClientComponent,
|
|
4857
|
-
shouldHydrate,
|
|
5250
|
+
isClientComponent: routeSlots.length > 0 ? false : isClientComponent,
|
|
5251
|
+
shouldHydrate: shouldHydrate || routeSlots.some((slot) => slot.isClientComponent || slot.shouldHydrate),
|
|
4858
5252
|
metadata: {
|
|
4859
5253
|
title: mergedMetadata.title,
|
|
4860
5254
|
description: mergedMetadata.description
|
|
4861
5255
|
},
|
|
4862
5256
|
layoutModules: layouts.map((l) => toUrlPath(l.modulePath)),
|
|
5257
|
+
routeSlots: routeSlots.map((slot) => ({
|
|
5258
|
+
...slot,
|
|
5259
|
+
modulePath: toUrlPath(slot.modulePath)
|
|
5260
|
+
})),
|
|
5261
|
+
interception: routeSlots.some((slot) => slot.interception) ? {
|
|
5262
|
+
from: interceptFromHeader,
|
|
5263
|
+
slots: routeSlots.filter((slot) => slot.interception).map((slot) => slot.name)
|
|
5264
|
+
} : void 0,
|
|
4863
5265
|
i18n: getFarmI18nClientSnapshot()
|
|
4864
5266
|
};
|
|
4865
5267
|
await sendWebResponse(
|
|
@@ -5195,6 +5597,7 @@ function farmPlugin(options = {}, initialPluginManager) {
|
|
|
5195
5597
|
export const getManifest = () => ({
|
|
5196
5598
|
routes: {},
|
|
5197
5599
|
layouts: {},
|
|
5600
|
+
slots: [],
|
|
5198
5601
|
clientEntry: "/@farm/client.js",
|
|
5199
5602
|
sharedAssets: []
|
|
5200
5603
|
});
|
|
@@ -5205,6 +5608,7 @@ export const getManifest = () => ({
|
|
|
5205
5608
|
clientEntry: "/@farm/client.js",
|
|
5206
5609
|
routes: {},
|
|
5207
5610
|
layouts: {},
|
|
5611
|
+
slots: [],
|
|
5208
5612
|
sharedAssets: [
|
|
5209
5613
|
{
|
|
5210
5614
|
tag: "link",
|
|
@@ -5234,6 +5638,13 @@ export const getManifest = () => ({
|
|
|
5234
5638
|
assets: []
|
|
5235
5639
|
};
|
|
5236
5640
|
}
|
|
5641
|
+
for (const slot of manifest.slots) {
|
|
5642
|
+
fullManifest.slots.push({
|
|
5643
|
+
...slot,
|
|
5644
|
+
preloads: [slot.modulePath],
|
|
5645
|
+
assets: []
|
|
5646
|
+
});
|
|
5647
|
+
}
|
|
5237
5648
|
return `
|
|
5238
5649
|
// Auto-generated manifest for SPA navigation (TanStack Start pattern)
|
|
5239
5650
|
// This manifest is inlined in the server bundle - no file on disk
|
|
@@ -5876,7 +6287,7 @@ window.__FARM_WRAP_PROVIDERS__ = wrapWithIntegrationProviders;
|
|
|
5876
6287
|
|
|
5877
6288
|
// Get manifest from window (inlined by server in HTML)
|
|
5878
6289
|
// Fallback to empty manifest if not available yet
|
|
5879
|
-
const getManifest = () => window.__FARM_MANIFEST__ || { routes: {}, layouts: {}, clientEntry: '', sharedAssets: [] };
|
|
6290
|
+
const getManifest = () => window.__FARM_MANIFEST__ || { routes: {}, layouts: {}, slots: [], clientEntry: '', sharedAssets: [] };
|
|
5880
6291
|
|
|
5881
6292
|
// ====== CLIENT-SIDE ROUTE MATCHING ======
|
|
5882
6293
|
// Matches URL to route using manifest (no server request!)
|
|
@@ -6215,6 +6626,9 @@ let LayoutComponent = null;
|
|
|
6215
6626
|
|
|
6216
6627
|
// Track if we've taken over rendering from SSR
|
|
6217
6628
|
let hasClientTakenOver = false;
|
|
6629
|
+
const routeSlotRoots = new Map();
|
|
6630
|
+
const routeSlotDefinitions = new Map();
|
|
6631
|
+
let activeRouteInterception = null;
|
|
6218
6632
|
|
|
6219
6633
|
function normalizeServerProps(rawProps) {
|
|
6220
6634
|
const props = rawProps && typeof rawProps === 'object' ? { ...rawProps } : {};
|
|
@@ -6227,6 +6641,123 @@ function normalizeServerProps(rawProps) {
|
|
|
6227
6641
|
return props;
|
|
6228
6642
|
}
|
|
6229
6643
|
|
|
6644
|
+
function getRouteSlotKey(slot) {
|
|
6645
|
+
return slot.ownerPattern + ':' + slot.name;
|
|
6646
|
+
}
|
|
6647
|
+
|
|
6648
|
+
async function renderRouteSlot(slot, mode = 'render') {
|
|
6649
|
+
const container = document.getElementById(slot.containerId);
|
|
6650
|
+
if (!container || !slot.modulePath) return false;
|
|
6651
|
+
if (mode === 'intercept' && !slot.isClientComponent && !slot.shouldHydrate) {
|
|
6652
|
+
return false;
|
|
6653
|
+
}
|
|
6654
|
+
|
|
6655
|
+
let slotModule = pageModuleCache.get(slot.modulePath);
|
|
6656
|
+
if (!slotModule) {
|
|
6657
|
+
slotModule = await import(/* @vite-ignore */ slot.modulePath);
|
|
6658
|
+
pageModuleCache.set(slot.modulePath, slotModule);
|
|
6659
|
+
}
|
|
6660
|
+
const SlotComponent = slotModule?.default;
|
|
6661
|
+
if (!SlotComponent) return false;
|
|
6662
|
+
|
|
6663
|
+
const props = reviveDeferredData(
|
|
6664
|
+
normalizeServerProps(slot.props || {}),
|
|
6665
|
+
window.__FARM_DEFERRED_DATA__ || {},
|
|
6666
|
+
);
|
|
6667
|
+
const element = wrapWithIntegrationProviders(
|
|
6668
|
+
React.createElement(SlotComponent, props),
|
|
6669
|
+
);
|
|
6670
|
+
const key = getRouteSlotKey(slot);
|
|
6671
|
+
const existingRoot = routeSlotRoots.get(key);
|
|
6672
|
+
|
|
6673
|
+
if (mode === 'hydrate') {
|
|
6674
|
+
if (existingRoot) return true;
|
|
6675
|
+
const root = hydrateRoot(container, element);
|
|
6676
|
+
routeSlotRoots.set(key, root);
|
|
6677
|
+
} else {
|
|
6678
|
+
if (existingRoot) {
|
|
6679
|
+
try { existingRoot.unmount(); } catch (error) {}
|
|
6680
|
+
}
|
|
6681
|
+
const root = createRoot(container);
|
|
6682
|
+
root.render(element);
|
|
6683
|
+
routeSlotRoots.set(key, root);
|
|
6684
|
+
}
|
|
6685
|
+
|
|
6686
|
+
routeSlotDefinitions.set(key, slot);
|
|
6687
|
+
return true;
|
|
6688
|
+
}
|
|
6689
|
+
|
|
6690
|
+
async function hydrateInitialRouteSlots() {
|
|
6691
|
+
const slots = Array.isArray(window.__FARM_ROUTE_SLOTS__)
|
|
6692
|
+
? window.__FARM_ROUTE_SLOTS__
|
|
6693
|
+
: [];
|
|
6694
|
+
let hydrated = false;
|
|
6695
|
+
|
|
6696
|
+
for (const slot of slots) {
|
|
6697
|
+
routeSlotDefinitions.set(getRouteSlotKey(slot), slot);
|
|
6698
|
+
if (!slot.isClientComponent && !slot.shouldHydrate) continue;
|
|
6699
|
+
try {
|
|
6700
|
+
hydrated = (await renderRouteSlot(slot, 'hydrate')) || hydrated;
|
|
6701
|
+
} catch (error) {
|
|
6702
|
+
console.warn('[Farm.js] Could not hydrate route slot:', slot.name, error);
|
|
6703
|
+
}
|
|
6704
|
+
}
|
|
6705
|
+
|
|
6706
|
+
return hydrated;
|
|
6707
|
+
}
|
|
6708
|
+
|
|
6709
|
+
async function renderRouteInterception(pageData) {
|
|
6710
|
+
const slots = Array.isArray(pageData.routeSlots)
|
|
6711
|
+
? pageData.routeSlots.filter((slot) => slot.interception)
|
|
6712
|
+
: [];
|
|
6713
|
+
if (!pageData.interception || slots.length === 0) return false;
|
|
6714
|
+
|
|
6715
|
+
const previous = new Map();
|
|
6716
|
+
for (const slot of slots) {
|
|
6717
|
+
const key = getRouteSlotKey(slot);
|
|
6718
|
+
previous.set(key, routeSlotDefinitions.get(key) || null);
|
|
6719
|
+
if (!(await renderRouteSlot(slot, 'intercept'))) {
|
|
6720
|
+
return false;
|
|
6721
|
+
}
|
|
6722
|
+
}
|
|
6723
|
+
|
|
6724
|
+
activeRouteInterception = {
|
|
6725
|
+
from: pageData.interception.from,
|
|
6726
|
+
slots,
|
|
6727
|
+
previous,
|
|
6728
|
+
};
|
|
6729
|
+
return true;
|
|
6730
|
+
}
|
|
6731
|
+
|
|
6732
|
+
async function clearRouteInterception(destination) {
|
|
6733
|
+
if (!activeRouteInterception) return false;
|
|
6734
|
+
const active = activeRouteInterception;
|
|
6735
|
+
activeRouteInterception = null;
|
|
6736
|
+
|
|
6737
|
+
for (const slot of active.slots) {
|
|
6738
|
+
const key = getRouteSlotKey(slot);
|
|
6739
|
+
const root = routeSlotRoots.get(key);
|
|
6740
|
+
if (root) {
|
|
6741
|
+
try { root.unmount(); } catch (error) {}
|
|
6742
|
+
routeSlotRoots.delete(key);
|
|
6743
|
+
}
|
|
6744
|
+
|
|
6745
|
+
const previous = active.previous.get(key);
|
|
6746
|
+
if (previous && (previous.isClientComponent || previous.shouldHydrate)) {
|
|
6747
|
+
await renderRouteSlot(previous, 'render');
|
|
6748
|
+
} else {
|
|
6749
|
+
const container = document.getElementById(slot.containerId);
|
|
6750
|
+
if (container) container.replaceChildren();
|
|
6751
|
+
if (previous) routeSlotDefinitions.set(key, previous);
|
|
6752
|
+
else routeSlotDefinitions.delete(key);
|
|
6753
|
+
}
|
|
6754
|
+
}
|
|
6755
|
+
|
|
6756
|
+
if (!active.from) return false;
|
|
6757
|
+
const background = new URL(active.from, window.location.origin);
|
|
6758
|
+
return destination === background.pathname + background.search;
|
|
6759
|
+
}
|
|
6760
|
+
|
|
6230
6761
|
function applyCanonicalPathFromProps(props) {
|
|
6231
6762
|
const canonicalPath = props && typeof props.__farmCanonicalPath === 'string'
|
|
6232
6763
|
? props.__farmCanonicalPath
|
|
@@ -6461,6 +6992,17 @@ async function tryHydrateImportedPage(
|
|
|
6461
6992
|
async function renderPage(pageData) {
|
|
6462
6993
|
const container = document.getElementById('root');
|
|
6463
6994
|
if (!container) return;
|
|
6995
|
+
const destination = window.location.pathname + window.location.search;
|
|
6996
|
+
|
|
6997
|
+
if (pageData.interception) {
|
|
6998
|
+
if (await renderRouteInterception(pageData)) return;
|
|
6999
|
+
window.location.assign(destination);
|
|
7000
|
+
return;
|
|
7001
|
+
}
|
|
7002
|
+
|
|
7003
|
+
if (await clearRouteInterception(destination)) {
|
|
7004
|
+
return;
|
|
7005
|
+
}
|
|
6464
7006
|
|
|
6465
7007
|
const route = {
|
|
6466
7008
|
modulePath: pageData.modulePath,
|
|
@@ -6689,7 +7231,9 @@ async function hydrate() {
|
|
|
6689
7231
|
window.__FARM_SHOULD_HYDRATE__ === true ||
|
|
6690
7232
|
isClientComponent ||
|
|
6691
7233
|
await moduleLooksClient(modulePath);
|
|
7234
|
+
const hydratedSlots = await hydrateInitialRouteSlots();
|
|
6692
7235
|
if (!shouldHydrate) {
|
|
7236
|
+
if (hydratedSlots) replayPreHydrationClicks();
|
|
6693
7237
|
console.log('[Farm.js] Server component - SPA router ready')
|
|
6694
7238
|
return
|
|
6695
7239
|
}
|
|
@@ -7084,4 +7628,4 @@ export {
|
|
|
7084
7628
|
farmPlugin,
|
|
7085
7629
|
defineConfig
|
|
7086
7630
|
};
|
|
7087
|
-
//# sourceMappingURL=chunk-
|
|
7631
|
+
//# sourceMappingURL=chunk-A2LUXHD2.mjs.map
|