@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
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
FARM_DOCS_LAST_MODIFIED_MANIFEST,
|
|
10
10
|
createFarmDocsLastModifiedManifest,
|
|
11
11
|
getFarmDocsRouteTypeEntries
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-HNIQFZKB.mjs";
|
|
13
13
|
import {
|
|
14
14
|
generateFarmDocsSearchClientRuntime,
|
|
15
15
|
isFarmDocsSearchEnabled,
|
|
@@ -17,11 +17,11 @@ import {
|
|
|
17
17
|
} from "./chunk-V7RBCSDJ.mjs";
|
|
18
18
|
import {
|
|
19
19
|
mergeFarmViteConfig
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-QM746KUO.mjs";
|
|
21
21
|
import {
|
|
22
22
|
hasCustomFarmRouteContext,
|
|
23
23
|
resolveDeployOutputPath
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-NM3CRAAL.mjs";
|
|
25
25
|
import {
|
|
26
26
|
PluginManager
|
|
27
27
|
} from "./chunk-C3DLZMBU.mjs";
|
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
generateFarmTypeArtifacts,
|
|
32
32
|
getClientModuleMetadata,
|
|
33
33
|
resolveRouteRenderingConfigFromFile
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-A2LUXHD2.mjs";
|
|
35
35
|
import {
|
|
36
36
|
farmEnvironmentFunctionsPlugin
|
|
37
37
|
} from "./chunk-V6WE6JSZ.mjs";
|
|
@@ -59,7 +59,7 @@ import {
|
|
|
59
59
|
} from "./chunk-K4667E2Q.mjs";
|
|
60
60
|
import {
|
|
61
61
|
APIRouteManager
|
|
62
|
-
} from "./chunk-
|
|
62
|
+
} from "./chunk-Z5CQMP54.mjs";
|
|
63
63
|
import {
|
|
64
64
|
readFarmI18nCatalogs
|
|
65
65
|
} from "./chunk-2ED5Q2GH.mjs";
|
|
@@ -749,6 +749,18 @@ async function buildUniversal(config, routeManager, apiRouteManager, serverRende
|
|
|
749
749
|
...isFarmMarkdownPageFile(entry.modulePath) ? { source: readFileSync(entry.modulePath, "utf8") } : {}
|
|
750
750
|
});
|
|
751
751
|
}
|
|
752
|
+
const routeSlots = Array.from(
|
|
753
|
+
routeManager.getRouteSlots().values(),
|
|
754
|
+
(entry) => ({
|
|
755
|
+
name: entry.name,
|
|
756
|
+
ownerPattern: entry.ownerPattern,
|
|
757
|
+
pattern: entry.pattern,
|
|
758
|
+
modulePath: entry.modulePath,
|
|
759
|
+
containerId: entry.containerId,
|
|
760
|
+
interception: entry.interception,
|
|
761
|
+
fallback: entry.fallback
|
|
762
|
+
})
|
|
763
|
+
);
|
|
752
764
|
logger.info(`\u{1F4CB} Found ${pageRoutes.length} page routes`);
|
|
753
765
|
const fs = await import("fs/promises");
|
|
754
766
|
const layoutRoutes = [];
|
|
@@ -792,7 +804,16 @@ async function buildUniversal(config, routeManager, apiRouteManager, serverRende
|
|
|
792
804
|
logger.info("\u{1F4E6} Building client and SSR bundles in parallel...");
|
|
793
805
|
const [clientBuildResult, ssrBuildResult] = await Promise.allSettled([
|
|
794
806
|
// Client build (to disk)
|
|
795
|
-
buildClient(
|
|
807
|
+
buildClient(
|
|
808
|
+
productionVite,
|
|
809
|
+
config,
|
|
810
|
+
root,
|
|
811
|
+
srcDir,
|
|
812
|
+
clientOutputDir,
|
|
813
|
+
pageRoutes,
|
|
814
|
+
layoutRoutes,
|
|
815
|
+
routeSlots
|
|
816
|
+
),
|
|
796
817
|
// SSR build (in memory)
|
|
797
818
|
buildSSRInMemory(
|
|
798
819
|
productionVite,
|
|
@@ -803,7 +824,8 @@ async function buildUniversal(config, routeManager, apiRouteManager, serverRende
|
|
|
803
824
|
serverRenderer,
|
|
804
825
|
preset,
|
|
805
826
|
pageRoutes,
|
|
806
|
-
layoutRoutes
|
|
827
|
+
layoutRoutes,
|
|
828
|
+
routeSlots
|
|
807
829
|
)
|
|
808
830
|
]);
|
|
809
831
|
const [routeRuntimeManifestResult] = await routeRuntimeManifestResultPromise;
|
|
@@ -823,7 +845,8 @@ async function buildUniversal(config, routeManager, apiRouteManager, serverRende
|
|
|
823
845
|
srcDir,
|
|
824
846
|
clientOutputDir,
|
|
825
847
|
pageRoutes,
|
|
826
|
-
layoutRoutes
|
|
848
|
+
layoutRoutes,
|
|
849
|
+
routeSlots
|
|
827
850
|
);
|
|
828
851
|
}
|
|
829
852
|
const ssrResult = ssrBuildResult.value;
|
|
@@ -926,7 +949,7 @@ async function validateClientBuildOutput(root, srcDir, outputDir) {
|
|
|
926
949
|
}
|
|
927
950
|
}
|
|
928
951
|
__name(validateClientBuildOutput, "validateClientBuildOutput");
|
|
929
|
-
async function buildClient(productionVite, config, root, srcDir, outputDir, pageRoutes, layoutRoutes = []) {
|
|
952
|
+
async function buildClient(productionVite, config, root, srcDir, outputDir, pageRoutes, layoutRoutes = [], routeSlots = []) {
|
|
930
953
|
const viteBuild = productionVite.build;
|
|
931
954
|
const { farmPlugin } = await import("./vite.mjs");
|
|
932
955
|
const { PluginManager: PluginManager2 } = await import("./plugin.mjs");
|
|
@@ -953,8 +976,16 @@ async function buildClient(productionVite, config, root, srcDir, outputDir, page
|
|
|
953
976
|
logger.warn(`\u26A0\uFE0F Could not inspect route file ${route.modulePath}: ${error}`);
|
|
954
977
|
}
|
|
955
978
|
}
|
|
979
|
+
const clientRouteSlots = routeSlots.filter((slot) => {
|
|
980
|
+
try {
|
|
981
|
+
return getClientModuleMetadata(slot.modulePath, root).shouldHydrate;
|
|
982
|
+
} catch (error) {
|
|
983
|
+
logger.warn(`\u26A0\uFE0F Could not inspect route slot ${slot.modulePath}: ${error}`);
|
|
984
|
+
return false;
|
|
985
|
+
}
|
|
986
|
+
});
|
|
956
987
|
logger.info(
|
|
957
|
-
`\u{1F4F1} Total hydratable routes detected: ${clientPages.length}
|
|
988
|
+
`\u{1F4F1} Total hydratable routes detected: ${clientPages.length} pages and ${clientRouteSlots.length} slots`
|
|
958
989
|
);
|
|
959
990
|
const clientEntryRoot = path3.join(root, ".farm", "tmp");
|
|
960
991
|
await fs.mkdir(clientEntryRoot, { recursive: true });
|
|
@@ -963,6 +994,7 @@ async function buildClient(productionVite, config, root, srcDir, outputDir, page
|
|
|
963
994
|
const clientHydrationCode = generateClientHydrationEntry(
|
|
964
995
|
clientPages,
|
|
965
996
|
layoutRoutes,
|
|
997
|
+
clientRouteSlots,
|
|
966
998
|
root,
|
|
967
999
|
srcDir,
|
|
968
1000
|
isFarmDocsSearchEnabled(config.docs),
|
|
@@ -1295,7 +1327,7 @@ function generateUniversalRouterStateProperties() {
|
|
|
1295
1327
|
`.trim();
|
|
1296
1328
|
}
|
|
1297
1329
|
__name(generateUniversalRouterStateProperties, "generateUniversalRouterStateProperties");
|
|
1298
|
-
function generateClientHydrationEntry(clientPages, layoutRoutes, root, srcDir, docsSearchEnabled, docsSearchModuleId, i18nConfig = {
|
|
1330
|
+
function generateClientHydrationEntry(clientPages, layoutRoutes, clientRouteSlots, root, srcDir, docsSearchEnabled, docsSearchModuleId, i18nConfig = {
|
|
1299
1331
|
enabled: false,
|
|
1300
1332
|
locales: ["en"],
|
|
1301
1333
|
defaultLocale: "en",
|
|
@@ -1363,7 +1395,7 @@ function isFarmLocaleDocumentChange() {
|
|
|
1363
1395
|
return false;
|
|
1364
1396
|
}
|
|
1365
1397
|
`;
|
|
1366
|
-
if (clientPages.length === 0) {
|
|
1398
|
+
if (clientPages.length === 0 && clientRouteSlots.length === 0) {
|
|
1367
1399
|
return `
|
|
1368
1400
|
// Farm.js Client Runtime (no client components)
|
|
1369
1401
|
${cssImport}
|
|
@@ -1613,11 +1645,25 @@ document.addEventListener("click", function(e) {
|
|
|
1613
1645
|
}
|
|
1614
1646
|
const imports = [];
|
|
1615
1647
|
const routeEntries = [];
|
|
1648
|
+
const routeSlotEntries = [];
|
|
1616
1649
|
clientPages.forEach((page, index) => {
|
|
1617
1650
|
const importPath = toImportPath(page.modulePath);
|
|
1618
1651
|
imports.push(`import Page${index} from "${importPath}";`);
|
|
1619
1652
|
routeEntries.push(` { pattern: ${JSON.stringify(page.pattern)}, Component: Page${index} }`);
|
|
1620
1653
|
});
|
|
1654
|
+
clientRouteSlots.forEach((slot, index) => {
|
|
1655
|
+
const importPath = toImportPath(slot.modulePath);
|
|
1656
|
+
imports.push(`import RouteSlot${index} from "${importPath}";`);
|
|
1657
|
+
routeSlotEntries.push(` {
|
|
1658
|
+
name: ${JSON.stringify(slot.name)},
|
|
1659
|
+
ownerPattern: ${JSON.stringify(slot.ownerPattern)},
|
|
1660
|
+
pattern: ${JSON.stringify(slot.pattern)},
|
|
1661
|
+
containerId: ${JSON.stringify(slot.containerId)},
|
|
1662
|
+
interception: ${JSON.stringify(slot.interception)},
|
|
1663
|
+
fallback: ${JSON.stringify(slot.fallback)},
|
|
1664
|
+
Component: RouteSlot${index},
|
|
1665
|
+
}`);
|
|
1666
|
+
});
|
|
1621
1667
|
return `
|
|
1622
1668
|
// Farm.js Client Runtime - SPA with Hydration
|
|
1623
1669
|
${cssImport}
|
|
@@ -1639,6 +1685,10 @@ const clientRoutes = [
|
|
|
1639
1685
|
${routeEntries.join(",\n")}
|
|
1640
1686
|
];
|
|
1641
1687
|
|
|
1688
|
+
const clientRouteSlots = [
|
|
1689
|
+
${routeSlotEntries.join(",\n")}
|
|
1690
|
+
];
|
|
1691
|
+
|
|
1642
1692
|
// Layout routes for wrapping client components
|
|
1643
1693
|
const layoutRoutes = [
|
|
1644
1694
|
${layoutRegistrations.join(",\n")}
|
|
@@ -1693,6 +1743,146 @@ function matchRoute(pathname) {
|
|
|
1693
1743
|
return null;
|
|
1694
1744
|
}
|
|
1695
1745
|
|
|
1746
|
+
function matchesRoutePrefix(pathname, pattern) {
|
|
1747
|
+
if (pattern === "/") return true;
|
|
1748
|
+
const pathSegments = getFarmRoutePathname(pathname).split("/").filter(Boolean);
|
|
1749
|
+
const patternSegments = pattern.split("/").filter(Boolean);
|
|
1750
|
+
if (patternSegments.length > pathSegments.length) return false;
|
|
1751
|
+
const candidate = "/" + pathSegments.slice(0, patternSegments.length).join("/");
|
|
1752
|
+
return matchFarmRoute(pattern, candidate) !== null;
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1755
|
+
function matchInterceptedRouteSlot(pathname, from) {
|
|
1756
|
+
for (const slot of clientRouteSlots) {
|
|
1757
|
+
if (!slot.interception || !matchesRoutePrefix(from, slot.ownerPattern)) continue;
|
|
1758
|
+
const params = matchFarmRoute(slot.pattern, getFarmRoutePathname(pathname));
|
|
1759
|
+
if (params !== null) return { slot: slot, params: params };
|
|
1760
|
+
}
|
|
1761
|
+
return null;
|
|
1762
|
+
}
|
|
1763
|
+
|
|
1764
|
+
function routeSlotKey(slot) {
|
|
1765
|
+
return slot.ownerPattern + ":" + slot.name;
|
|
1766
|
+
}
|
|
1767
|
+
|
|
1768
|
+
function findClientRouteSlot(slot) {
|
|
1769
|
+
return clientRouteSlots.find(function(candidate) {
|
|
1770
|
+
return candidate.name === slot.name &&
|
|
1771
|
+
candidate.ownerPattern === slot.ownerPattern &&
|
|
1772
|
+
candidate.pattern === slot.pattern &&
|
|
1773
|
+
candidate.interception === slot.interception &&
|
|
1774
|
+
candidate.fallback === slot.fallback;
|
|
1775
|
+
});
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
function readRouteSlotPayload(doc) {
|
|
1779
|
+
const script = doc.getElementById("__farm_route_slots_data__");
|
|
1780
|
+
if (!script?.textContent) return [];
|
|
1781
|
+
try {
|
|
1782
|
+
const parsed = JSON.parse(script.textContent);
|
|
1783
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
1784
|
+
} catch {
|
|
1785
|
+
return [];
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
|
|
1789
|
+
const routeSlotRoots = new Map();
|
|
1790
|
+
let activeRouteInterception = null;
|
|
1791
|
+
|
|
1792
|
+
function resetRouteSlotRoots() {
|
|
1793
|
+
for (const root of routeSlotRoots.values()) {
|
|
1794
|
+
try { root.unmount(); } catch {}
|
|
1795
|
+
}
|
|
1796
|
+
routeSlotRoots.clear();
|
|
1797
|
+
activeRouteInterception = null;
|
|
1798
|
+
}
|
|
1799
|
+
|
|
1800
|
+
function renderClientRouteSlot(slot, registration, mode) {
|
|
1801
|
+
const container = document.getElementById(slot.containerId);
|
|
1802
|
+
if (!container || !registration?.Component) return false;
|
|
1803
|
+
const key = routeSlotKey(slot);
|
|
1804
|
+
const existingRoot = routeSlotRoots.get(key);
|
|
1805
|
+
const props = slot.props && typeof slot.props === "object" ? slot.props : {};
|
|
1806
|
+
const element = React.createElement(registration.Component, props);
|
|
1807
|
+
|
|
1808
|
+
if (mode === "hydrate") {
|
|
1809
|
+
if (existingRoot) return true;
|
|
1810
|
+
const root = hydrateRoot(container, element);
|
|
1811
|
+
routeSlotRoots.set(key, root);
|
|
1812
|
+
return true;
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1815
|
+
if (existingRoot) {
|
|
1816
|
+
try { existingRoot.unmount(); } catch {}
|
|
1817
|
+
routeSlotRoots.delete(key);
|
|
1818
|
+
} else {
|
|
1819
|
+
container.replaceChildren();
|
|
1820
|
+
}
|
|
1821
|
+
const root = createRoot(container);
|
|
1822
|
+
root.render(element);
|
|
1823
|
+
routeSlotRoots.set(key, root);
|
|
1824
|
+
return true;
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1827
|
+
function hydrateInitialRouteSlots() {
|
|
1828
|
+
const slots = Array.isArray(window.__FARM_ROUTE_SLOTS__)
|
|
1829
|
+
? window.__FARM_ROUTE_SLOTS__
|
|
1830
|
+
: [];
|
|
1831
|
+
for (const slot of slots) {
|
|
1832
|
+
const registration = findClientRouteSlot(slot);
|
|
1833
|
+
if (!registration) continue;
|
|
1834
|
+
try {
|
|
1835
|
+
renderClientRouteSlot(slot, registration, "hydrate");
|
|
1836
|
+
} catch (error) {
|
|
1837
|
+
console.warn("[Farm.js] Could not hydrate route slot:", slot.name, error);
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
function renderRouteInterception(slot, registration, from) {
|
|
1843
|
+
const container = document.getElementById(slot.containerId);
|
|
1844
|
+
if (!container) return false;
|
|
1845
|
+
const key = routeSlotKey(slot);
|
|
1846
|
+
const previousSlot = (window.__FARM_ROUTE_SLOTS__ || []).find(function(candidate) {
|
|
1847
|
+
return routeSlotKey(candidate) === key;
|
|
1848
|
+
}) || null;
|
|
1849
|
+
const previousHtml = container.innerHTML;
|
|
1850
|
+
|
|
1851
|
+
if (!renderClientRouteSlot(slot, registration, "render")) return false;
|
|
1852
|
+
activeRouteInterception = {
|
|
1853
|
+
from: from,
|
|
1854
|
+
key: key,
|
|
1855
|
+
slot: slot,
|
|
1856
|
+
previousSlot: previousSlot,
|
|
1857
|
+
previousHtml: previousHtml,
|
|
1858
|
+
};
|
|
1859
|
+
return true;
|
|
1860
|
+
}
|
|
1861
|
+
|
|
1862
|
+
function clearRouteInterception(destination) {
|
|
1863
|
+
if (!activeRouteInterception) return false;
|
|
1864
|
+
const active = activeRouteInterception;
|
|
1865
|
+
activeRouteInterception = null;
|
|
1866
|
+
const root = routeSlotRoots.get(active.key);
|
|
1867
|
+
if (root) {
|
|
1868
|
+
try { root.unmount(); } catch {}
|
|
1869
|
+
routeSlotRoots.delete(active.key);
|
|
1870
|
+
}
|
|
1871
|
+
const container = document.getElementById(active.slot.containerId);
|
|
1872
|
+
if (container) {
|
|
1873
|
+
container.innerHTML = active.previousHtml;
|
|
1874
|
+
if (active.previousSlot) {
|
|
1875
|
+
const registration = findClientRouteSlot(active.previousSlot);
|
|
1876
|
+
if (registration) {
|
|
1877
|
+
try {
|
|
1878
|
+
renderClientRouteSlot(active.previousSlot, registration, "hydrate");
|
|
1879
|
+
} catch {}
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
return destination === active.from;
|
|
1884
|
+
}
|
|
1885
|
+
|
|
1696
1886
|
// State
|
|
1697
1887
|
let reactRoot = null;
|
|
1698
1888
|
let currentPathname = null;
|
|
@@ -1711,12 +1901,17 @@ function resetReactRoot() {
|
|
|
1711
1901
|
async function hydrate() {
|
|
1712
1902
|
const pathname = window.location.pathname;
|
|
1713
1903
|
const matched = matchRoute(pathname);
|
|
1714
|
-
|
|
1904
|
+
hydrateInitialRouteSlots();
|
|
1905
|
+
|
|
1715
1906
|
if (!matched) {
|
|
1716
1907
|
return;
|
|
1717
1908
|
}
|
|
1718
1909
|
|
|
1719
|
-
const
|
|
1910
|
+
const hasRouteSlots =
|
|
1911
|
+
Array.isArray(window.__FARM_ROUTE_SLOTS__) && window.__FARM_ROUTE_SLOTS__.length > 0;
|
|
1912
|
+
const container =
|
|
1913
|
+
(hasRouteSlots ? document.getElementById("__farm_page__") : null) ||
|
|
1914
|
+
document.getElementById("root");
|
|
1720
1915
|
if (!container) {
|
|
1721
1916
|
console.error("[Farm.js] No root element found");
|
|
1722
1917
|
return;
|
|
@@ -1730,7 +1925,9 @@ async function hydrate() {
|
|
|
1730
1925
|
|
|
1731
1926
|
// Create page element and wrap with layouts
|
|
1732
1927
|
const pageElement = React.createElement(Component, props);
|
|
1733
|
-
const wrappedElement =
|
|
1928
|
+
const wrappedElement = hasRouteSlots
|
|
1929
|
+
? pageElement
|
|
1930
|
+
: wrapWithLayouts(pageElement, pathname, params);
|
|
1734
1931
|
|
|
1735
1932
|
const shouldHydrate = !isHydrated && Boolean(container.innerHTML.trim());
|
|
1736
1933
|
const hydrationSession = await farmClientRuntime.beginHydration({
|
|
@@ -1795,6 +1992,57 @@ ${generateUniversalRouterStateProperties()}
|
|
|
1795
1992
|
: undefined,
|
|
1796
1993
|
});
|
|
1797
1994
|
|
|
1995
|
+
if (activeRouteInterception && clearRouteInterception(to)) {
|
|
1996
|
+
await farmClientRuntime.markNavigationLoaded(clientNavigation, {
|
|
1997
|
+
routeSlots: "restored",
|
|
1998
|
+
});
|
|
1999
|
+
await farmClientRuntime.resolveNavigation(clientNavigation);
|
|
2000
|
+
void farmClientRuntime.scheduleNavigationRendered(clientNavigation);
|
|
2001
|
+
this.currentPath = to;
|
|
2002
|
+
this.finishNavigation();
|
|
2003
|
+
return;
|
|
2004
|
+
}
|
|
2005
|
+
if (activeRouteInterception) {
|
|
2006
|
+
clearRouteInterception(to);
|
|
2007
|
+
}
|
|
2008
|
+
|
|
2009
|
+
const intercepted = matchInterceptedRouteSlot(pathname, from);
|
|
2010
|
+
if (intercepted) {
|
|
2011
|
+
const html = await this.fetchPage(to, from);
|
|
2012
|
+
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
2013
|
+
const slotPayload = readRouteSlotPayload(doc);
|
|
2014
|
+
const selectedSlot = slotPayload.find(function(slot) {
|
|
2015
|
+
return slot.interception &&
|
|
2016
|
+
slot.name === intercepted.slot.name &&
|
|
2017
|
+
slot.ownerPattern === intercepted.slot.ownerPattern;
|
|
2018
|
+
});
|
|
2019
|
+
|
|
2020
|
+
if (
|
|
2021
|
+
selectedSlot &&
|
|
2022
|
+
renderRouteInterception(selectedSlot, intercepted.slot, from)
|
|
2023
|
+
) {
|
|
2024
|
+
await farmClientRuntime.markNavigationLoaded(clientNavigation, {
|
|
2025
|
+
route: intercepted.slot.pattern,
|
|
2026
|
+
params: intercepted.params,
|
|
2027
|
+
});
|
|
2028
|
+
const historyState = createHistoryState(
|
|
2029
|
+
to,
|
|
2030
|
+
options.state,
|
|
2031
|
+
window.history.state,
|
|
2032
|
+
);
|
|
2033
|
+
if (action === "replace") {
|
|
2034
|
+
window.history.replaceState(historyState, "", url);
|
|
2035
|
+
} else if (action !== "pop") {
|
|
2036
|
+
window.history.pushState(historyState, "", url);
|
|
2037
|
+
}
|
|
2038
|
+
await farmClientRuntime.resolveNavigation(clientNavigation);
|
|
2039
|
+
void farmClientRuntime.scheduleNavigationRendered(clientNavigation);
|
|
2040
|
+
this.currentPath = to;
|
|
2041
|
+
this.finishNavigation();
|
|
2042
|
+
return;
|
|
2043
|
+
}
|
|
2044
|
+
}
|
|
2045
|
+
|
|
1798
2046
|
if (matched) {
|
|
1799
2047
|
const Component = matched.route.Component;
|
|
1800
2048
|
const params = matched.params;
|
|
@@ -1871,21 +2119,28 @@ ${generateUniversalRouterStateProperties()}
|
|
|
1871
2119
|
}
|
|
1872
2120
|
},
|
|
1873
2121
|
|
|
1874
|
-
fetchPage: async function(url) {
|
|
1875
|
-
const
|
|
2122
|
+
fetchPage: async function(url, interceptFrom) {
|
|
2123
|
+
const cacheKey = interceptFrom ? url + "\\nintercept:" + interceptFrom : url;
|
|
2124
|
+
const cached = this.prefetchCache.get(cacheKey);
|
|
1876
2125
|
if (cached) return cached;
|
|
1877
2126
|
|
|
1878
2127
|
const response = await fetch(url, {
|
|
1879
|
-
headers: {
|
|
2128
|
+
headers: {
|
|
2129
|
+
"Accept": "text/html",
|
|
2130
|
+
...(interceptFrom ? { "X-Farm-Intercept-From": interceptFrom } : {}),
|
|
2131
|
+
}
|
|
1880
2132
|
});
|
|
1881
2133
|
if (!response.ok) throw new Error("Failed to fetch page");
|
|
1882
|
-
|
|
2134
|
+
const html = await response.text();
|
|
2135
|
+
this.prefetchCache.set(cacheKey, html);
|
|
2136
|
+
return html;
|
|
1883
2137
|
},
|
|
1884
2138
|
|
|
1885
2139
|
swapContent: function(html, targetPath) {
|
|
1886
2140
|
const parser = new DOMParser();
|
|
1887
2141
|
const doc = parser.parseFromString(html, "text/html");
|
|
1888
2142
|
if (isFarmLocaleDocumentChange(doc)) return false;
|
|
2143
|
+
const nextRouteSlots = readRouteSlotPayload(doc);
|
|
1889
2144
|
|
|
1890
2145
|
// Update title
|
|
1891
2146
|
const newTitle = doc.querySelector("title");
|
|
@@ -1910,7 +2165,10 @@ ${generateUniversalRouterStateProperties()}
|
|
|
1910
2165
|
const currentRoot = document.getElementById("root");
|
|
1911
2166
|
if (!newRoot || !currentRoot) return this.swapDocument(doc);
|
|
1912
2167
|
resetReactRoot();
|
|
2168
|
+
resetRouteSlotRoots();
|
|
1913
2169
|
currentRoot.innerHTML = newRoot.innerHTML;
|
|
2170
|
+
window.__FARM_ROUTE_SLOTS__ = nextRouteSlots;
|
|
2171
|
+
hydrateInitialRouteSlots();
|
|
1914
2172
|
|
|
1915
2173
|
// Check if new page has a client component
|
|
1916
2174
|
const targetUrl = new URL(targetPath || window.location.href, window.location.origin);
|
|
@@ -1922,13 +2180,15 @@ ${generateUniversalRouterStateProperties()}
|
|
|
1922
2180
|
const params = matched.params;
|
|
1923
2181
|
const searchParams = Object.fromEntries(targetUrl.searchParams);
|
|
1924
2182
|
const props = { params: params, searchParams: Promise.resolve(searchParams) };
|
|
1925
|
-
|
|
1926
|
-
if (!reactRoot) {
|
|
1927
|
-
reactRoot = createRoot(currentRoot);
|
|
1928
|
-
}
|
|
1929
2183
|
const pageElement = React.createElement(Component, props);
|
|
1930
|
-
const
|
|
1931
|
-
|
|
2184
|
+
const hasRouteSlots = nextRouteSlots.length > 0;
|
|
2185
|
+
const pageContainer =
|
|
2186
|
+
(hasRouteSlots ? document.getElementById("__farm_page__") : null) || currentRoot;
|
|
2187
|
+
const wrappedElement = hasRouteSlots
|
|
2188
|
+
? pageElement
|
|
2189
|
+
: wrapWithLayouts(pageElement, newPathname, params);
|
|
2190
|
+
reactRoot = hydrateRoot(pageContainer, wrappedElement);
|
|
2191
|
+
isHydrated = true;
|
|
1932
2192
|
}
|
|
1933
2193
|
return true;
|
|
1934
2194
|
},
|
|
@@ -1937,6 +2197,7 @@ ${generateUniversalRouterStateProperties()}
|
|
|
1937
2197
|
if (!doc.documentElement || !doc.body) return false;
|
|
1938
2198
|
|
|
1939
2199
|
resetReactRoot();
|
|
2200
|
+
resetRouteSlotRoots();
|
|
1940
2201
|
|
|
1941
2202
|
Array.from(document.documentElement.attributes).forEach(function(attr) {
|
|
1942
2203
|
if (!doc.documentElement.hasAttribute(attr.name)) {
|
|
@@ -1970,10 +2231,12 @@ ${generateUniversalRouterStateProperties()}
|
|
|
1970
2231
|
if (url.origin !== window.location.origin) return;
|
|
1971
2232
|
|
|
1972
2233
|
const pathname = url.pathname + url.search;
|
|
1973
|
-
|
|
2234
|
+
const interceptFrom = this.currentPath;
|
|
2235
|
+
const cacheKey = pathname + "\\nintercept:" + interceptFrom;
|
|
2236
|
+
if (this.prefetchCache.has(cacheKey)) return;
|
|
1974
2237
|
|
|
1975
|
-
this.fetchPage(pathname)
|
|
1976
|
-
.then(function(html) { spaRouter.prefetchCache.set(
|
|
2238
|
+
this.fetchPage(pathname, interceptFrom)
|
|
2239
|
+
.then(function(html) { spaRouter.prefetchCache.set(cacheKey, html); })
|
|
1977
2240
|
.catch(function() {});
|
|
1978
2241
|
},
|
|
1979
2242
|
|
|
@@ -2064,7 +2327,7 @@ if (isFarmDocsSearchPage()) {
|
|
|
2064
2327
|
`.trim();
|
|
2065
2328
|
}
|
|
2066
2329
|
__name(generateClientHydrationEntry, "generateClientHydrationEntry");
|
|
2067
|
-
async function buildSSRInMemory(productionVite, config, root, routeManager, apiRouteManager, serverRenderer, preset, collectedPageRoutes, collectedLayoutRoutes) {
|
|
2330
|
+
async function buildSSRInMemory(productionVite, config, root, routeManager, apiRouteManager, serverRenderer, preset, collectedPageRoutes, collectedLayoutRoutes, collectedRouteSlots) {
|
|
2068
2331
|
const viteBuild = productionVite.build;
|
|
2069
2332
|
const { farmPlugin } = await import("./vite.mjs");
|
|
2070
2333
|
const { PluginManager: PluginManager2 } = await import("./plugin.mjs");
|
|
@@ -2097,6 +2360,7 @@ async function buildSSRInMemory(productionVite, config, root, routeManager, apiR
|
|
|
2097
2360
|
let ssrEntryFile;
|
|
2098
2361
|
const pageRoutes = collectedPageRoutes.map((route) => ({ ...route }));
|
|
2099
2362
|
const layoutRoutes = collectedLayoutRoutes.map((route) => ({ ...route }));
|
|
2363
|
+
const routeSlots = collectedRouteSlots.map((slot) => ({ ...slot }));
|
|
2100
2364
|
const metadataImageRoutes = [];
|
|
2101
2365
|
for (const entry of routeManager.getMetadataImages().values()) {
|
|
2102
2366
|
if (entry.sourceType === "static") {
|
|
@@ -2197,6 +2461,7 @@ async function buildSSRInMemory(productionVite, config, root, routeManager, apiR
|
|
|
2197
2461
|
apiRoutes,
|
|
2198
2462
|
pageRoutes,
|
|
2199
2463
|
layoutRoutes,
|
|
2464
|
+
routeSlots,
|
|
2200
2465
|
errorRoutes,
|
|
2201
2466
|
metadataImageRoutes,
|
|
2202
2467
|
middlewareRoutes,
|
|
@@ -2367,10 +2632,14 @@ async function buildSSRInMemory(productionVite, config, root, routeManager, apiR
|
|
|
2367
2632
|
}
|
|
2368
2633
|
}
|
|
2369
2634
|
}
|
|
2370
|
-
return {
|
|
2635
|
+
return {
|
|
2636
|
+
bundle: ssrBundle,
|
|
2637
|
+
entryFile: ssrEntryFile,
|
|
2638
|
+
configuredHeaderRoutes
|
|
2639
|
+
};
|
|
2371
2640
|
}
|
|
2372
2641
|
__name(buildSSRInMemory, "buildSSRInMemory");
|
|
2373
|
-
function generateVirtualEntryCode(apiRoutes, pageRoutes, layoutRoutes, errorRoutes, metadataImageRoutes, middlewareRoutes, redirectRoutes, configuredRewriteRoutes, configuredHeaderRoutes, notFoundPath, config, configModulePath, hasServerRuntimeIntegrations, hasRuntimeIntegrationConfig, hasConfiguredRuntimePlugins, preset, i18nCatalogs) {
|
|
2642
|
+
function generateVirtualEntryCode(apiRoutes, pageRoutes, layoutRoutes, routeSlots, errorRoutes, metadataImageRoutes, middlewareRoutes, redirectRoutes, configuredRewriteRoutes, configuredHeaderRoutes, notFoundPath, config, configModulePath, hasServerRuntimeIntegrations, hasRuntimeIntegrationConfig, hasConfiguredRuntimePlugins, preset, i18nCatalogs) {
|
|
2374
2643
|
const hasPluginRuntime = hasRuntimeIntegrationConfig || hasConfiguredRuntimePlugins;
|
|
2375
2644
|
const hasMiddlewareRuntime = middlewareRoutes.length > 0 || hasFarmMiddlewareConfig(config.middleware);
|
|
2376
2645
|
const farmDocsBaseConfig = config.docs?.enabled ? { ...config.docs, config: void 0 } : void 0;
|
|
@@ -2414,10 +2683,12 @@ function generateVirtualEntryCode(apiRoutes, pageRoutes, layoutRoutes, errorRout
|
|
|
2414
2683
|
return;
|
|
2415
2684
|
}
|
|
2416
2685
|
pageImports.push(`import * as ${varName} from "${route.modulePath}";`);
|
|
2686
|
+
const shouldHydrate = getClientModuleMetadata(route.modulePath, config.root).shouldHydrate;
|
|
2417
2687
|
pageRegistrations.push(`
|
|
2418
2688
|
{
|
|
2419
2689
|
pattern: ${JSON.stringify(route.pattern)},
|
|
2420
2690
|
module: ${varName},
|
|
2691
|
+
shouldHydrate: ${JSON.stringify(shouldHydrate)},
|
|
2421
2692
|
}`);
|
|
2422
2693
|
});
|
|
2423
2694
|
const layoutImports = [];
|
|
@@ -2431,6 +2702,22 @@ function generateVirtualEntryCode(apiRoutes, pageRoutes, layoutRoutes, errorRout
|
|
|
2431
2702
|
module: ${varName},
|
|
2432
2703
|
}`);
|
|
2433
2704
|
});
|
|
2705
|
+
const routeSlotImports = [];
|
|
2706
|
+
const routeSlotRegistrations = [];
|
|
2707
|
+
routeSlots.forEach((slot, index) => {
|
|
2708
|
+
const varName = `routeSlot${index}`;
|
|
2709
|
+
routeSlotImports.push(`import * as ${varName} from "${slot.modulePath}";`);
|
|
2710
|
+
routeSlotRegistrations.push(`
|
|
2711
|
+
{
|
|
2712
|
+
name: ${JSON.stringify(slot.name)},
|
|
2713
|
+
ownerPattern: ${JSON.stringify(slot.ownerPattern)},
|
|
2714
|
+
pattern: ${JSON.stringify(slot.pattern)},
|
|
2715
|
+
containerId: ${JSON.stringify(slot.containerId)},
|
|
2716
|
+
interception: ${JSON.stringify(slot.interception)},
|
|
2717
|
+
fallback: ${JSON.stringify(slot.fallback)},
|
|
2718
|
+
module: ${varName},
|
|
2719
|
+
}`);
|
|
2720
|
+
});
|
|
2434
2721
|
const errorImports = [];
|
|
2435
2722
|
const errorRegistrations = [];
|
|
2436
2723
|
errorRoutes.forEach((errorRoute, index) => {
|
|
@@ -2481,6 +2768,7 @@ function generateVirtualEntryCode(apiRoutes, pageRoutes, layoutRoutes, errorRout
|
|
|
2481
2768
|
_runWithMiddlewareData,
|
|
2482
2769
|
addMetadataImageReference,
|
|
2483
2770
|
applyProductionMiddlewareHeaders,
|
|
2771
|
+
configureFarmCache,
|
|
2484
2772
|
configureFarmObservability,
|
|
2485
2773
|
createFarmCacheKey,
|
|
2486
2774
|
createFarmLocaleCookie,
|
|
@@ -2583,6 +2871,7 @@ async function handleAPIRequest(request) {
|
|
|
2583
2871
|
${apiImports.join("\n")}
|
|
2584
2872
|
${pageImports.join("\n")}
|
|
2585
2873
|
${layoutImports.join("\n")}
|
|
2874
|
+
${routeSlotImports.join("\n")}
|
|
2586
2875
|
${errorImports.join("\n")}
|
|
2587
2876
|
${metadataImageImports.join("\n")}
|
|
2588
2877
|
${middlewareImports.join("\n")}
|
|
@@ -2660,6 +2949,7 @@ const farmObservabilityConfig = farmUserConfig?.observability ?? ${JSON.stringif
|
|
|
2660
2949
|
config.observability ?? false
|
|
2661
2950
|
)};
|
|
2662
2951
|
configureFarmObservability(farmObservabilityConfig);
|
|
2952
|
+
configureFarmCache(farmResolvedRuntimeConfig.cache);
|
|
2663
2953
|
const farmI18nConfig = ${JSON.stringify(config.i18n)};
|
|
2664
2954
|
const farmI18nRuntime = ${config.i18n.enabled ? `createFarmI18nRuntime(farmI18nConfig, ${JSON.stringify(i18nCatalogs)})` : "null"};
|
|
2665
2955
|
${config.i18n.enabled ? "_setDefaultFarmI18nRuntime(farmI18nRuntime);" : ""}
|
|
@@ -2717,6 +3007,9 @@ for (const route of pageRoutes) {
|
|
|
2717
3007
|
const layoutRoutes = [${layoutRegistrations.join(",")}
|
|
2718
3008
|
];
|
|
2719
3009
|
|
|
3010
|
+
const routeSlots = [${routeSlotRegistrations.join(",")}
|
|
3011
|
+
];
|
|
3012
|
+
|
|
2720
3013
|
// Route-level error boundaries bundled at build time.
|
|
2721
3014
|
const errorRoutes = [${errorRegistrations.join(",")}
|
|
2722
3015
|
];
|
|
@@ -2751,18 +3044,21 @@ function serializeFarmInlineValue(value) {
|
|
|
2751
3044
|
.replace(/\\u2029/g, "\\\\u2029");
|
|
2752
3045
|
}
|
|
2753
3046
|
|
|
2754
|
-
function renderFarmClientBootstrapScript(canonicalPath) {
|
|
3047
|
+
function renderFarmClientBootstrapScript(canonicalPath, selectedRouteSlots) {
|
|
2755
3048
|
const integrationManifest = ${hasRuntimeIntegrationConfig ? "getRegisteredIntegrationAPIManifest()" : "{}"};
|
|
3049
|
+
const serializedRouteSlots = serializeFarmInlineValue(selectedRouteSlots || []);
|
|
2756
3050
|
let source = 'window.__FARM_INTEGRATION_API_MANIFEST__=' +
|
|
2757
3051
|
serializeFarmInlineValue(integrationManifest) +
|
|
2758
|
-
';';
|
|
3052
|
+
';window.__FARM_ROUTE_SLOTS__=' + serializedRouteSlots + ';';
|
|
2759
3053
|
if (typeof canonicalPath === "string" && canonicalPath.startsWith("/")) {
|
|
2760
3054
|
const serializedPath = serializeFarmInlineValue(canonicalPath);
|
|
2761
3055
|
source += 'if(location.pathname+location.search!==' + serializedPath + '){' +
|
|
2762
3056
|
'history.replaceState(Object.assign({},history.state||{},{path:' + serializedPath + '}),"",' +
|
|
2763
3057
|
serializedPath + ');}';
|
|
2764
3058
|
}
|
|
2765
|
-
return '<script>' +
|
|
3059
|
+
return '<script id="__farm_route_slots_data__" type="application/json">' +
|
|
3060
|
+
serializedRouteSlots +
|
|
3061
|
+
'</script><script>' + source + '</script>';
|
|
2766
3062
|
}
|
|
2767
3063
|
|
|
2768
3064
|
function escapeFarmHtmlAttribute(value) {
|
|
@@ -3512,6 +3808,79 @@ function matchPageRoute(pathname) {
|
|
|
3512
3808
|
return null;
|
|
3513
3809
|
}
|
|
3514
3810
|
|
|
3811
|
+
function matchesRoutePrefix(pathname, pattern) {
|
|
3812
|
+
if (pattern === "/") return true;
|
|
3813
|
+
const pathSegments = normalizeRuntimePath(pathname).split("/").filter(Boolean);
|
|
3814
|
+
const patternSegments = normalizeRuntimePath(pattern).split("/").filter(Boolean);
|
|
3815
|
+
if (patternSegments.length > pathSegments.length) return false;
|
|
3816
|
+
const candidate = "/" + pathSegments.slice(0, patternSegments.length).join("/");
|
|
3817
|
+
return matchRuntimePathPattern(pattern, candidate) !== null;
|
|
3818
|
+
}
|
|
3819
|
+
|
|
3820
|
+
function routeSlotSpecificity(slot) {
|
|
3821
|
+
return slot.pattern.split("/").reduce(function(score, segment) {
|
|
3822
|
+
if (!segment) return score;
|
|
3823
|
+
if (segment.startsWith("[[...")) return score + 1;
|
|
3824
|
+
if (segment.startsWith("[...")) return score + 2;
|
|
3825
|
+
if (segment.startsWith("[")) return score + 3;
|
|
3826
|
+
return score + 10;
|
|
3827
|
+
}, 0);
|
|
3828
|
+
}
|
|
3829
|
+
|
|
3830
|
+
function matchRouteSlots(pathname, interceptFrom) {
|
|
3831
|
+
const groups = new Map();
|
|
3832
|
+
for (const slot of routeSlots) {
|
|
3833
|
+
if (!matchesRoutePrefix(pathname, slot.ownerPattern)) continue;
|
|
3834
|
+
const key = slot.ownerPattern + ":" + slot.name;
|
|
3835
|
+
const entries = groups.get(key) || [];
|
|
3836
|
+
entries.push(slot);
|
|
3837
|
+
groups.set(key, entries);
|
|
3838
|
+
}
|
|
3839
|
+
|
|
3840
|
+
const normalizedFrom =
|
|
3841
|
+
typeof interceptFrom === "string" && interceptFrom.startsWith("/")
|
|
3842
|
+
? new URL(interceptFrom, "http://farm.local").pathname
|
|
3843
|
+
: null;
|
|
3844
|
+
const matches = [];
|
|
3845
|
+
|
|
3846
|
+
for (const entries of groups.values()) {
|
|
3847
|
+
const candidates = entries
|
|
3848
|
+
.filter(function(entry) { return !entry.fallback; })
|
|
3849
|
+
.filter(function(entry) {
|
|
3850
|
+
return !entry.interception ||
|
|
3851
|
+
(normalizedFrom && matchesRoutePrefix(normalizedFrom, entry.ownerPattern));
|
|
3852
|
+
})
|
|
3853
|
+
.map(function(entry) {
|
|
3854
|
+
return {
|
|
3855
|
+
entry: entry,
|
|
3856
|
+
params: matchRuntimePathPattern(entry.pattern, pathname),
|
|
3857
|
+
};
|
|
3858
|
+
})
|
|
3859
|
+
.filter(function(candidate) { return candidate.params !== null; })
|
|
3860
|
+
.sort(function(left, right) {
|
|
3861
|
+
if (left.entry.interception !== right.entry.interception) {
|
|
3862
|
+
return left.entry.interception ? -1 : 1;
|
|
3863
|
+
}
|
|
3864
|
+
return routeSlotSpecificity(right.entry) - routeSlotSpecificity(left.entry);
|
|
3865
|
+
});
|
|
3866
|
+
|
|
3867
|
+
if (candidates[0]) {
|
|
3868
|
+
matches.push({ ...candidates[0].entry, params: candidates[0].params });
|
|
3869
|
+
continue;
|
|
3870
|
+
}
|
|
3871
|
+
|
|
3872
|
+
const fallback = entries.find(function(entry) { return entry.fallback; });
|
|
3873
|
+
if (fallback) matches.push({ ...fallback, params: {} });
|
|
3874
|
+
}
|
|
3875
|
+
|
|
3876
|
+
return matches.sort(function(left, right) {
|
|
3877
|
+
const ownerDepth =
|
|
3878
|
+
left.ownerPattern.split("/").filter(Boolean).length -
|
|
3879
|
+
right.ownerPattern.split("/").filter(Boolean).length;
|
|
3880
|
+
return ownerDepth || left.name.localeCompare(right.name);
|
|
3881
|
+
});
|
|
3882
|
+
}
|
|
3883
|
+
|
|
3515
3884
|
function hasLocalRequestRoute(request, routePathname) {
|
|
3516
3885
|
const pathname = new URL(request.url).pathname;
|
|
3517
3886
|
if (matchLocalAPIRequest(request) || matchLocalIntegrationRequest(request)) {
|
|
@@ -3662,6 +4031,7 @@ function getPPRShellBypassReason(request, middlewareData, middlewareContext) {
|
|
|
3662
4031
|
if (method !== "GET" && method !== "HEAD") return "method";
|
|
3663
4032
|
if (request.headers.get("cookie")) return "cookie";
|
|
3664
4033
|
if (request.headers.get("authorization")) return "authorization";
|
|
4034
|
+
if (request.headers.get("x-farm-intercept-from")) return "route-interception";
|
|
3665
4035
|
if (request.headers.get("x-farm-ppr-refresh")) return "refresh";
|
|
3666
4036
|
if (hasConfiguredRouteContext) return "route-context";
|
|
3667
4037
|
if (middlewareData?.size) return "middleware-data";
|
|
@@ -3715,8 +4085,8 @@ function getRouteSharedCacheControl(routeModule, pprCanCache) {
|
|
|
3715
4085
|
return "public, s-maxage=" + revalidate + ", stale-while-revalidate=300";
|
|
3716
4086
|
}
|
|
3717
4087
|
|
|
3718
|
-
function getCachedPPRShell(cacheKey) {
|
|
3719
|
-
const entry = pprShellCache.
|
|
4088
|
+
async function getCachedPPRShell(cacheKey) {
|
|
4089
|
+
const entry = await pprShellCache.getEntryAsync(cacheKey);
|
|
3720
4090
|
if (!entry) {
|
|
3721
4091
|
return null;
|
|
3722
4092
|
}
|
|
@@ -3931,7 +4301,7 @@ async function handleFarmRequestInContext(
|
|
|
3931
4301
|
}
|
|
3932
4302
|
}
|
|
3933
4303
|
if (pprCacheKey) {
|
|
3934
|
-
const cachedPPRShell = getCachedPPRShell(pprCacheKey);
|
|
4304
|
+
const cachedPPRShell = await getCachedPPRShell(pprCacheKey);
|
|
3935
4305
|
if (cachedPPRShell) {
|
|
3936
4306
|
emitFarmEvent({ type: "ppr.shell.hit", route: pathname, key: pprCacheKey });
|
|
3937
4307
|
emitFarmEvent({
|
|
@@ -3959,6 +4329,10 @@ async function handleFarmRequestInContext(
|
|
|
3959
4329
|
|
|
3960
4330
|
// Get applicable layouts for this page
|
|
3961
4331
|
const applicableLayouts = getApplicableLayouts(routePathname);
|
|
4332
|
+
const selectedRouteSlots = matchRouteSlots(
|
|
4333
|
+
routePathname,
|
|
4334
|
+
request.headers.get("x-farm-intercept-from"),
|
|
4335
|
+
);
|
|
3962
4336
|
|
|
3963
4337
|
if (PageComponent) {
|
|
3964
4338
|
// Parse search params - make it a resolved Promise for async components
|
|
@@ -4046,6 +4420,82 @@ async function handleFarmRequestInContext(
|
|
|
4046
4420
|
throw routeStateError;
|
|
4047
4421
|
}
|
|
4048
4422
|
}
|
|
4423
|
+
|
|
4424
|
+
const renderedRouteSlots = await Promise.all(
|
|
4425
|
+
selectedRouteSlots.map(async function(slot) {
|
|
4426
|
+
const slotContext = hasConfiguredRouteContext
|
|
4427
|
+
? await resolveFarmRouteContext(farmResolvedRuntimeConfig, {
|
|
4428
|
+
request,
|
|
4429
|
+
params: slot.params,
|
|
4430
|
+
search: searchParamsObj,
|
|
4431
|
+
path: pathname,
|
|
4432
|
+
})
|
|
4433
|
+
: undefined;
|
|
4434
|
+
const rawSlotProps = withFarmRouteContext(
|
|
4435
|
+
{
|
|
4436
|
+
params: slot.params,
|
|
4437
|
+
searchParams: Promise.resolve(searchParamsObj),
|
|
4438
|
+
path: pathname,
|
|
4439
|
+
...(middlewareData?.size ? { middleware: { data: middlewareData } } : {}),
|
|
4440
|
+
},
|
|
4441
|
+
slotContext,
|
|
4442
|
+
);
|
|
4443
|
+
if (slot.module.__farmResolveRouteProps && slotContext !== undefined) {
|
|
4444
|
+
Object.defineProperty(rawSlotProps, "context", {
|
|
4445
|
+
value: slotContext,
|
|
4446
|
+
enumerable: true,
|
|
4447
|
+
configurable: true,
|
|
4448
|
+
});
|
|
4449
|
+
}
|
|
4450
|
+
|
|
4451
|
+
const slotSchemas = slot.module.__farmRouteParsesProps
|
|
4452
|
+
? {}
|
|
4453
|
+
: slot.module.__farmRouteSchemas || {};
|
|
4454
|
+
let slotProps = slot.module.__farmResolveRouteProps
|
|
4455
|
+
? await slot.module.__farmResolveRouteProps(rawSlotProps)
|
|
4456
|
+
: {
|
|
4457
|
+
...rawSlotProps,
|
|
4458
|
+
params: slotSchemas.params?.parse
|
|
4459
|
+
? slotSchemas.params.parse(slot.params)
|
|
4460
|
+
: slot.params,
|
|
4461
|
+
search: slotSchemas.search?.parse
|
|
4462
|
+
? slotSchemas.search.parse(searchParamsObj)
|
|
4463
|
+
: searchParamsObj,
|
|
4464
|
+
searchParams: Promise.resolve(
|
|
4465
|
+
slotSchemas.search?.parse
|
|
4466
|
+
? slotSchemas.search.parse(searchParamsObj)
|
|
4467
|
+
: searchParamsObj,
|
|
4468
|
+
),
|
|
4469
|
+
};
|
|
4470
|
+
if (
|
|
4471
|
+
slot.module.__farmResolveRouteProps &&
|
|
4472
|
+
slotContext !== undefined &&
|
|
4473
|
+
slotProps.context === slotContext
|
|
4474
|
+
) {
|
|
4475
|
+
const { context: _slotContext, ...renderSlotProps } = slotProps;
|
|
4476
|
+
slotProps = renderSlotProps;
|
|
4477
|
+
}
|
|
4478
|
+
|
|
4479
|
+
return { ...slot, props: slotProps };
|
|
4480
|
+
}),
|
|
4481
|
+
);
|
|
4482
|
+
const routeSlotPayload = renderedRouteSlots.map(function(slot) {
|
|
4483
|
+
return {
|
|
4484
|
+
name: slot.name,
|
|
4485
|
+
ownerPattern: slot.ownerPattern,
|
|
4486
|
+
pattern: slot.pattern,
|
|
4487
|
+
containerId: slot.containerId,
|
|
4488
|
+
interception: slot.interception,
|
|
4489
|
+
fallback: slot.fallback,
|
|
4490
|
+
props: {
|
|
4491
|
+
params: slot.props.params,
|
|
4492
|
+
search: slot.props.search || searchParamsObj,
|
|
4493
|
+
searchParams: slot.props.search || searchParamsObj,
|
|
4494
|
+
...("data" in slot.props ? { data: slot.props.data } : {}),
|
|
4495
|
+
path: pathname,
|
|
4496
|
+
},
|
|
4497
|
+
};
|
|
4498
|
+
});
|
|
4049
4499
|
|
|
4050
4500
|
const renderPageElement = async () => {
|
|
4051
4501
|
// First, render the page content
|
|
@@ -4073,6 +4523,14 @@ async function handleFarmRequestInContext(
|
|
|
4073
4523
|
pageElement = React.createElement(PageComponent, pageProps);
|
|
4074
4524
|
}
|
|
4075
4525
|
|
|
4526
|
+
if (route.shouldHydrate && renderedRouteSlots.length > 0) {
|
|
4527
|
+
pageElement = React.createElement(
|
|
4528
|
+
"div",
|
|
4529
|
+
{ id: "__farm_page__", "data-farm-client": "true" },
|
|
4530
|
+
pageElement,
|
|
4531
|
+
);
|
|
4532
|
+
}
|
|
4533
|
+
|
|
4076
4534
|
// Wrap with layouts (from innermost to outermost)
|
|
4077
4535
|
// Layouts are sorted by depth (root first), so we process in reverse
|
|
4078
4536
|
let wrappedElement = pageElement;
|
|
@@ -4080,9 +4538,23 @@ async function handleFarmRequestInContext(
|
|
|
4080
4538
|
const layout = applicableLayouts[i];
|
|
4081
4539
|
const LayoutComponent = layout.module.default;
|
|
4082
4540
|
if (LayoutComponent) {
|
|
4541
|
+
const slotProps = {};
|
|
4542
|
+
for (const slot of renderedRouteSlots) {
|
|
4543
|
+
if (slot.ownerPattern !== layout.pattern) continue;
|
|
4544
|
+
slotProps[slot.name] = React.createElement(
|
|
4545
|
+
"div",
|
|
4546
|
+
{
|
|
4547
|
+
id: slot.containerId,
|
|
4548
|
+
"data-farm-route-slot": slot.name,
|
|
4549
|
+
"data-farm-slot-owner": slot.ownerPattern,
|
|
4550
|
+
},
|
|
4551
|
+
React.createElement(slot.module.default, slot.props),
|
|
4552
|
+
);
|
|
4553
|
+
}
|
|
4083
4554
|
wrappedElement = React.createElement(LayoutComponent, {
|
|
4084
4555
|
children: wrappedElement,
|
|
4085
4556
|
params,
|
|
4557
|
+
...slotProps,
|
|
4086
4558
|
});
|
|
4087
4559
|
}
|
|
4088
4560
|
}
|
|
@@ -4134,6 +4606,7 @@ async function handleFarmRequestInContext(
|
|
|
4134
4606
|
);
|
|
4135
4607
|
const hasRequestScopedRender = Boolean(
|
|
4136
4608
|
pageStatus >= 400 ||
|
|
4609
|
+
request.headers.get("x-farm-intercept-from") ||
|
|
4137
4610
|
hasPrivateRequestHeaders ||
|
|
4138
4611
|
hasConfiguredRouteContext ||
|
|
4139
4612
|
middlewareData?.size ||
|
|
@@ -4173,7 +4646,10 @@ async function handleFarmRequestInContext(
|
|
|
4173
4646
|
' <link rel="modulepreload" href="/farm-client.js">\\n' +
|
|
4174
4647
|
'</head>\\n<body>\\n <div id="root">';
|
|
4175
4648
|
const streamSuffix = '</div>\\n' +
|
|
4176
|
-
' ' + renderFarmClientBootstrapScript(
|
|
4649
|
+
' ' + renderFarmClientBootstrapScript(
|
|
4650
|
+
pageProps.__farmCanonicalPath,
|
|
4651
|
+
routeSlotPayload
|
|
4652
|
+
) + '\\n' +
|
|
4177
4653
|
' <script type="module" src="/farm-client.js"></script>\\n' +
|
|
4178
4654
|
'</body>\\n</html>';
|
|
4179
4655
|
const streamedDocument = createFarmDocumentStream(
|
|
@@ -4230,7 +4706,10 @@ async function handleFarmRequestInContext(
|
|
|
4230
4706
|
// Inject client script before closing body tag
|
|
4231
4707
|
.replace(
|
|
4232
4708
|
/<\\/body>/i,
|
|
4233
|
-
' ' + renderFarmClientBootstrapScript(
|
|
4709
|
+
' ' + renderFarmClientBootstrapScript(
|
|
4710
|
+
pageProps.__farmCanonicalPath,
|
|
4711
|
+
routeSlotPayload
|
|
4712
|
+
) + '\\n' +
|
|
4234
4713
|
' <script type="module" src="/farm-client.js"></script>\\n</body>',
|
|
4235
4714
|
);
|
|
4236
4715
|
|
|
@@ -4251,7 +4730,7 @@ async function handleFarmRequestInContext(
|
|
|
4251
4730
|
</head>
|
|
4252
4731
|
<body>
|
|
4253
4732
|
<div id="root">\${html}</div>
|
|
4254
|
-
\${renderFarmClientBootstrapScript(pageProps.__farmCanonicalPath)}
|
|
4733
|
+
\${renderFarmClientBootstrapScript(pageProps.__farmCanonicalPath, routeSlotPayload)}
|
|
4255
4734
|
<script type="module" src="/farm-client.js"></script>
|
|
4256
4735
|
</body>
|
|
4257
4736
|
</html>\`;
|
|
@@ -4259,7 +4738,7 @@ async function handleFarmRequestInContext(
|
|
|
4259
4738
|
fullHtml = applyFarmI18nDocument(fullHtml, pathname, farmI18nSnapshot);
|
|
4260
4739
|
|
|
4261
4740
|
if (pageStatus === 200 && pprCacheKey && request.method.toUpperCase() !== "HEAD") {
|
|
4262
|
-
pprShellCache.
|
|
4741
|
+
await pprShellCache.setAsync(
|
|
4263
4742
|
pprCacheKey,
|
|
4264
4743
|
{ html: fullHtml },
|
|
4265
4744
|
{
|
|
@@ -5759,4 +6238,4 @@ __name(buildNitro, "buildNitro");
|
|
|
5759
6238
|
export {
|
|
5760
6239
|
build
|
|
5761
6240
|
};
|
|
5762
|
-
//# sourceMappingURL=chunk-
|
|
6241
|
+
//# sourceMappingURL=chunk-2NHCNRF6.mjs.map
|