@react-router/dev 0.0.0-experimental-a383e1e6e → 0.0.0-experimental-fde52e515
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/CHANGELOG.md +9 -0
- package/bin.js +2 -2
- package/dist/cli/index.js +301 -159
- package/dist/config.js +1 -1
- package/dist/routes.js +1 -1
- package/dist/vite/cloudflare.js +1 -1
- package/dist/vite.js +469 -231
- package/package.json +6 -6
package/dist/vite.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @react-router/dev v0.0.0-experimental-
|
|
2
|
+
* @react-router/dev v0.0.0-experimental-fde52e515
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -52,6 +52,7 @@ var fse = __toESM(require("fs-extra"));
|
|
|
52
52
|
var babel = __toESM(require("@babel/core"));
|
|
53
53
|
var import_react_router2 = require("react-router");
|
|
54
54
|
var import_es_module_lexer = require("es-module-lexer");
|
|
55
|
+
var import_pick3 = __toESM(require("lodash/pick"));
|
|
55
56
|
var import_jsesc = __toESM(require("jsesc"));
|
|
56
57
|
var import_picocolors3 = __toESM(require("picocolors"));
|
|
57
58
|
var import_kebabCase = __toESM(require("lodash/kebabCase"));
|
|
@@ -271,6 +272,13 @@ var detectPackageManager = () => {
|
|
|
271
272
|
|
|
272
273
|
// config/config.ts
|
|
273
274
|
var excludedConfigPresetKeys = ["presets"];
|
|
275
|
+
var branchRouteProperties = [
|
|
276
|
+
"id",
|
|
277
|
+
"path",
|
|
278
|
+
"file",
|
|
279
|
+
"index"
|
|
280
|
+
];
|
|
281
|
+
var configRouteToBranchRoute = (configRoute) => (0, import_pick2.default)(configRoute, branchRouteProperties);
|
|
274
282
|
var mergeReactRouterConfig = (...configs) => {
|
|
275
283
|
let reducer = (configA, configB) => {
|
|
276
284
|
let mergeRequired = (key) => configA[key] !== void 0 && configB[key] !== void 0;
|
|
@@ -694,8 +702,6 @@ function generate(ctx, route) {
|
|
|
694
702
|
export type HeadersArgs = T.HeadersArgs
|
|
695
703
|
export type HeadersFunction = (args: HeadersArgs) => Headers | HeadersInit
|
|
696
704
|
|
|
697
|
-
export type unstable_MiddlewareArgs = T.CreateServerMiddlewareArgs<Info>
|
|
698
|
-
export type unstable_ClientMiddlewareArgs = T.CreateClientMiddlewareArgs<Info>
|
|
699
705
|
export type LoaderArgs = T.CreateServerLoaderArgs<Info>
|
|
700
706
|
export type ClientLoaderArgs = T.CreateClientLoaderArgs<Info>
|
|
701
707
|
export type ActionArgs = T.CreateServerActionArgs<Info>
|
|
@@ -1800,6 +1806,8 @@ var plugin = {
|
|
|
1800
1806
|
return function Wrapped() {
|
|
1801
1807
|
const props = {
|
|
1802
1808
|
params: useParams(),
|
|
1809
|
+
loaderData: useLoaderData(),
|
|
1810
|
+
actionData: useActionData(),
|
|
1803
1811
|
};
|
|
1804
1812
|
return h(HydrateFallback, props);
|
|
1805
1813
|
};
|
|
@@ -1893,27 +1901,18 @@ function toFunctionExpression(decl) {
|
|
|
1893
1901
|
}
|
|
1894
1902
|
|
|
1895
1903
|
// vite/plugin.ts
|
|
1896
|
-
var SERVER_ONLY_ROUTE_EXPORTS = [
|
|
1897
|
-
|
|
1898
|
-
"action",
|
|
1899
|
-
"unstable_middleware",
|
|
1900
|
-
"headers"
|
|
1901
|
-
];
|
|
1902
|
-
var CLIENT_ONLY_NON_COMPONENT_EXPORTS = [
|
|
1904
|
+
var SERVER_ONLY_ROUTE_EXPORTS = ["loader", "action", "headers"];
|
|
1905
|
+
var CLIENT_ROUTE_EXPORTS = [
|
|
1903
1906
|
"clientAction",
|
|
1904
1907
|
"clientLoader",
|
|
1905
|
-
"unstable_clientMiddleware",
|
|
1906
|
-
"handle",
|
|
1907
|
-
"meta",
|
|
1908
|
-
"links",
|
|
1909
|
-
"shouldRevalidate"
|
|
1910
|
-
];
|
|
1911
|
-
var CLIENT_ROUTE_EXPORTS = [
|
|
1912
|
-
...CLIENT_ONLY_NON_COMPONENT_EXPORTS,
|
|
1913
1908
|
"default",
|
|
1914
1909
|
"ErrorBoundary",
|
|
1910
|
+
"handle",
|
|
1915
1911
|
"HydrateFallback",
|
|
1916
|
-
"Layout"
|
|
1912
|
+
"Layout",
|
|
1913
|
+
"links",
|
|
1914
|
+
"meta",
|
|
1915
|
+
"shouldRevalidate"
|
|
1917
1916
|
];
|
|
1918
1917
|
var BUILD_CLIENT_ROUTE_QUERY_STRING = "?__react-router-build-client-route";
|
|
1919
1918
|
var isRouteEntryModuleId = (id) => {
|
|
@@ -2074,16 +2073,24 @@ var getRouteModuleExports = async (viteChildCompiler, ctx, routeFile, readRouteF
|
|
|
2074
2073
|
);
|
|
2075
2074
|
return getExportNames(code);
|
|
2076
2075
|
};
|
|
2077
|
-
var
|
|
2078
|
-
|
|
2076
|
+
var resolveEnvironmentBuildContext = ({
|
|
2077
|
+
viteCommand,
|
|
2078
|
+
viteUserConfig
|
|
2079
|
+
}) => {
|
|
2080
|
+
if (!("__reactRouterEnvironmentBuildContext" in viteUserConfig) || !viteUserConfig.__reactRouterEnvironmentBuildContext) {
|
|
2079
2081
|
return null;
|
|
2080
2082
|
}
|
|
2081
|
-
|
|
2083
|
+
let buildContext = viteUserConfig.__reactRouterEnvironmentBuildContext;
|
|
2084
|
+
let resolvedBuildContext = {
|
|
2085
|
+
name: buildContext.name,
|
|
2086
|
+
options: buildContext.resolveOptions({ viteCommand, viteUserConfig })
|
|
2087
|
+
};
|
|
2088
|
+
return resolvedBuildContext;
|
|
2082
2089
|
};
|
|
2083
|
-
var getServerBuildDirectory = (ctx) => path6.join(
|
|
2090
|
+
var getServerBuildDirectory = (ctx, { serverBundleId } = {}) => path6.join(
|
|
2084
2091
|
ctx.reactRouterConfig.buildDirectory,
|
|
2085
2092
|
"server",
|
|
2086
|
-
...
|
|
2093
|
+
...serverBundleId ? [serverBundleId] : []
|
|
2087
2094
|
);
|
|
2088
2095
|
var getClientBuildDirectory = (reactRouterConfig) => path6.join(reactRouterConfig.buildDirectory, "client");
|
|
2089
2096
|
var defaultEntriesDir = path6.resolve(
|
|
@@ -2135,36 +2142,36 @@ var reactRouterVitePlugin = () => {
|
|
|
2135
2142
|
process.exit(1);
|
|
2136
2143
|
}
|
|
2137
2144
|
let viteManifestEnabled = viteUserConfig.build?.manifest === true;
|
|
2138
|
-
let
|
|
2139
|
-
isSsrBuild: true,
|
|
2140
|
-
getReactRouterServerManifest: async () => (await generateReactRouterManifestsForBuild()).reactRouterServerManifest,
|
|
2141
|
-
serverBundleBuildConfig: getServerBundleBuildConfig(viteUserConfig)
|
|
2142
|
-
} : { isSsrBuild: false };
|
|
2145
|
+
let environmentBuildContext = viteCommand === "build" ? resolveEnvironmentBuildContext({ viteCommand, viteUserConfig }) : null;
|
|
2143
2146
|
firstLoad = false;
|
|
2144
2147
|
ctx = {
|
|
2148
|
+
environmentBuildContext,
|
|
2145
2149
|
reactRouterConfig,
|
|
2146
2150
|
rootDirectory,
|
|
2147
2151
|
entryClientFilePath,
|
|
2148
2152
|
entryServerFilePath,
|
|
2149
2153
|
publicPath,
|
|
2150
|
-
viteManifestEnabled
|
|
2151
|
-
...ssrBuildCtx
|
|
2154
|
+
viteManifestEnabled
|
|
2152
2155
|
};
|
|
2153
2156
|
};
|
|
2154
2157
|
let pluginIndex = (pluginName) => {
|
|
2155
2158
|
invariant(viteConfig);
|
|
2156
2159
|
return viteConfig.plugins.findIndex((plugin2) => plugin2.name === pluginName);
|
|
2157
2160
|
};
|
|
2158
|
-
let getServerEntry = async () => {
|
|
2161
|
+
let getServerEntry = async ({ routeIds }) => {
|
|
2159
2162
|
invariant(viteConfig, "viteconfig required to generate the server entry");
|
|
2160
|
-
let routes =
|
|
2163
|
+
let routes = routeIds ? (
|
|
2161
2164
|
// For server bundle builds, the server build should only import the
|
|
2162
2165
|
// routes for this bundle rather than importing all routes
|
|
2163
|
-
ctx.
|
|
2166
|
+
(0, import_pick3.default)(ctx.reactRouterConfig.routes, routeIds)
|
|
2164
2167
|
) : (
|
|
2165
2168
|
// Otherwise, all routes are imported as usual
|
|
2166
2169
|
ctx.reactRouterConfig.routes
|
|
2167
2170
|
);
|
|
2171
|
+
let prerenderPaths = await getPrerenderPaths(
|
|
2172
|
+
ctx.reactRouterConfig.prerender,
|
|
2173
|
+
routes
|
|
2174
|
+
);
|
|
2168
2175
|
return `
|
|
2169
2176
|
import * as entryServer from ${JSON.stringify(
|
|
2170
2177
|
resolveFileUrl(ctx, ctx.entryServerFilePath)
|
|
@@ -2179,7 +2186,7 @@ var reactRouterVitePlugin = () => {
|
|
|
2179
2186
|
)};`;
|
|
2180
2187
|
}).join("\n")}
|
|
2181
2188
|
export { default as assets } from ${JSON.stringify(
|
|
2182
|
-
virtual.serverManifest.id
|
|
2189
|
+
`${virtual.serverManifest.id}${routeIds ? `?route-ids=${routeIds.join(",")}` : ""}`
|
|
2183
2190
|
)};
|
|
2184
2191
|
export const assetsBuildDirectory = ${JSON.stringify(
|
|
2185
2192
|
path6.relative(
|
|
@@ -2191,6 +2198,7 @@ var reactRouterVitePlugin = () => {
|
|
|
2191
2198
|
export const future = ${JSON.stringify(ctx.reactRouterConfig.future)};
|
|
2192
2199
|
export const ssr = ${ctx.reactRouterConfig.ssr};
|
|
2193
2200
|
export const isSpaMode = ${isSpaModeEnabled(ctx.reactRouterConfig)};
|
|
2201
|
+
export const prerender = ${JSON.stringify(prerenderPaths)};
|
|
2194
2202
|
export const publicPath = ${JSON.stringify(ctx.publicPath)};
|
|
2195
2203
|
export const entry = { module: entryServer };
|
|
2196
2204
|
export const routes = {
|
|
@@ -2228,7 +2236,9 @@ var reactRouterVitePlugin = () => {
|
|
|
2228
2236
|
);
|
|
2229
2237
|
return /* @__PURE__ */ new Set([...cssUrlPaths, ...chunkAssetPaths]);
|
|
2230
2238
|
};
|
|
2231
|
-
let generateReactRouterManifestsForBuild = async (
|
|
2239
|
+
let generateReactRouterManifestsForBuild = async ({
|
|
2240
|
+
routeIds
|
|
2241
|
+
}) => {
|
|
2232
2242
|
invariant(viteConfig);
|
|
2233
2243
|
let viteManifest = await loadViteManifest(
|
|
2234
2244
|
getClientBuildDirectory(ctx.reactRouterConfig)
|
|
@@ -2245,9 +2255,9 @@ var reactRouterVitePlugin = () => {
|
|
|
2245
2255
|
ctx
|
|
2246
2256
|
);
|
|
2247
2257
|
let enforceSplitRouteModules = ctx.reactRouterConfig.future.unstable_splitRouteModules === "enforce";
|
|
2248
|
-
for (let
|
|
2258
|
+
for (let route of Object.values(ctx.reactRouterConfig.routes)) {
|
|
2249
2259
|
let routeFile = path6.join(ctx.reactRouterConfig.appDirectory, route.file);
|
|
2250
|
-
let sourceExports = routeManifestExports[
|
|
2260
|
+
let sourceExports = routeManifestExports[route.id];
|
|
2251
2261
|
let isRootRoute = route.parentId === void 0;
|
|
2252
2262
|
let hasClientAction = sourceExports.includes("clientAction");
|
|
2253
2263
|
let hasClientLoader = sourceExports.includes("clientLoader");
|
|
@@ -2305,10 +2315,9 @@ var reactRouterVitePlugin = () => {
|
|
|
2305
2315
|
getRouteChunkModuleId(routeFile, "HydrateFallback")
|
|
2306
2316
|
) : void 0
|
|
2307
2317
|
};
|
|
2308
|
-
browserRoutes[
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
serverRoutes[key] = routeManifestEntry;
|
|
2318
|
+
browserRoutes[route.id] = routeManifestEntry;
|
|
2319
|
+
if (!routeIds || routeIds.includes(route.id)) {
|
|
2320
|
+
serverRoutes[route.id] = routeManifestEntry;
|
|
2312
2321
|
}
|
|
2313
2322
|
}
|
|
2314
2323
|
let fingerprintedValues = { entry, routes: browserRoutes };
|
|
@@ -2456,23 +2465,6 @@ var reactRouterVitePlugin = () => {
|
|
|
2456
2465
|
""
|
|
2457
2466
|
)
|
|
2458
2467
|
);
|
|
2459
|
-
let baseRollupOptions = {
|
|
2460
|
-
// Silence Rollup "use client" warnings
|
|
2461
|
-
// Adapted from https://github.com/vitejs/vite-plugin-react/pull/144
|
|
2462
|
-
onwarn(warning, defaultHandler) {
|
|
2463
|
-
if (warning.code === "MODULE_LEVEL_DIRECTIVE" && warning.message.includes("use client")) {
|
|
2464
|
-
return;
|
|
2465
|
-
}
|
|
2466
|
-
if (viteUserConfig.build?.rollupOptions?.onwarn) {
|
|
2467
|
-
viteUserConfig.build.rollupOptions.onwarn(
|
|
2468
|
-
warning,
|
|
2469
|
-
defaultHandler
|
|
2470
|
-
);
|
|
2471
|
-
} else {
|
|
2472
|
-
defaultHandler(warning);
|
|
2473
|
-
}
|
|
2474
|
-
}
|
|
2475
|
-
};
|
|
2476
2468
|
return {
|
|
2477
2469
|
__reactRouterPluginContext: ctx,
|
|
2478
2470
|
appType: viteCommand === "serve" && viteConfigEnv.mode === "production" && ctx.reactRouterConfig.ssr === false ? "spa" : "custom",
|
|
@@ -2530,83 +2522,11 @@ var reactRouterVitePlugin = () => {
|
|
|
2530
2522
|
// will throw an error that the file is not allowed to be read.
|
|
2531
2523
|
// https://vitejs.dev/config/server-options#server-fs-allow
|
|
2532
2524
|
server: viteUserConfig.server?.fs?.allow ? { fs: { allow: defaultEntries } } : void 0,
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
manifest: true,
|
|
2539
|
-
outDir: getClientBuildDirectory(ctx.reactRouterConfig),
|
|
2540
|
-
rollupOptions: {
|
|
2541
|
-
...baseRollupOptions,
|
|
2542
|
-
preserveEntrySignatures: "exports-only",
|
|
2543
|
-
output: {
|
|
2544
|
-
entryFileNames({ moduleIds }) {
|
|
2545
|
-
let routeChunkModuleId = moduleIds.find(isRouteChunkModuleId);
|
|
2546
|
-
let routeChunkName = routeChunkModuleId ? getRouteChunkNameFromModuleId(
|
|
2547
|
-
routeChunkModuleId
|
|
2548
|
-
) : null;
|
|
2549
|
-
let routeChunkSuffix = routeChunkName ? `-${(0, import_kebabCase.default)(routeChunkName)}` : "";
|
|
2550
|
-
return `assets/[name]${routeChunkSuffix}-[hash].js`;
|
|
2551
|
-
}
|
|
2552
|
-
},
|
|
2553
|
-
input: [
|
|
2554
|
-
ctx.entryClientFilePath,
|
|
2555
|
-
...Object.values(
|
|
2556
|
-
ctx.reactRouterConfig.routes
|
|
2557
|
-
).flatMap((route) => {
|
|
2558
|
-
let routeFilePath = path6.resolve(
|
|
2559
|
-
ctx.reactRouterConfig.appDirectory,
|
|
2560
|
-
route.file
|
|
2561
|
-
);
|
|
2562
|
-
let isRootRoute = route.file === ctx.reactRouterConfig.routes.root.file;
|
|
2563
|
-
let code = fse.readFileSync(
|
|
2564
|
-
routeFilePath,
|
|
2565
|
-
"utf-8"
|
|
2566
|
-
);
|
|
2567
|
-
return [
|
|
2568
|
-
`${routeFilePath}${BUILD_CLIENT_ROUTE_QUERY_STRING}`,
|
|
2569
|
-
...ctx.reactRouterConfig.future.unstable_splitRouteModules && !isRootRoute ? routeChunkExportNames.map(
|
|
2570
|
-
(exportName) => code.includes(exportName) ? getRouteChunkModuleId(
|
|
2571
|
-
routeFilePath,
|
|
2572
|
-
exportName
|
|
2573
|
-
) : null
|
|
2574
|
-
) : []
|
|
2575
|
-
].filter(isNonNullable);
|
|
2576
|
-
})
|
|
2577
|
-
]
|
|
2578
|
-
}
|
|
2579
|
-
} : {
|
|
2580
|
-
// We move SSR-only assets to client assets. Note that the
|
|
2581
|
-
// SSR build can also emit code-split JS files (e.g. by
|
|
2582
|
-
// dynamic import) under the same assets directory
|
|
2583
|
-
// regardless of "ssrEmitAssets" option, so we also need to
|
|
2584
|
-
// keep these JS files have to be kept as-is.
|
|
2585
|
-
ssrEmitAssets: true,
|
|
2586
|
-
copyPublicDir: false,
|
|
2587
|
-
// Assets in the public directory are only used by the client
|
|
2588
|
-
manifest: true,
|
|
2589
|
-
// We need the manifest to detect SSR-only assets
|
|
2590
|
-
outDir: getServerBuildDirectory(ctx),
|
|
2591
|
-
rollupOptions: {
|
|
2592
|
-
...baseRollupOptions,
|
|
2593
|
-
preserveEntrySignatures: "exports-only",
|
|
2594
|
-
input: viteUserConfig.build?.rollupOptions?.input ?? virtual.serverBuild.id,
|
|
2595
|
-
output: {
|
|
2596
|
-
entryFileNames: ctx.reactRouterConfig.serverBuildFile,
|
|
2597
|
-
format: ctx.reactRouterConfig.serverModuleFormat
|
|
2598
|
-
}
|
|
2599
|
-
}
|
|
2600
|
-
}
|
|
2601
|
-
}
|
|
2602
|
-
} : void 0,
|
|
2603
|
-
// Vite config options for SPA preview mode
|
|
2604
|
-
...viteCommand === "serve" && ctx.reactRouterConfig.ssr === false ? {
|
|
2605
|
-
build: {
|
|
2606
|
-
manifest: true,
|
|
2607
|
-
outDir: getClientBuildDirectory(ctx.reactRouterConfig)
|
|
2608
|
-
}
|
|
2609
|
-
} : void 0
|
|
2525
|
+
build: ctx.environmentBuildContext?.options.build ?? (await getEnvironmentOptions(
|
|
2526
|
+
ctx,
|
|
2527
|
+
viteConfigEnv.isSsrBuild ? "ssr" : "client",
|
|
2528
|
+
{ viteCommand, viteUserConfig }
|
|
2529
|
+
)).build
|
|
2610
2530
|
};
|
|
2611
2531
|
},
|
|
2612
2532
|
async configResolved(resolvedViteConfig) {
|
|
@@ -2622,8 +2542,7 @@ var reactRouterVitePlugin = () => {
|
|
|
2622
2542
|
let childCompilerConfigFile = await vite2.loadConfigFromFile(
|
|
2623
2543
|
{
|
|
2624
2544
|
command: viteConfig.command,
|
|
2625
|
-
mode: viteConfig.mode
|
|
2626
|
-
isSsrBuild: ctx.isSsrBuild
|
|
2545
|
+
mode: viteConfig.mode
|
|
2627
2546
|
},
|
|
2628
2547
|
viteConfig.configFile
|
|
2629
2548
|
);
|
|
@@ -2765,14 +2684,14 @@ var reactRouterVitePlugin = () => {
|
|
|
2765
2684
|
// After the SSR build is finished, we inspect the Vite manifest for
|
|
2766
2685
|
// the SSR build and move server-only assets to client assets directory
|
|
2767
2686
|
async handler() {
|
|
2768
|
-
if (!
|
|
2687
|
+
if (!viteConfigEnv.isSsrBuild) {
|
|
2769
2688
|
return;
|
|
2770
2689
|
}
|
|
2771
2690
|
invariant(viteConfig);
|
|
2772
2691
|
let clientBuildDirectory = getClientBuildDirectory(
|
|
2773
2692
|
ctx.reactRouterConfig
|
|
2774
2693
|
);
|
|
2775
|
-
let serverBuildDirectory = getServerBuildDirectory(ctx);
|
|
2694
|
+
let serverBuildDirectory = ctx.environmentBuildContext?.options.build.outDir ?? getServerBuildDirectory(ctx);
|
|
2776
2695
|
let ssrViteManifest = await loadViteManifest(serverBuildDirectory);
|
|
2777
2696
|
let ssrAssetPaths = getViteManifestAssetPaths(ssrViteManifest);
|
|
2778
2697
|
let movedAssetPaths = [];
|
|
@@ -2806,7 +2725,7 @@ var reactRouterVitePlugin = () => {
|
|
|
2806
2725
|
].join("\n")
|
|
2807
2726
|
);
|
|
2808
2727
|
}
|
|
2809
|
-
if (ctx.reactRouterConfig
|
|
2728
|
+
if (isPrerenderingEnabled(ctx.reactRouterConfig)) {
|
|
2810
2729
|
await handlePrerender(
|
|
2811
2730
|
viteConfig,
|
|
2812
2731
|
ctx.reactRouterConfig,
|
|
@@ -2961,16 +2880,25 @@ var reactRouterVitePlugin = () => {
|
|
|
2961
2880
|
name: "react-router:virtual-modules",
|
|
2962
2881
|
enforce: "pre",
|
|
2963
2882
|
resolveId(id) {
|
|
2964
|
-
|
|
2965
|
-
|
|
2883
|
+
let [baseId, queryString] = id.split("?");
|
|
2884
|
+
const vmod2 = Object.values(virtual).find((vmod3) => vmod3.id === baseId);
|
|
2885
|
+
if (vmod2)
|
|
2886
|
+
return vmod2.resolvedId + (queryString ? `?${queryString}` : "");
|
|
2966
2887
|
},
|
|
2967
2888
|
async load(id) {
|
|
2968
|
-
|
|
2889
|
+
let [baseId, queryString] = id.split("?");
|
|
2890
|
+
switch (baseId) {
|
|
2969
2891
|
case virtual.serverBuild.resolvedId: {
|
|
2970
|
-
|
|
2892
|
+
let searchParams = new URLSearchParams(queryString);
|
|
2893
|
+
let routeIds = searchParams.get("route-ids")?.split(",") || void 0;
|
|
2894
|
+
return await getServerEntry({ routeIds });
|
|
2971
2895
|
}
|
|
2972
2896
|
case virtual.serverManifest.resolvedId: {
|
|
2973
|
-
let
|
|
2897
|
+
let searchParams = new URLSearchParams(queryString);
|
|
2898
|
+
let routeIds = searchParams.get("route-ids")?.split(",") || void 0;
|
|
2899
|
+
let reactRouterManifest = viteCommand === "build" ? (await generateReactRouterManifestsForBuild({
|
|
2900
|
+
routeIds
|
|
2901
|
+
})).reactRouterServerManifest : await getReactRouterManifestForDev();
|
|
2974
2902
|
return `export default ${(0, import_jsesc.default)(reactRouterManifest, {
|
|
2975
2903
|
es6: true
|
|
2976
2904
|
})};`;
|
|
@@ -3071,12 +2999,15 @@ var reactRouterVitePlugin = () => {
|
|
|
3071
2999
|
if (!route) return;
|
|
3072
3000
|
if (!options?.ssr && isSpaModeEnabled(ctx.reactRouterConfig)) {
|
|
3073
3001
|
let exportNames = getExportNames(code);
|
|
3074
|
-
let serverOnlyExports = exportNames.filter(
|
|
3075
|
-
(exp
|
|
3076
|
-
|
|
3002
|
+
let serverOnlyExports = exportNames.filter((exp) => {
|
|
3003
|
+
if (route.id === "root" && exp === "loader") {
|
|
3004
|
+
return false;
|
|
3005
|
+
}
|
|
3006
|
+
return SERVER_ONLY_ROUTE_EXPORTS.includes(exp);
|
|
3007
|
+
});
|
|
3077
3008
|
if (serverOnlyExports.length > 0) {
|
|
3078
3009
|
let str = serverOnlyExports.map((e) => `\`${e}\``).join(", ");
|
|
3079
|
-
let message = `SPA Mode: ${serverOnlyExports.length} invalid route export(s) in \`${route.file}\`: ${str}. See https://
|
|
3010
|
+
let message = `SPA Mode: ${serverOnlyExports.length} invalid route export(s) in \`${route.file}\`: ${str}. See https://reactrouter.com/how-to/spa for more information.`;
|
|
3080
3011
|
throw Error(message);
|
|
3081
3012
|
}
|
|
3082
3013
|
if (route.id !== "root") {
|
|
@@ -3084,7 +3015,7 @@ var reactRouterVitePlugin = () => {
|
|
|
3084
3015
|
(exp) => exp === "HydrateFallback"
|
|
3085
3016
|
);
|
|
3086
3017
|
if (hasHydrateFallback) {
|
|
3087
|
-
let message = `SPA Mode: Invalid \`HydrateFallback\` export found in \`${route.file}\`. \`HydrateFallback\` is only permitted on the root route in SPA Mode. See https://
|
|
3018
|
+
let message = `SPA Mode: Invalid \`HydrateFallback\` export found in \`${route.file}\`. \`HydrateFallback\` is only permitted on the root route in SPA Mode. See https://reactrouter.com/how-to/spa for more information.`;
|
|
3088
3019
|
throw Error(message);
|
|
3089
3020
|
}
|
|
3090
3021
|
}
|
|
@@ -3271,7 +3202,14 @@ function uniqueNodes(nodes) {
|
|
|
3271
3202
|
}
|
|
3272
3203
|
function addRefreshWrapper(reactRouterConfig, code, id) {
|
|
3273
3204
|
let route = getRoute(reactRouterConfig, id);
|
|
3274
|
-
let acceptExports = route ?
|
|
3205
|
+
let acceptExports = route ? [
|
|
3206
|
+
"clientAction",
|
|
3207
|
+
"clientLoader",
|
|
3208
|
+
"handle",
|
|
3209
|
+
"meta",
|
|
3210
|
+
"links",
|
|
3211
|
+
"shouldRevalidate"
|
|
3212
|
+
] : [];
|
|
3275
3213
|
return REACT_REFRESH_HEADER.replaceAll("__SOURCE__", JSON.stringify(id)) + code + REACT_REFRESH_FOOTER.replaceAll("__SOURCE__", JSON.stringify(id)).replaceAll("__ACCEPT_EXPORTS__", JSON.stringify(acceptExports)).replaceAll("__ROUTE_ID__", JSON.stringify(route?.id));
|
|
3276
3214
|
}
|
|
3277
3215
|
var REACT_REFRESH_HEADER = `
|
|
@@ -3370,8 +3308,11 @@ async function getRouteMetadata(cache, ctx, viteChildCompiler, route, readRouteF
|
|
|
3370
3308
|
};
|
|
3371
3309
|
return info;
|
|
3372
3310
|
}
|
|
3311
|
+
function isPrerenderingEnabled(reactRouterConfig) {
|
|
3312
|
+
return reactRouterConfig.prerender != null && reactRouterConfig.prerender !== false;
|
|
3313
|
+
}
|
|
3373
3314
|
function isSpaModeEnabled(reactRouterConfig) {
|
|
3374
|
-
return reactRouterConfig.ssr === false && (reactRouterConfig
|
|
3315
|
+
return reactRouterConfig.ssr === false && !isPrerenderingEnabled(reactRouterConfig);
|
|
3375
3316
|
}
|
|
3376
3317
|
async function getPrerenderBuildAndHandler(viteConfig, serverBuildDirectory, serverBuildFile) {
|
|
3377
3318
|
let serverBuildPath = path6.join(serverBuildDirectory, serverBuildFile);
|
|
@@ -3383,20 +3324,44 @@ async function getPrerenderBuildAndHandler(viteConfig, serverBuildDirectory, ser
|
|
|
3383
3324
|
};
|
|
3384
3325
|
}
|
|
3385
3326
|
async function handleSpaMode(viteConfig, reactRouterConfig, serverBuildDirectory, serverBuildFile, clientBuildDirectory) {
|
|
3386
|
-
let { handler } = await getPrerenderBuildAndHandler(
|
|
3327
|
+
let { build, handler } = await getPrerenderBuildAndHandler(
|
|
3387
3328
|
viteConfig,
|
|
3388
3329
|
serverBuildDirectory,
|
|
3389
3330
|
serverBuildFile
|
|
3390
3331
|
);
|
|
3391
|
-
let request = new Request(`http://localhost${reactRouterConfig.basename}
|
|
3332
|
+
let request = new Request(`http://localhost${reactRouterConfig.basename}`, {
|
|
3333
|
+
headers: {
|
|
3334
|
+
// Enable SPA mode in the server runtime and only render down to the root
|
|
3335
|
+
"X-React-Router-SPA-Mode": "yes"
|
|
3336
|
+
}
|
|
3337
|
+
});
|
|
3392
3338
|
let response = await handler(request);
|
|
3393
3339
|
let html = await response.text();
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3340
|
+
let isPrerenderSpaFallback = build.prerender.includes("/");
|
|
3341
|
+
let filename3 = isPrerenderSpaFallback ? "__spa-fallback__.html" : "index.html";
|
|
3342
|
+
if (response.status !== 200) {
|
|
3343
|
+
if (isPrerenderSpaFallback) {
|
|
3344
|
+
throw new Error(
|
|
3345
|
+
`Prerender: Received a ${response.status} status code from \`entry.server.tsx\` while prerendering your \`${filename3}\` file.
|
|
3346
|
+
` + html
|
|
3347
|
+
);
|
|
3348
|
+
} else {
|
|
3349
|
+
throw new Error(
|
|
3350
|
+
`SPA Mode: Received a ${response.status} status code from \`entry.server.tsx\` while prerendering your \`${filename3}\` file.
|
|
3351
|
+
` + html
|
|
3352
|
+
);
|
|
3353
|
+
}
|
|
3354
|
+
}
|
|
3355
|
+
if (!html.includes("window.__reactRouterContext =") || !html.includes("window.__reactRouterRouteModules =")) {
|
|
3356
|
+
throw new Error(
|
|
3357
|
+
"SPA Mode: Did you forget to include `<Scripts/>` in your root route? Your pre-rendered HTML cannot hydrate without `<Scripts />`."
|
|
3358
|
+
);
|
|
3359
|
+
}
|
|
3360
|
+
await fse.writeFile(path6.join(clientBuildDirectory, filename3), html);
|
|
3361
|
+
let prettyDir = path6.relative(process.cwd(), clientBuildDirectory);
|
|
3362
|
+
let prettyPath = path6.join(prettyDir, filename3);
|
|
3363
|
+
let prefix = isPrerenderSpaFallback ? "Prerender" : "SPA Mode";
|
|
3364
|
+
viteConfig.logger.info(`${prefix}: Generated \`${prettyPath}\``);
|
|
3400
3365
|
}
|
|
3401
3366
|
async function handlePrerender(viteConfig, reactRouterConfig, serverBuildDirectory, serverBuildPath, clientBuildDirectory) {
|
|
3402
3367
|
let { build, handler } = await getPrerenderBuildAndHandler(
|
|
@@ -3405,29 +3370,22 @@ async function handlePrerender(viteConfig, reactRouterConfig, serverBuildDirecto
|
|
|
3405
3370
|
serverBuildPath
|
|
3406
3371
|
);
|
|
3407
3372
|
let routes = createPrerenderRoutes(build.routes);
|
|
3408
|
-
let
|
|
3409
|
-
if (typeof reactRouterConfig.prerender === "boolean") {
|
|
3410
|
-
invariant(reactRouterConfig.prerender, "Expected prerender:true");
|
|
3411
|
-
routesToPrerender = determineStaticPrerenderRoutes(
|
|
3412
|
-
routes,
|
|
3413
|
-
viteConfig,
|
|
3414
|
-
true
|
|
3415
|
-
);
|
|
3416
|
-
} else if (typeof reactRouterConfig.prerender === "function") {
|
|
3417
|
-
routesToPrerender = await reactRouterConfig.prerender({
|
|
3418
|
-
getStaticPaths: () => determineStaticPrerenderRoutes(routes, viteConfig, false)
|
|
3419
|
-
});
|
|
3420
|
-
} else {
|
|
3421
|
-
routesToPrerender = reactRouterConfig.prerender || ["/"];
|
|
3422
|
-
}
|
|
3373
|
+
let prerenderedRoutes = /* @__PURE__ */ new Set();
|
|
3423
3374
|
let headers = {
|
|
3424
3375
|
// Header that can be used in the loader to know if you're running at
|
|
3425
3376
|
// build time or runtime
|
|
3426
3377
|
"X-React-Router-Prerender": "yes"
|
|
3427
3378
|
};
|
|
3428
|
-
for (let path7 of
|
|
3379
|
+
for (let path7 of build.prerender) {
|
|
3429
3380
|
let matches = (0, import_react_router2.matchRoutes)(routes, `/${path7}/`.replace(/^\/\/+/, "/"));
|
|
3430
|
-
|
|
3381
|
+
invariant(
|
|
3382
|
+
matches,
|
|
3383
|
+
`Unable to prerender path because it does not match any routes: ${path7}`
|
|
3384
|
+
);
|
|
3385
|
+
matches.forEach((m) => prerenderedRoutes.add(m.route.id));
|
|
3386
|
+
let hasLoaders = matches.some(
|
|
3387
|
+
(m) => build.assets.routes[m.route.id]?.hasLoader
|
|
3388
|
+
);
|
|
3431
3389
|
let data;
|
|
3432
3390
|
if (hasLoaders) {
|
|
3433
3391
|
data = await prerenderData(
|
|
@@ -3467,8 +3425,34 @@ async function handlePrerender(viteConfig, reactRouterConfig, serverBuildDirecto
|
|
|
3467
3425
|
);
|
|
3468
3426
|
}
|
|
3469
3427
|
}
|
|
3428
|
+
if (reactRouterConfig.ssr === false) {
|
|
3429
|
+
let errors = [];
|
|
3430
|
+
for (let [routeId, route] of Object.entries(build.routes)) {
|
|
3431
|
+
let invalidApis = [];
|
|
3432
|
+
if (route) {
|
|
3433
|
+
if (route.module.headers) invalidApis.push("headers");
|
|
3434
|
+
if (route.module.action) invalidApis.push("action");
|
|
3435
|
+
if (invalidApis.length > 0) {
|
|
3436
|
+
errors.push(
|
|
3437
|
+
`Prerender: ${invalidApis.length} invalid route export(s) in \`${route.id}\` when prerendering with \`ssr:false\`: ${invalidApis.join(", ")}. See https://reactrouter.com/how-to/spa for more information.`
|
|
3438
|
+
);
|
|
3439
|
+
}
|
|
3440
|
+
if (route.module.loader && !prerenderedRoutes.has(routeId)) {
|
|
3441
|
+
errors.push(
|
|
3442
|
+
`Prerender: 1 invalid route export in \`${route.id}\` when using \`ssr:false\` with \`prerender\` because the route is never prerendered so the loader will never be called. See https://reactrouter.com/how-to/spa for more information.`
|
|
3443
|
+
);
|
|
3444
|
+
}
|
|
3445
|
+
}
|
|
3446
|
+
}
|
|
3447
|
+
if (errors.length > 0) {
|
|
3448
|
+
viteConfig.logger.error(errors.join("\n"));
|
|
3449
|
+
throw new Error(
|
|
3450
|
+
"Invalid route exports found when prerendering with `ssr:false`"
|
|
3451
|
+
);
|
|
3452
|
+
}
|
|
3453
|
+
}
|
|
3470
3454
|
}
|
|
3471
|
-
function
|
|
3455
|
+
function getStaticPrerenderPaths(routes) {
|
|
3472
3456
|
let paths = ["/"];
|
|
3473
3457
|
let paramRoutes = [];
|
|
3474
3458
|
function recurse(subtree, prefix = "") {
|
|
@@ -3488,28 +3472,29 @@ function determineStaticPrerenderRoutes(routes, viteConfig, isBooleanUsage = fal
|
|
|
3488
3472
|
}
|
|
3489
3473
|
}
|
|
3490
3474
|
recurse(routes);
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
"You may want to use the `prerender()` API to prerender the following paths:",
|
|
3496
|
-
...paramRoutes.map((p) => " - " + p)
|
|
3497
|
-
].join("\n")
|
|
3498
|
-
);
|
|
3499
|
-
}
|
|
3500
|
-
return paths.map((p) => p.replace(/\/\/+/g, "/").replace(/(.+)\/$/, "$1"));
|
|
3475
|
+
return {
|
|
3476
|
+
paths: paths.map((p) => p.replace(/\/\/+/g, "/").replace(/(.+)\/$/, "$1")),
|
|
3477
|
+
paramRoutes
|
|
3478
|
+
};
|
|
3501
3479
|
}
|
|
3502
3480
|
async function prerenderData(handler, prerenderPath, clientBuildDirectory, reactRouterConfig, viteConfig, requestInit) {
|
|
3503
3481
|
let normalizedPath = `${reactRouterConfig.basename}${prerenderPath === "/" ? "/_root.data" : `${prerenderPath.replace(/\/$/, "")}.data`}`.replace(/\/\/+/g, "/");
|
|
3504
3482
|
let request = new Request(`http://localhost${normalizedPath}`, requestInit);
|
|
3505
3483
|
let response = await handler(request);
|
|
3506
3484
|
let data = await response.text();
|
|
3507
|
-
|
|
3485
|
+
if (response.status !== 200) {
|
|
3486
|
+
throw new Error(
|
|
3487
|
+
`Prerender: Received a ${response.status} status code from \`entry.server.tsx\` while prerendering the \`${path6}\` path.
|
|
3488
|
+
${normalizedPath}`
|
|
3489
|
+
);
|
|
3490
|
+
}
|
|
3508
3491
|
let outdir = path6.relative(process.cwd(), clientBuildDirectory);
|
|
3509
3492
|
let outfile = path6.join(outdir, ...normalizedPath.split("/"));
|
|
3510
3493
|
await fse.ensureDir(path6.dirname(outfile));
|
|
3511
3494
|
await fse.outputFile(outfile, data);
|
|
3512
|
-
viteConfig.logger.info(
|
|
3495
|
+
viteConfig.logger.info(
|
|
3496
|
+
`Prerender Data: ${prerenderPath} -> ${import_picocolors3.default.bold(outfile)}`
|
|
3497
|
+
);
|
|
3513
3498
|
return data;
|
|
3514
3499
|
}
|
|
3515
3500
|
async function prerenderRoute(handler, prerenderPath, clientBuildDirectory, reactRouterConfig, viteConfig, requestInit) {
|
|
@@ -3520,42 +3505,83 @@ async function prerenderRoute(handler, prerenderPath, clientBuildDirectory, reac
|
|
|
3520
3505
|
let request = new Request(`http://localhost${normalizedPath}`, requestInit);
|
|
3521
3506
|
let response = await handler(request);
|
|
3522
3507
|
let html = await response.text();
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3508
|
+
if (response.status !== 200) {
|
|
3509
|
+
throw new Error(
|
|
3510
|
+
`Prerender: Received a ${response.status} status code from \`entry.server.tsx\` while prerendering the \`${normalizedPath}\` path.
|
|
3511
|
+
${html}`
|
|
3512
|
+
);
|
|
3526
3513
|
}
|
|
3527
3514
|
let outdir = path6.relative(process.cwd(), clientBuildDirectory);
|
|
3528
3515
|
let outfile = path6.join(outdir, ...normalizedPath.split("/"), "index.html");
|
|
3529
3516
|
await fse.ensureDir(path6.dirname(outfile));
|
|
3530
3517
|
await fse.outputFile(outfile, html);
|
|
3531
|
-
viteConfig.logger.info(
|
|
3518
|
+
viteConfig.logger.info(
|
|
3519
|
+
`Prerender: ${prerenderPath} -> ${import_picocolors3.default.bold(outfile)}`
|
|
3520
|
+
);
|
|
3532
3521
|
}
|
|
3533
3522
|
async function prerenderResourceRoute(handler, prerenderPath, clientBuildDirectory, reactRouterConfig, viteConfig, requestInit) {
|
|
3534
3523
|
let normalizedPath = `${reactRouterConfig.basename}${prerenderPath}/`.replace(/\/\/+/g, "/").replace(/\/$/g, "");
|
|
3535
3524
|
let request = new Request(`http://localhost${normalizedPath}`, requestInit);
|
|
3536
3525
|
let response = await handler(request);
|
|
3537
3526
|
let text = await response.text();
|
|
3538
|
-
|
|
3527
|
+
if (response.status !== 200) {
|
|
3528
|
+
throw new Error(
|
|
3529
|
+
`Prerender: Received a ${response.status} status code from \`entry.server.tsx\` while prerendering the \`${normalizedPath}\` path.
|
|
3530
|
+
${text}`
|
|
3531
|
+
);
|
|
3532
|
+
}
|
|
3539
3533
|
let outdir = path6.relative(process.cwd(), clientBuildDirectory);
|
|
3540
3534
|
let outfile = path6.join(outdir, ...normalizedPath.split("/"));
|
|
3541
3535
|
await fse.ensureDir(path6.dirname(outfile));
|
|
3542
3536
|
await fse.outputFile(outfile, text);
|
|
3543
|
-
viteConfig.logger.info(
|
|
3537
|
+
viteConfig.logger.info(
|
|
3538
|
+
`Prerender: ${prerenderPath} -> ${import_picocolors3.default.bold(outfile)}`
|
|
3539
|
+
);
|
|
3544
3540
|
}
|
|
3545
|
-
function
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3541
|
+
async function getPrerenderPaths(prerender, routes) {
|
|
3542
|
+
let prerenderPaths = [];
|
|
3543
|
+
if (prerender != null && prerender !== false) {
|
|
3544
|
+
let prerenderRoutes = createPrerenderRoutes(routes);
|
|
3545
|
+
if (prerender === true) {
|
|
3546
|
+
let { paths, paramRoutes } = getStaticPrerenderPaths(prerenderRoutes);
|
|
3547
|
+
if (paramRoutes.length > 0) {
|
|
3548
|
+
console.warn(
|
|
3549
|
+
import_picocolors3.default.yellow(
|
|
3550
|
+
[
|
|
3551
|
+
"\u26A0\uFE0F Paths with dynamic/splat params cannot be prerendered when using `prerender: true`. You may want to use the `prerender()` API to prerender the following paths:",
|
|
3552
|
+
...paramRoutes.map((p) => " - " + p)
|
|
3553
|
+
].join("\n")
|
|
3554
|
+
)
|
|
3555
|
+
);
|
|
3556
|
+
}
|
|
3557
|
+
prerenderPaths = paths;
|
|
3558
|
+
} else if (typeof prerender === "function") {
|
|
3559
|
+
prerenderPaths = await prerender({
|
|
3560
|
+
getStaticPaths: () => getStaticPrerenderPaths(prerenderRoutes).paths
|
|
3561
|
+
});
|
|
3562
|
+
} else {
|
|
3563
|
+
prerenderPaths = prerender || ["/"];
|
|
3564
|
+
}
|
|
3551
3565
|
}
|
|
3566
|
+
return prerenderPaths;
|
|
3552
3567
|
}
|
|
3553
|
-
function
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3568
|
+
function createPrerenderRoutes(manifest, parentId = "", routesByParentId = groupRoutesByParentId2(manifest)) {
|
|
3569
|
+
return (routesByParentId[parentId] || []).map((route) => {
|
|
3570
|
+
let commonRoute = {
|
|
3571
|
+
id: route.id,
|
|
3572
|
+
path: route.path
|
|
3573
|
+
};
|
|
3574
|
+
if (route.index) {
|
|
3575
|
+
return {
|
|
3576
|
+
index: true,
|
|
3577
|
+
...commonRoute
|
|
3578
|
+
};
|
|
3579
|
+
}
|
|
3580
|
+
return {
|
|
3581
|
+
children: createPrerenderRoutes(manifest, route.id, routesByParentId),
|
|
3582
|
+
...commonRoute
|
|
3583
|
+
};
|
|
3584
|
+
});
|
|
3559
3585
|
}
|
|
3560
3586
|
function groupRoutesByParentId2(manifest) {
|
|
3561
3587
|
let routes = {};
|
|
@@ -3570,28 +3596,54 @@ function groupRoutesByParentId2(manifest) {
|
|
|
3570
3596
|
});
|
|
3571
3597
|
return routes;
|
|
3572
3598
|
}
|
|
3573
|
-
function
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3599
|
+
function getAddressableRoutes(routes) {
|
|
3600
|
+
let nonAddressableIds = /* @__PURE__ */ new Set();
|
|
3601
|
+
for (let id in routes) {
|
|
3602
|
+
let route = routes[id];
|
|
3603
|
+
if (route.index) {
|
|
3604
|
+
invariant(
|
|
3605
|
+
route.parentId,
|
|
3606
|
+
`Expected index route "${route.id}" to have "parentId" set`
|
|
3607
|
+
);
|
|
3608
|
+
nonAddressableIds.add(route.parentId);
|
|
3609
|
+
}
|
|
3610
|
+
if (typeof route.path !== "string" && !route.index) {
|
|
3611
|
+
nonAddressableIds.add(id);
|
|
3612
|
+
}
|
|
3613
|
+
}
|
|
3614
|
+
return Object.values(routes).filter(
|
|
3615
|
+
(route) => !nonAddressableIds.has(route.id)
|
|
3616
|
+
);
|
|
3617
|
+
}
|
|
3618
|
+
function getRouteBranch(routes, routeId) {
|
|
3619
|
+
let branch = [];
|
|
3620
|
+
let currentRouteId = routeId;
|
|
3621
|
+
while (currentRouteId) {
|
|
3622
|
+
let route = routes[currentRouteId];
|
|
3623
|
+
invariant(route, `Missing route for ${currentRouteId}`);
|
|
3624
|
+
branch.push(route);
|
|
3625
|
+
currentRouteId = route.parentId;
|
|
3626
|
+
}
|
|
3627
|
+
return branch.reverse();
|
|
3628
|
+
}
|
|
3629
|
+
function hasServerBundles(buildManifest) {
|
|
3630
|
+
return Object.keys(buildManifest.serverBundles ?? {}).length > 0;
|
|
3631
|
+
}
|
|
3632
|
+
function getRoutesByServerBundleId(buildManifest) {
|
|
3633
|
+
if (!buildManifest.routeIdToServerBundleId) {
|
|
3634
|
+
return {};
|
|
3635
|
+
}
|
|
3636
|
+
let routesByServerBundleId = {};
|
|
3637
|
+
for (let [routeId, serverBundleId] of Object.entries(
|
|
3638
|
+
buildManifest.routeIdToServerBundleId
|
|
3639
|
+
)) {
|
|
3640
|
+
routesByServerBundleId[serverBundleId] ??= {};
|
|
3641
|
+
let branch = getRouteBranch(buildManifest.routes, routeId);
|
|
3642
|
+
for (let route of branch) {
|
|
3643
|
+
routesByServerBundleId[serverBundleId][route.id] = route;
|
|
3644
|
+
}
|
|
3645
|
+
}
|
|
3646
|
+
return routesByServerBundleId;
|
|
3595
3647
|
}
|
|
3596
3648
|
var resolveRouteFileCode = async (ctx, input) => {
|
|
3597
3649
|
if (typeof input === "string") return input;
|
|
@@ -3657,6 +3709,192 @@ function validateRouteChunks({
|
|
|
3657
3709
|
].join("\n\n")
|
|
3658
3710
|
);
|
|
3659
3711
|
}
|
|
3712
|
+
async function getBuildManifest(ctx) {
|
|
3713
|
+
let { routes, serverBundles, appDirectory } = ctx.reactRouterConfig;
|
|
3714
|
+
if (!serverBundles) {
|
|
3715
|
+
return { routes };
|
|
3716
|
+
}
|
|
3717
|
+
let { normalizePath } = await import("vite");
|
|
3718
|
+
let serverBuildDirectory = getServerBuildDirectory(ctx);
|
|
3719
|
+
let resolvedAppDirectory = path6.resolve(ctx.rootDirectory, appDirectory);
|
|
3720
|
+
let rootRelativeRoutes = Object.fromEntries(
|
|
3721
|
+
Object.entries(routes).map(([id, route]) => {
|
|
3722
|
+
let filePath = path6.join(resolvedAppDirectory, route.file);
|
|
3723
|
+
let rootRelativeFilePath = normalizePath(
|
|
3724
|
+
path6.relative(ctx.rootDirectory, filePath)
|
|
3725
|
+
);
|
|
3726
|
+
return [id, { ...route, file: rootRelativeFilePath }];
|
|
3727
|
+
})
|
|
3728
|
+
);
|
|
3729
|
+
let buildManifest = {
|
|
3730
|
+
serverBundles: {},
|
|
3731
|
+
routeIdToServerBundleId: {},
|
|
3732
|
+
routes: rootRelativeRoutes
|
|
3733
|
+
};
|
|
3734
|
+
await Promise.all(
|
|
3735
|
+
getAddressableRoutes(routes).map(async (route) => {
|
|
3736
|
+
let branch = getRouteBranch(routes, route.id);
|
|
3737
|
+
let serverBundleId = await serverBundles({
|
|
3738
|
+
branch: branch.map(
|
|
3739
|
+
(route2) => configRouteToBranchRoute({
|
|
3740
|
+
...route2,
|
|
3741
|
+
// Ensure absolute paths are passed to the serverBundles function
|
|
3742
|
+
file: path6.join(resolvedAppDirectory, route2.file)
|
|
3743
|
+
})
|
|
3744
|
+
)
|
|
3745
|
+
});
|
|
3746
|
+
if (typeof serverBundleId !== "string") {
|
|
3747
|
+
throw new Error(`The "serverBundles" function must return a string`);
|
|
3748
|
+
}
|
|
3749
|
+
if (!/^[a-zA-Z0-9-_]+$/.test(serverBundleId)) {
|
|
3750
|
+
throw new Error(
|
|
3751
|
+
`The "serverBundles" function must only return strings containing alphanumeric characters, hyphens and underscores.`
|
|
3752
|
+
);
|
|
3753
|
+
}
|
|
3754
|
+
buildManifest.routeIdToServerBundleId[route.id] = serverBundleId;
|
|
3755
|
+
buildManifest.serverBundles[serverBundleId] ??= {
|
|
3756
|
+
id: serverBundleId,
|
|
3757
|
+
file: normalizePath(
|
|
3758
|
+
path6.join(
|
|
3759
|
+
path6.relative(
|
|
3760
|
+
ctx.rootDirectory,
|
|
3761
|
+
path6.join(serverBuildDirectory, serverBundleId)
|
|
3762
|
+
),
|
|
3763
|
+
ctx.reactRouterConfig.serverBuildFile
|
|
3764
|
+
)
|
|
3765
|
+
)
|
|
3766
|
+
};
|
|
3767
|
+
})
|
|
3768
|
+
);
|
|
3769
|
+
return buildManifest;
|
|
3770
|
+
}
|
|
3771
|
+
function mergeBuildOptions(base, overrides) {
|
|
3772
|
+
let vite2 = getVite();
|
|
3773
|
+
return vite2.mergeConfig({ build: base }, { build: overrides }).build;
|
|
3774
|
+
}
|
|
3775
|
+
async function getEnvironmentOptionsResolvers(ctx, buildManifest) {
|
|
3776
|
+
let { serverBuildFile, serverModuleFormat } = ctx.reactRouterConfig;
|
|
3777
|
+
function getBaseBuildOptions({
|
|
3778
|
+
viteUserConfig
|
|
3779
|
+
}) {
|
|
3780
|
+
return {
|
|
3781
|
+
cssMinify: viteUserConfig.build?.cssMinify ?? true,
|
|
3782
|
+
manifest: true,
|
|
3783
|
+
// The manifest is enabled for all builds to detect SSR-only assets
|
|
3784
|
+
rollupOptions: {
|
|
3785
|
+
preserveEntrySignatures: "exports-only",
|
|
3786
|
+
// Silence Rollup "use client" warnings
|
|
3787
|
+
// Adapted from https://github.com/vitejs/vite-plugin-react/pull/144
|
|
3788
|
+
onwarn(warning, defaultHandler) {
|
|
3789
|
+
if (warning.code === "MODULE_LEVEL_DIRECTIVE" && warning.message.includes("use client")) {
|
|
3790
|
+
return;
|
|
3791
|
+
}
|
|
3792
|
+
let userHandler = viteUserConfig.build?.rollupOptions?.onwarn;
|
|
3793
|
+
if (userHandler) {
|
|
3794
|
+
userHandler(warning, defaultHandler);
|
|
3795
|
+
} else {
|
|
3796
|
+
defaultHandler(warning);
|
|
3797
|
+
}
|
|
3798
|
+
}
|
|
3799
|
+
}
|
|
3800
|
+
};
|
|
3801
|
+
}
|
|
3802
|
+
function getBaseServerBuildOptions({
|
|
3803
|
+
viteUserConfig
|
|
3804
|
+
}) {
|
|
3805
|
+
return mergeBuildOptions(getBaseBuildOptions({ viteUserConfig }), {
|
|
3806
|
+
// We move SSR-only assets to client assets. Note that the
|
|
3807
|
+
// SSR build can also emit code-split JS files (e.g. by
|
|
3808
|
+
// dynamic import) under the same assets directory
|
|
3809
|
+
// regardless of "ssrEmitAssets" option, so we also need to
|
|
3810
|
+
// keep these JS files have to be kept as-is.
|
|
3811
|
+
ssrEmitAssets: true,
|
|
3812
|
+
copyPublicDir: false,
|
|
3813
|
+
// Assets in the public directory are only used by the client
|
|
3814
|
+
rollupOptions: {
|
|
3815
|
+
output: {
|
|
3816
|
+
entryFileNames: serverBuildFile,
|
|
3817
|
+
format: serverModuleFormat
|
|
3818
|
+
}
|
|
3819
|
+
}
|
|
3820
|
+
});
|
|
3821
|
+
}
|
|
3822
|
+
let environmentOptionsResolvers = {
|
|
3823
|
+
client: ({ viteUserConfig }) => ({
|
|
3824
|
+
build: mergeBuildOptions(getBaseBuildOptions({ viteUserConfig }), {
|
|
3825
|
+
rollupOptions: {
|
|
3826
|
+
input: [
|
|
3827
|
+
ctx.entryClientFilePath,
|
|
3828
|
+
...Object.values(ctx.reactRouterConfig.routes).flatMap((route) => {
|
|
3829
|
+
let routeFilePath = path6.resolve(
|
|
3830
|
+
ctx.reactRouterConfig.appDirectory,
|
|
3831
|
+
route.file
|
|
3832
|
+
);
|
|
3833
|
+
let isRootRoute = route.file === ctx.reactRouterConfig.routes.root.file;
|
|
3834
|
+
let code = fse.readFileSync(routeFilePath, "utf-8");
|
|
3835
|
+
return [
|
|
3836
|
+
`${routeFilePath}${BUILD_CLIENT_ROUTE_QUERY_STRING}`,
|
|
3837
|
+
...ctx.reactRouterConfig.future.unstable_splitRouteModules && !isRootRoute ? routeChunkExportNames.map(
|
|
3838
|
+
(exportName) => code.includes(exportName) ? getRouteChunkModuleId(routeFilePath, exportName) : null
|
|
3839
|
+
) : []
|
|
3840
|
+
].filter(isNonNullable);
|
|
3841
|
+
})
|
|
3842
|
+
],
|
|
3843
|
+
output: {
|
|
3844
|
+
entryFileNames({ moduleIds }) {
|
|
3845
|
+
let routeChunkModuleId = moduleIds.find(isRouteChunkModuleId);
|
|
3846
|
+
let routeChunkName = routeChunkModuleId ? getRouteChunkNameFromModuleId(routeChunkModuleId) : null;
|
|
3847
|
+
let routeChunkSuffix = routeChunkName ? `-${(0, import_kebabCase.default)(routeChunkName)}` : "";
|
|
3848
|
+
return `assets/[name]${routeChunkSuffix}-[hash].js`;
|
|
3849
|
+
}
|
|
3850
|
+
}
|
|
3851
|
+
},
|
|
3852
|
+
outDir: getClientBuildDirectory(ctx.reactRouterConfig)
|
|
3853
|
+
})
|
|
3854
|
+
})
|
|
3855
|
+
};
|
|
3856
|
+
if (hasServerBundles(buildManifest)) {
|
|
3857
|
+
for (let [serverBundleId, routes] of Object.entries(
|
|
3858
|
+
getRoutesByServerBundleId(buildManifest)
|
|
3859
|
+
)) {
|
|
3860
|
+
environmentOptionsResolvers[`ssr-bundle-${serverBundleId}`] = ({
|
|
3861
|
+
viteUserConfig
|
|
3862
|
+
}) => ({
|
|
3863
|
+
build: mergeBuildOptions(
|
|
3864
|
+
getBaseServerBuildOptions({ viteUserConfig }),
|
|
3865
|
+
{
|
|
3866
|
+
outDir: getServerBuildDirectory(ctx, { serverBundleId }),
|
|
3867
|
+
rollupOptions: {
|
|
3868
|
+
input: `${virtual.serverBuild.id}?route-ids=${Object.keys(
|
|
3869
|
+
routes
|
|
3870
|
+
).join(",")}`
|
|
3871
|
+
}
|
|
3872
|
+
}
|
|
3873
|
+
)
|
|
3874
|
+
});
|
|
3875
|
+
}
|
|
3876
|
+
} else {
|
|
3877
|
+
environmentOptionsResolvers.ssr = ({ viteUserConfig }) => ({
|
|
3878
|
+
build: mergeBuildOptions(getBaseServerBuildOptions({ viteUserConfig }), {
|
|
3879
|
+
outDir: getServerBuildDirectory(ctx),
|
|
3880
|
+
rollupOptions: {
|
|
3881
|
+
input: viteUserConfig.build?.rollupOptions?.input ?? virtual.serverBuild.id
|
|
3882
|
+
}
|
|
3883
|
+
})
|
|
3884
|
+
});
|
|
3885
|
+
}
|
|
3886
|
+
return environmentOptionsResolvers;
|
|
3887
|
+
}
|
|
3888
|
+
async function getEnvironmentOptions(ctx, environmentName, resolverOptions) {
|
|
3889
|
+
let buildManifest = await getBuildManifest(ctx);
|
|
3890
|
+
let environmentResolvers = await getEnvironmentOptionsResolvers(
|
|
3891
|
+
ctx,
|
|
3892
|
+
buildManifest
|
|
3893
|
+
);
|
|
3894
|
+
let resolver = environmentResolvers[environmentName];
|
|
3895
|
+
invariant(resolver, `Missing environment resolver for ${environmentName}`);
|
|
3896
|
+
return resolver(resolverOptions);
|
|
3897
|
+
}
|
|
3660
3898
|
function isNonNullable(x) {
|
|
3661
3899
|
return x != null;
|
|
3662
3900
|
}
|