rsbuild-plugin-react-router 0.4.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +72 -240
- package/dist/{451.js → 511.js} +461 -331
- package/dist/build-output-transforms.d.ts +32 -7
- package/dist/classic-mode.d.ts +56 -0
- package/dist/config-imports.d.ts +8 -2
- package/dist/constants.d.ts +3 -0
- package/dist/dev-background-resources.d.ts +3 -3
- package/dist/dev-generation.d.ts +2 -3
- package/dist/dev-hmr.d.ts +8 -2
- package/dist/dev-runtime-controller.d.ts +6 -1
- package/dist/dev-source-maps.d.ts +4 -0
- package/dist/effect-runtime.d.ts +17 -5
- package/dist/entry-paths.d.ts +16 -0
- package/dist/environment-output.d.ts +6 -0
- package/dist/export-utils.d.ts +2 -1
- package/dist/federation.d.ts +2 -0
- package/dist/index.cjs +3675 -2107
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3614 -2214
- package/dist/lazy-compilation-prewarm.d.ts +8 -5
- package/dist/manifest.d.ts +16 -4
- package/dist/mode-plan.d.ts +82 -0
- package/dist/modify-browser-manifest.d.ts +8 -4
- package/dist/performance.d.ts +4 -1
- package/dist/plugin-utils.d.ts +27 -1
- package/dist/prerender-build.d.ts +5 -5
- package/dist/prerender.d.ts +1 -5
- package/dist/react-router-config.d.ts +11 -3
- package/dist/route-artifacts.d.ts +4 -2
- package/dist/route-chunks.d.ts +2 -1
- package/dist/route-component-transform.d.ts +0 -2
- package/dist/route-export-pruning.d.ts +4 -1
- package/dist/route-imports.d.ts +18 -0
- package/dist/route-module-transform-loader.d.ts +14 -0
- package/dist/route-module-transform-loader.js +44 -0
- package/dist/route-module-transform-rules.d.ts +14 -0
- package/dist/route-transform-tasks.d.ts +6 -0
- package/dist/route-watch.d.ts +11 -6
- package/dist/rsc-dev-server.d.ts +26 -0
- package/dist/rsc-prerender.d.ts +54 -0
- package/dist/rsc-route-config.d.ts +6 -0
- package/dist/rsc-route-exports.d.ts +15 -0
- package/dist/rsc-route-transform-loader.cjs +43 -0
- package/dist/rsc-route-transform-loader.d.ts +30 -0
- package/dist/rsc-route-transform-loader.js +16 -0
- package/dist/rsc-route-transform-registration.d.ts +12 -0
- package/dist/rsc-route-transforms.d.ts +21 -0
- package/dist/rsc-support.d.ts +23 -0
- package/dist/rsc-virtual-modules.d.ts +19 -0
- package/dist/server-build-plan.d.ts +2 -1
- package/dist/server-build-resolution.d.ts +1 -2
- package/dist/server-utils.d.ts +4 -5
- package/dist/ssr-asset-relocation.d.ts +98 -0
- package/dist/templates/entry.rsc.client.d.ts +1 -0
- package/dist/templates/entry.rsc.client.js +61 -0
- package/dist/templates/entry.rsc.d.ts +9 -0
- package/dist/templates/entry.rsc.js +38 -0
- package/dist/templates/entry.rsc.ssr.d.ts +4 -0
- package/dist/templates/entry.rsc.ssr.js +24 -0
- package/dist/typegen.d.ts +4 -2
- package/dist/types.d.ts +34 -6
- package/package.json +76 -22
- package/src/build-output-transforms.ts +181 -43
- package/src/classic-mode.ts +253 -0
- package/src/config-imports.ts +153 -6
- package/src/constants.ts +6 -2
- package/src/dev-background-resources.ts +46 -100
- package/src/dev-generation.ts +52 -33
- package/src/dev-hmr.ts +112 -80
- package/src/dev-runtime-artifacts.ts +11 -12
- package/src/dev-runtime-controller.ts +75 -85
- package/src/dev-runtime-session.ts +14 -18
- package/src/dev-server.ts +2 -0
- package/src/dev-source-maps.ts +257 -0
- package/src/effect-runtime.ts +105 -57
- package/src/entry-paths.ts +80 -0
- package/src/environment-output.ts +55 -0
- package/src/export-utils.ts +15 -11
- package/src/federation.ts +38 -0
- package/src/index.ts +666 -519
- package/src/lazy-compilation-prewarm.ts +20 -4
- package/src/manifest.ts +157 -82
- package/src/mode-plan.ts +367 -0
- package/src/modify-browser-manifest.ts +130 -124
- package/src/performance.ts +11 -2
- package/src/plugin-utils.ts +103 -39
- package/src/prerender-build.ts +82 -104
- package/src/prerender.ts +23 -24
- package/src/react-router-config.ts +72 -26
- package/src/route-artifacts.ts +96 -66
- package/src/route-chunks.ts +167 -51
- package/src/route-component-transform.ts +14 -21
- package/src/route-export-pruning.ts +4 -3
- package/src/route-imports.ts +100 -0
- package/src/route-module-transform-loader.ts +149 -0
- package/src/route-module-transform-rules.ts +115 -0
- package/src/route-transform-tasks.ts +44 -29
- package/src/route-watch.ts +166 -188
- package/src/rsc-dev-server.ts +112 -0
- package/src/rsc-prerender.ts +362 -0
- package/src/rsc-route-config.ts +175 -0
- package/src/rsc-route-exports.ts +67 -0
- package/src/rsc-route-transform-loader.ts +65 -0
- package/src/rsc-route-transform-registration.ts +145 -0
- package/src/rsc-route-transforms.ts +995 -0
- package/src/rsc-runtime.d.ts +143 -0
- package/src/rsc-support.ts +116 -0
- package/src/rsc-virtual-modules.ts +113 -0
- package/src/server-build-plan.ts +14 -3
- package/src/server-build-resolution.ts +37 -47
- package/src/server-utils.ts +21 -35
- package/src/ssr-asset-relocation.ts +183 -0
- package/src/ssr-externals.ts +8 -26
- package/src/templates/entry.rsc.client.tsx +168 -0
- package/src/templates/entry.rsc.ssr.tsx +45 -0
- package/src/templates/entry.rsc.tsx +80 -0
- package/src/typegen.ts +40 -23
- package/src/types.ts +43 -6
- package/src/warnings/warn-on-client-source-maps.ts +6 -10
- package/dist/parallel-route-transform-protocol.d.ts +0 -25
- package/dist/parallel-route-transform-worker.d.ts +0 -1
- package/dist/parallel-route-transform-worker.js +0 -38
- package/dist/parallel-route-transforms.d.ts +0 -29
- package/src/parallel-route-transform-protocol.ts +0 -35
- package/src/parallel-route-transform-worker.ts +0 -82
- package/src/parallel-route-transforms.ts +0 -458
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { threadId } from 'node:worker_threads';
|
|
2
|
+
import remapping, { type SourceMapInput } from '@jridgewell/remapping';
|
|
3
|
+
import type { LoaderDefinition } from '@rspack/core';
|
|
4
|
+
import { createReactRouterPerformanceProfiler } from './performance.js';
|
|
5
|
+
import { executeRouteTransformTask } from './route-transform-tasks.js';
|
|
6
|
+
|
|
7
|
+
export type RouteModuleTransformLoaderOptions = {
|
|
8
|
+
environmentName: string;
|
|
9
|
+
performanceScopeId: string;
|
|
10
|
+
logPerformance: boolean;
|
|
11
|
+
ssr: boolean;
|
|
12
|
+
isBuild: boolean;
|
|
13
|
+
isSpaMode: boolean;
|
|
14
|
+
rootRoutePath: string | null;
|
|
15
|
+
devHmr: boolean;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
type LoaderContextWithSourceMap = ThisParameterType<
|
|
19
|
+
LoaderDefinition<RouteModuleTransformLoaderOptions>
|
|
20
|
+
> & {
|
|
21
|
+
sourceMap?: boolean;
|
|
22
|
+
};
|
|
23
|
+
type LoaderInputSourceMap = Parameters<
|
|
24
|
+
LoaderDefinition<RouteModuleTransformLoaderOptions>
|
|
25
|
+
>[1];
|
|
26
|
+
type RawLoaderSourceMap = Exclude<LoaderInputSourceMap, string | undefined>;
|
|
27
|
+
|
|
28
|
+
const LOADER_PERFORMANCE_FLUSH_DELAY_MS = 50;
|
|
29
|
+
const performanceWorkerId = `process-${process.pid}:thread-${threadId}`;
|
|
30
|
+
|
|
31
|
+
const composeSourceMaps = (
|
|
32
|
+
generatedMap: SourceMapInput,
|
|
33
|
+
inputSourceMap: SourceMapInput
|
|
34
|
+
): RawLoaderSourceMap =>
|
|
35
|
+
JSON.parse(
|
|
36
|
+
remapping([generatedMap, inputSourceMap], () => null).toString()
|
|
37
|
+
) as RawLoaderSourceMap;
|
|
38
|
+
|
|
39
|
+
const performanceProfilersByScope = new Map<
|
|
40
|
+
string,
|
|
41
|
+
Map<string, ReturnType<typeof createReactRouterPerformanceProfiler>>
|
|
42
|
+
>();
|
|
43
|
+
let performanceFlushTimer: ReturnType<typeof setTimeout> | undefined;
|
|
44
|
+
|
|
45
|
+
const getPerformanceProfiler = (
|
|
46
|
+
scopeId: string,
|
|
47
|
+
environment: string | undefined
|
|
48
|
+
): ReturnType<typeof createReactRouterPerformanceProfiler> => {
|
|
49
|
+
let profilers = performanceProfilersByScope.get(scopeId);
|
|
50
|
+
if (!profilers) {
|
|
51
|
+
profilers = new Map();
|
|
52
|
+
performanceProfilersByScope.set(scopeId, profilers);
|
|
53
|
+
}
|
|
54
|
+
const environmentKey = environment ?? 'unknown';
|
|
55
|
+
let profiler = profilers.get(environmentKey);
|
|
56
|
+
if (!profiler) {
|
|
57
|
+
profiler = createReactRouterPerformanceProfiler({
|
|
58
|
+
enabled: true,
|
|
59
|
+
log: message => console.info(message),
|
|
60
|
+
});
|
|
61
|
+
profilers.set(environmentKey, profiler);
|
|
62
|
+
}
|
|
63
|
+
return profiler;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export const flushRouteModuleTransformLoaderPerformance = (): void => {
|
|
67
|
+
if (performanceFlushTimer) {
|
|
68
|
+
clearTimeout(performanceFlushTimer);
|
|
69
|
+
performanceFlushTimer = undefined;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
for (const profilers of performanceProfilersByScope.values()) {
|
|
73
|
+
for (const [environment, profiler] of profilers) {
|
|
74
|
+
profiler.flush(environment === 'unknown' ? undefined : environment, {
|
|
75
|
+
partial: true,
|
|
76
|
+
workerId: performanceWorkerId,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
performanceProfilersByScope.clear();
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const schedulePerformanceFlush = (): void => {
|
|
84
|
+
if (performanceFlushTimer) {
|
|
85
|
+
clearTimeout(performanceFlushTimer);
|
|
86
|
+
}
|
|
87
|
+
performanceFlushTimer = setTimeout(
|
|
88
|
+
flushRouteModuleTransformLoaderPerformance,
|
|
89
|
+
LOADER_PERFORMANCE_FLUSH_DELAY_MS
|
|
90
|
+
);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
process.once('beforeExit', flushRouteModuleTransformLoaderPerformance);
|
|
94
|
+
|
|
95
|
+
const routeModuleTransformLoader: LoaderDefinition<RouteModuleTransformLoaderOptions> =
|
|
96
|
+
async function routeModuleTransformLoader(
|
|
97
|
+
this: LoaderContextWithSourceMap,
|
|
98
|
+
source,
|
|
99
|
+
inputSourceMap
|
|
100
|
+
) {
|
|
101
|
+
const callback = this.async();
|
|
102
|
+
const options = this.getOptions();
|
|
103
|
+
|
|
104
|
+
const transform = () =>
|
|
105
|
+
executeRouteTransformTask({
|
|
106
|
+
kind: 'routeModule',
|
|
107
|
+
code: String(source),
|
|
108
|
+
resource: this.resource,
|
|
109
|
+
resourcePath: this.resourcePath,
|
|
110
|
+
environmentName: options.environmentName,
|
|
111
|
+
sourceMaps: Boolean(this.sourceMap),
|
|
112
|
+
ssr: options.ssr,
|
|
113
|
+
isBuild: options.isBuild,
|
|
114
|
+
isSpaMode: options.isSpaMode,
|
|
115
|
+
rootRoutePath: options.rootRoutePath,
|
|
116
|
+
devHmr: options.devHmr,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
const result = options.logPerformance
|
|
121
|
+
? await getPerformanceProfiler(
|
|
122
|
+
options.performanceScopeId,
|
|
123
|
+
options.environmentName
|
|
124
|
+
).record(
|
|
125
|
+
options.environmentName,
|
|
126
|
+
'route:module',
|
|
127
|
+
this.resource,
|
|
128
|
+
transform
|
|
129
|
+
)
|
|
130
|
+
: await transform();
|
|
131
|
+
|
|
132
|
+
const outputSourceMap =
|
|
133
|
+
result.map && inputSourceMap
|
|
134
|
+
? composeSourceMaps(
|
|
135
|
+
result.map as SourceMapInput,
|
|
136
|
+
inputSourceMap as SourceMapInput
|
|
137
|
+
)
|
|
138
|
+
: result.map;
|
|
139
|
+
callback(null, result.code, outputSourceMap ?? undefined);
|
|
140
|
+
} catch (error) {
|
|
141
|
+
callback(error instanceof Error ? error : new Error(String(error)));
|
|
142
|
+
} finally {
|
|
143
|
+
if (options.logPerformance) {
|
|
144
|
+
schedulePerformanceFlush();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
export default routeModuleTransformLoader;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { fileURLToPath } from 'node:url';
|
|
2
|
+
import type { Rspack } from '@rsbuild/core';
|
|
3
|
+
import type { RouteModuleTransformLoaderOptions } from './route-module-transform-loader.js';
|
|
4
|
+
import type { PluginOptions, Route } from './types.js';
|
|
5
|
+
|
|
6
|
+
const routeModuleTransformLoaderPath = fileURLToPath(
|
|
7
|
+
new URL('./route-module-transform-loader.js', import.meta.url)
|
|
8
|
+
);
|
|
9
|
+
|
|
10
|
+
const getRouteModuleTransformParallel = (
|
|
11
|
+
parallelRouteTransform: PluginOptions['parallelRouteTransform']
|
|
12
|
+
): Rspack.RuleSetLoaderWithOptions['parallel'] => {
|
|
13
|
+
if (
|
|
14
|
+
parallelRouteTransform === undefined ||
|
|
15
|
+
parallelRouteTransform === false
|
|
16
|
+
) {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
if (parallelRouteTransform === true) {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
if (typeof parallelRouteTransform === 'number') {
|
|
23
|
+
if (
|
|
24
|
+
!Number.isInteger(parallelRouteTransform) ||
|
|
25
|
+
parallelRouteTransform < 1
|
|
26
|
+
) {
|
|
27
|
+
throw new Error(
|
|
28
|
+
'[react-router] parallelRouteTransform must be true, false, or a positive integer.'
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
return { maxWorkers: parallelRouteTransform };
|
|
32
|
+
}
|
|
33
|
+
throw new Error(
|
|
34
|
+
'[react-router] parallelRouteTransform must be true, false, or a positive integer.'
|
|
35
|
+
);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const shouldUseRouteModuleTransformLoader = (
|
|
39
|
+
parallelRouteTransform: PluginOptions['parallelRouteTransform']
|
|
40
|
+
): boolean =>
|
|
41
|
+
getRouteModuleTransformParallel(parallelRouteTransform) !== undefined;
|
|
42
|
+
|
|
43
|
+
const createRouteModuleTransformUse = (
|
|
44
|
+
options: RouteModuleTransformLoaderOptions,
|
|
45
|
+
parallelRouteTransform: PluginOptions['parallelRouteTransform']
|
|
46
|
+
): Rspack.RuleSetLoaderWithOptions => {
|
|
47
|
+
const parallel = getRouteModuleTransformParallel(parallelRouteTransform);
|
|
48
|
+
return {
|
|
49
|
+
loader: routeModuleTransformLoaderPath,
|
|
50
|
+
options,
|
|
51
|
+
...(parallel ? { parallel } : {}),
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const registerRouteModuleTransformRules = (
|
|
56
|
+
rspackConfig: Rspack.Configuration,
|
|
57
|
+
{
|
|
58
|
+
environmentName,
|
|
59
|
+
ssr,
|
|
60
|
+
isBuild,
|
|
61
|
+
isSpaMode,
|
|
62
|
+
rootRoutePath,
|
|
63
|
+
devHmr,
|
|
64
|
+
logPerformance,
|
|
65
|
+
routeByFilePath,
|
|
66
|
+
parallelRouteTransform,
|
|
67
|
+
}: {
|
|
68
|
+
environmentName: string;
|
|
69
|
+
ssr: boolean;
|
|
70
|
+
isBuild: boolean;
|
|
71
|
+
isSpaMode: boolean;
|
|
72
|
+
rootRoutePath: string | null;
|
|
73
|
+
devHmr: boolean;
|
|
74
|
+
logPerformance: boolean;
|
|
75
|
+
routeByFilePath: Map<string, Route>;
|
|
76
|
+
parallelRouteTransform: PluginOptions['parallelRouteTransform'];
|
|
77
|
+
}
|
|
78
|
+
): void => {
|
|
79
|
+
const routeModuleTransformUse = createRouteModuleTransformUse(
|
|
80
|
+
{
|
|
81
|
+
environmentName,
|
|
82
|
+
performanceScopeId: [
|
|
83
|
+
environmentName,
|
|
84
|
+
isBuild ? 'build' : 'dev',
|
|
85
|
+
ssr ? 'ssr' : 'spa',
|
|
86
|
+
rootRoutePath ?? 'rootless',
|
|
87
|
+
].join(':'),
|
|
88
|
+
logPerformance,
|
|
89
|
+
ssr,
|
|
90
|
+
isBuild,
|
|
91
|
+
isSpaMode,
|
|
92
|
+
rootRoutePath,
|
|
93
|
+
devHmr,
|
|
94
|
+
},
|
|
95
|
+
parallelRouteTransform
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
rspackConfig.module ??= {};
|
|
99
|
+
rspackConfig.module.rules ??= [];
|
|
100
|
+
rspackConfig.module.rules.push(
|
|
101
|
+
{
|
|
102
|
+
resourceQuery: /\?react-router-route/,
|
|
103
|
+
enforce: 'post',
|
|
104
|
+
use: [routeModuleTransformUse],
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
test: path => routeByFilePath.has(path),
|
|
108
|
+
resourceQuery: {
|
|
109
|
+
not: /__react-router-build-client-route|react-router-route|route-chunk=/,
|
|
110
|
+
},
|
|
111
|
+
enforce: 'post',
|
|
112
|
+
use: [routeModuleTransformUse],
|
|
113
|
+
}
|
|
114
|
+
);
|
|
115
|
+
};
|
|
@@ -24,10 +24,7 @@ import {
|
|
|
24
24
|
type RouteChunkCache,
|
|
25
25
|
type RouteChunkConfig,
|
|
26
26
|
} from './route-chunks.js';
|
|
27
|
-
import {
|
|
28
|
-
getProgram,
|
|
29
|
-
type AnyNode,
|
|
30
|
-
} from './route-ast.js';
|
|
27
|
+
import { getProgram, type AnyNode } from './route-ast.js';
|
|
31
28
|
|
|
32
29
|
export type RouteTransformResult = {
|
|
33
30
|
code: string;
|
|
@@ -88,6 +85,10 @@ export type RouteTransformTaskOptions = {
|
|
|
88
85
|
routeChunkCache?: RouteChunkCache;
|
|
89
86
|
};
|
|
90
87
|
|
|
88
|
+
export type RouteTransformRunner = (
|
|
89
|
+
task: RouteTransformTask
|
|
90
|
+
) => Promise<RouteTransformResult>;
|
|
91
|
+
|
|
91
92
|
const defaultRouteChunkCache: RouteChunkCache = new Map();
|
|
92
93
|
|
|
93
94
|
const getRouteChunkCache = (options?: RouteTransformTaskOptions) =>
|
|
@@ -309,6 +310,41 @@ const buildComponentRefreshRegistrations = (names: string[]): string => {
|
|
|
309
310
|
return `\nif (typeof $RefreshReg$ === 'function') {\n${registrations}\n}\n`;
|
|
310
311
|
};
|
|
311
312
|
|
|
313
|
+
export const validateSpaModeRouteExports = ({
|
|
314
|
+
exportNames,
|
|
315
|
+
resourcePath,
|
|
316
|
+
rootRoutePath,
|
|
317
|
+
}: {
|
|
318
|
+
exportNames: readonly string[];
|
|
319
|
+
resourcePath: string;
|
|
320
|
+
rootRoutePath: string | null;
|
|
321
|
+
}): void => {
|
|
322
|
+
const isRootRoute = resourcePath === rootRoutePath;
|
|
323
|
+
const relativePath = relative(process.cwd(), resourcePath);
|
|
324
|
+
const invalidServerOnly = exportNames.filter(exp => {
|
|
325
|
+
if (isRootRoute && exp === 'loader') return false;
|
|
326
|
+
return SERVER_ONLY_ROUTE_EXPORTS_SET.has(exp);
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
if (invalidServerOnly.length > 0) {
|
|
330
|
+
const list = invalidServerOnly.map(exp => `\`${exp}\``).join(', ');
|
|
331
|
+
throw new Error(
|
|
332
|
+
`SPA Mode: ${invalidServerOnly.length} invalid route export(s) in ` +
|
|
333
|
+
`\`${relativePath}\`: ${list}. ` +
|
|
334
|
+
`See https://reactrouter.com/how-to/spa for more information.`
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
if (!isRootRoute && exportNames.includes('HydrateFallback')) {
|
|
339
|
+
throw new Error(
|
|
340
|
+
`SPA Mode: Invalid \`HydrateFallback\` export found in ` +
|
|
341
|
+
`\`${relativePath}\`. ` +
|
|
342
|
+
`\`HydrateFallback\` is only permitted on the root route in SPA Mode. ` +
|
|
343
|
+
`See https://reactrouter.com/how-to/spa for more information.`
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
|
|
312
348
|
const transformRouteModule = async (
|
|
313
349
|
task: RouteModuleTransformTask
|
|
314
350
|
): Promise<RouteTransformResult> => {
|
|
@@ -324,32 +360,11 @@ const transformRouteModule = async (
|
|
|
324
360
|
|
|
325
361
|
const ast = parse(code, { sourceType: 'module' });
|
|
326
362
|
if (task.environmentName === 'web' && !task.ssr && task.isSpaMode) {
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
const invalidServerOnly = resolvedExportNames.filter(exp => {
|
|
332
|
-
if (isRootRoute && exp === 'loader') return false;
|
|
333
|
-
return SERVER_ONLY_ROUTE_EXPORTS_SET.has(exp);
|
|
363
|
+
validateSpaModeRouteExports({
|
|
364
|
+
exportNames: collectProgramExportNames(getProgram(ast)),
|
|
365
|
+
resourcePath: task.resourcePath,
|
|
366
|
+
rootRoutePath: task.rootRoutePath,
|
|
334
367
|
});
|
|
335
|
-
|
|
336
|
-
if (invalidServerOnly.length > 0) {
|
|
337
|
-
const list = invalidServerOnly.map(e => `\`${e}\``).join(', ');
|
|
338
|
-
throw new Error(
|
|
339
|
-
`SPA Mode: ${invalidServerOnly.length} invalid route export(s) in ` +
|
|
340
|
-
`\`${relativePath}\`: ${list}. ` +
|
|
341
|
-
`See https://reactrouter.com/how-to/spa for more information.`
|
|
342
|
-
);
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
if (!isRootRoute && resolvedExportNames.includes('HydrateFallback')) {
|
|
346
|
-
throw new Error(
|
|
347
|
-
`SPA Mode: Invalid \`HydrateFallback\` export found in ` +
|
|
348
|
-
`\`${relativePath}\`. ` +
|
|
349
|
-
`\`HydrateFallback\` is only permitted on the root route in SPA Mode. ` +
|
|
350
|
-
`See https://reactrouter.com/how-to/spa for more information.`
|
|
351
|
-
);
|
|
352
|
-
}
|
|
353
368
|
}
|
|
354
369
|
|
|
355
370
|
const removedServerOnlyExports =
|