@bleedingdev/modern-js-runtime 3.2.0-ultramodern.10 → 3.2.0-ultramodern.100
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/cjs/boundary-debugger/index.js +299 -0
- package/dist/cjs/cli/ssr/index.js +5 -15
- package/dist/cjs/cli/template.server.js +1 -0
- package/dist/cjs/core/react/wrapper.js +9 -3
- package/dist/cjs/core/server/federatedCss.js +47 -0
- package/dist/cjs/core/server/helmet.js +8 -2
- package/dist/cjs/core/server/scriptOrder.js +59 -0
- package/dist/cjs/core/server/stream/afterTemplate.js +13 -5
- package/dist/cjs/core/server/stream/beforeTemplate.js +13 -20
- package/dist/cjs/core/server/stream/beforeTemplate.worker.js +98 -0
- package/dist/cjs/core/server/stream/createReadableStream.js +7 -2
- package/dist/cjs/core/server/stream/createReadableStream.worker.js +4 -2
- package/dist/cjs/core/server/stream/shared.js +3 -1
- package/dist/cjs/core/server/string/index.js +16 -9
- package/dist/cjs/core/server/string/loadable.js +74 -10
- package/dist/cjs/exports/head.js +196 -5
- package/dist/cjs/exports/loadable.js +34 -4
- package/dist/cjs/exports/tanstack-router.js +311 -54
- package/dist/cjs/router/cli/code/tanstackTypes.js +116 -51
- package/dist/cjs/router/cli/code/templates.js +15 -9
- package/dist/cjs/router/runtime/tanstack/hydrationBoundary.js +44 -0
- package/dist/cjs/router/runtime/tanstack/outlet.js +54 -0
- package/dist/cjs/router/runtime/tanstack/plugin.js +190 -88
- package/dist/cjs/router/runtime/tanstack/plugin.node.js +4 -14
- package/dist/cjs/router/runtime/tanstack/routeTree.js +64 -12
- package/dist/cjs/rsc/server.worker.js +58 -0
- package/dist/cjs/ssr/serverRender/renderToString/entry.js +9 -8
- package/dist/esm/boundary-debugger/index.mjs +263 -0
- package/dist/esm/cli/ssr/index.mjs +5 -15
- package/dist/esm/cli/template.server.mjs +1 -0
- package/dist/esm/core/react/wrapper.mjs +9 -3
- package/dist/esm/core/server/federatedCss.mjs +13 -0
- package/dist/esm/core/server/helmet.mjs +5 -2
- package/dist/esm/core/server/scriptOrder.mjs +25 -0
- package/dist/esm/core/server/stream/afterTemplate.mjs +14 -6
- package/dist/esm/core/server/stream/beforeTemplate.mjs +14 -11
- package/dist/esm/core/server/stream/beforeTemplate.worker.mjs +64 -0
- package/dist/esm/core/server/stream/createReadableStream.mjs +7 -2
- package/dist/esm/core/server/stream/createReadableStream.worker.mjs +4 -2
- package/dist/esm/core/server/stream/shared.mjs +3 -1
- package/dist/esm/core/server/string/index.mjs +17 -9
- package/dist/esm/core/server/string/loadable.mjs +70 -9
- package/dist/esm/exports/head.mjs +189 -4
- package/dist/esm/exports/loadable.mjs +20 -3
- package/dist/esm/exports/tanstack-router.mjs +2 -1
- package/dist/esm/router/cli/code/tanstackTypes.mjs +116 -51
- package/dist/esm/router/cli/code/templates.mjs +15 -9
- package/dist/esm/router/runtime/tanstack/hydrationBoundary.mjs +10 -0
- package/dist/esm/router/runtime/tanstack/outlet.mjs +17 -0
- package/dist/esm/router/runtime/tanstack/plugin.mjs +193 -91
- package/dist/esm/router/runtime/tanstack/plugin.node.mjs +5 -15
- package/dist/esm/router/runtime/tanstack/routeTree.mjs +65 -13
- package/dist/esm/rsc/server.worker.mjs +1 -0
- package/dist/esm/ssr/serverRender/renderToString/entry.mjs +9 -6
- package/dist/esm-node/boundary-debugger/index.mjs +264 -0
- package/dist/esm-node/cli/ssr/index.mjs +5 -15
- package/dist/esm-node/cli/template.server.mjs +1 -0
- package/dist/esm-node/core/react/wrapper.mjs +9 -3
- package/dist/esm-node/core/server/federatedCss.mjs +14 -0
- package/dist/esm-node/core/server/helmet.mjs +5 -2
- package/dist/esm-node/core/server/scriptOrder.mjs +26 -0
- package/dist/esm-node/core/server/stream/afterTemplate.mjs +14 -6
- package/dist/esm-node/core/server/stream/beforeTemplate.mjs +14 -11
- package/dist/esm-node/core/server/stream/beforeTemplate.worker.mjs +65 -0
- package/dist/esm-node/core/server/stream/createReadableStream.mjs +7 -2
- package/dist/esm-node/core/server/stream/createReadableStream.worker.mjs +4 -2
- package/dist/esm-node/core/server/stream/shared.mjs +3 -1
- package/dist/esm-node/core/server/string/index.mjs +17 -9
- package/dist/esm-node/core/server/string/loadable.mjs +70 -9
- package/dist/esm-node/exports/head.mjs +189 -4
- package/dist/esm-node/exports/loadable.mjs +20 -3
- package/dist/esm-node/exports/tanstack-router.mjs +2 -1
- package/dist/esm-node/router/cli/code/tanstackTypes.mjs +116 -51
- package/dist/esm-node/router/cli/code/templates.mjs +15 -9
- package/dist/esm-node/router/runtime/tanstack/hydrationBoundary.mjs +11 -0
- package/dist/esm-node/router/runtime/tanstack/outlet.mjs +18 -0
- package/dist/esm-node/router/runtime/tanstack/plugin.mjs +193 -91
- package/dist/esm-node/router/runtime/tanstack/plugin.node.mjs +5 -15
- package/dist/esm-node/router/runtime/tanstack/routeTree.mjs +65 -13
- package/dist/esm-node/rsc/server.worker.mjs +2 -0
- package/dist/esm-node/ssr/serverRender/renderToString/entry.mjs +9 -6
- package/dist/types/boundary-debugger/index.d.ts +28 -0
- package/dist/types/core/context/runtime.d.ts +4 -0
- package/dist/types/core/server/federatedCss.d.ts +5 -0
- package/dist/types/core/server/helmet.d.ts +5 -3
- package/dist/types/core/server/scriptOrder.d.ts +1 -0
- package/dist/types/core/server/stream/beforeTemplate.d.ts +1 -0
- package/dist/types/core/server/stream/beforeTemplate.worker.d.ts +10 -0
- package/dist/types/core/server/stream/shared.d.ts +8 -0
- package/dist/types/core/server/string/loadable.d.ts +11 -0
- package/dist/types/exports/head.d.ts +10 -3
- package/dist/types/exports/loadable.d.ts +8 -1
- package/dist/types/exports/tanstack-router.d.ts +3 -1
- package/dist/types/router/runtime/tanstack/hydrationBoundary.d.ts +2 -0
- package/dist/types/router/runtime/tanstack/outlet.d.ts +2 -0
- package/dist/types/rsc/server.worker.d.ts +1 -0
- package/package.json +24 -18
|
@@ -77,9 +77,21 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
77
77
|
const topLevel = rootModern ? rootModern.children || [] : routes;
|
|
78
78
|
const imports = [];
|
|
79
79
|
const statements = [];
|
|
80
|
+
const componentImportMap = new Map();
|
|
80
81
|
const loaderImportMap = new Map();
|
|
82
|
+
const usedRouteVarNames = new Set();
|
|
83
|
+
let componentIndex = 0;
|
|
81
84
|
let loaderIndex = 0;
|
|
82
85
|
let routeIndex = 0;
|
|
86
|
+
const getImportNameForComponent = (componentPath)=>{
|
|
87
|
+
if ('string' != typeof componentPath || 0 === componentPath.length) return null;
|
|
88
|
+
const existing = componentImportMap.get(componentPath);
|
|
89
|
+
if (existing) return existing;
|
|
90
|
+
const componentName = `component_${componentIndex++}`;
|
|
91
|
+
imports.push(`import ${componentName} from ${quote(componentPath)};`);
|
|
92
|
+
componentImportMap.set(componentPath, componentName);
|
|
93
|
+
return componentName;
|
|
94
|
+
};
|
|
83
95
|
const getImportNamesForLoader = async (aliasedNoExtPath, inline, hasAction)=>{
|
|
84
96
|
const key = `${inline ? 'inline' : 'default'}:${hasAction ? 'action' : 'loader'}:${aliasedNoExtPath}`;
|
|
85
97
|
const existing = loaderImportMap.get(key);
|
|
@@ -111,10 +123,17 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
111
123
|
actionName
|
|
112
124
|
};
|
|
113
125
|
};
|
|
126
|
+
const reserveRouteVarName = (preferred)=>{
|
|
127
|
+
let candidate = preferred;
|
|
128
|
+
let suffix = 1;
|
|
129
|
+
while(usedRouteVarNames.has(candidate))candidate = `${preferred}_${suffix++}`;
|
|
130
|
+
usedRouteVarNames.add(candidate);
|
|
131
|
+
return candidate;
|
|
132
|
+
};
|
|
114
133
|
const createRouteVarName = (route)=>{
|
|
115
134
|
const id = route.id;
|
|
116
135
|
const base = id ? makeLegalIdentifier(id) : `r_${routeIndex++}`;
|
|
117
|
-
return `route_${base}
|
|
136
|
+
return reserveRouteVarName(`route_${base}`);
|
|
118
137
|
};
|
|
119
138
|
const buildRoute = async (opts)=>{
|
|
120
139
|
const { parentVar, route } = opts;
|
|
@@ -129,6 +148,8 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
129
148
|
const routeOpts = [
|
|
130
149
|
`getParentRoute: () => ${parentVar},`
|
|
131
150
|
];
|
|
151
|
+
const componentName = getImportNameForComponent(route._component);
|
|
152
|
+
if (componentName) routeOpts.push(`component: ${componentName},`);
|
|
132
153
|
if (isPathlessLayout(route)) {
|
|
133
154
|
const id = route.id;
|
|
134
155
|
routeOpts.push(`id: ${quote(id || 'pathless')},`);
|
|
@@ -143,14 +164,16 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
143
164
|
actionName
|
|
144
165
|
});
|
|
145
166
|
if (staticDataSnippet) routeOpts.push(staticDataSnippet);
|
|
146
|
-
statements.push(`const ${varName} = createRoute({\n ${routeOpts.join('\n ')}\n});`);
|
|
147
167
|
const children = route.children;
|
|
168
|
+
const hasChildren = Boolean(children && children.length > 0);
|
|
169
|
+
const routeCtorVarName = hasChildren ? reserveRouteVarName(`${varName}__base`) : varName;
|
|
170
|
+
statements.push(`const ${routeCtorVarName} = createRoute({\n ${routeOpts.join('\n ')}\n});`);
|
|
148
171
|
if (children && children.length > 0) {
|
|
149
172
|
const childVars = await Promise.all(children.map((child)=>buildRoute({
|
|
150
|
-
parentVar:
|
|
173
|
+
parentVar: routeCtorVarName,
|
|
151
174
|
route: child
|
|
152
175
|
})));
|
|
153
|
-
statements.push(
|
|
176
|
+
statements.push(`const ${varName} = ${routeCtorVarName}.addChildren([${childVars.join(', ')}]);`);
|
|
154
177
|
}
|
|
155
178
|
return varName;
|
|
156
179
|
};
|
|
@@ -164,6 +187,8 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
164
187
|
route
|
|
165
188
|
})));
|
|
166
189
|
const rootOpts = [];
|
|
190
|
+
const rootComponentName = getImportNameForComponent(rootModern?._component);
|
|
191
|
+
if (rootComponentName) rootOpts.push(`component: ${rootComponentName},`);
|
|
167
192
|
if (rootLoaderName) rootOpts.push(`loader: modernLoaderToTanstack({ hasSplat: false }, ${rootLoaderName}),`);
|
|
168
193
|
const routerGenTs = `/* eslint-disable */
|
|
169
194
|
// This file is auto-generated by Modern.js. Do not edit manually.
|
|
@@ -197,7 +222,7 @@ function isRedirectResponse(res: Response) {
|
|
|
197
222
|
}
|
|
198
223
|
|
|
199
224
|
function throwTanstackRedirect(location: string) {
|
|
200
|
-
const target = location
|
|
225
|
+
const target = location.length > 0 ? location : '/';
|
|
201
226
|
try {
|
|
202
227
|
void new URL(target);
|
|
203
228
|
throw redirect({ href: target });
|
|
@@ -223,21 +248,87 @@ function createRouteStaticData(opts: {
|
|
|
223
248
|
modernRouteAction?: unknown;
|
|
224
249
|
modernRouteLoader?: unknown;
|
|
225
250
|
}) {
|
|
226
|
-
const staticData:
|
|
251
|
+
const staticData: {
|
|
252
|
+
modernRouteId?: string;
|
|
253
|
+
modernRouteAction?: unknown;
|
|
254
|
+
modernRouteLoader?: unknown;
|
|
255
|
+
} = {};
|
|
227
256
|
|
|
228
|
-
if (opts.modernRouteId) {
|
|
257
|
+
if (typeof opts.modernRouteId === 'string' && opts.modernRouteId.length > 0) {
|
|
229
258
|
staticData.modernRouteId = opts.modernRouteId;
|
|
230
259
|
}
|
|
231
260
|
|
|
232
|
-
if (opts.modernRouteLoader) {
|
|
261
|
+
if (typeof opts.modernRouteLoader !== 'undefined') {
|
|
233
262
|
staticData.modernRouteLoader = opts.modernRouteLoader;
|
|
234
263
|
}
|
|
235
264
|
|
|
236
|
-
if (opts.modernRouteAction) {
|
|
265
|
+
if (typeof opts.modernRouteAction !== 'undefined') {
|
|
237
266
|
staticData.modernRouteAction = opts.modernRouteAction;
|
|
238
267
|
}
|
|
239
268
|
|
|
240
|
-
return
|
|
269
|
+
return staticData;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function getLoaderSignal(ctx: any): AbortSignal {
|
|
273
|
+
const abortSignal = ctx?.abortController?.signal;
|
|
274
|
+
if (abortSignal instanceof AbortSignal) {
|
|
275
|
+
return abortSignal;
|
|
276
|
+
}
|
|
277
|
+
if (ctx?.signal instanceof AbortSignal) {
|
|
278
|
+
return ctx.signal;
|
|
279
|
+
}
|
|
280
|
+
return new AbortController().signal;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function getLoaderHref(ctx: any): string {
|
|
284
|
+
if (typeof ctx?.location === 'string') {
|
|
285
|
+
return ctx.location;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const publicHref = ctx?.location?.publicHref;
|
|
289
|
+
if (typeof publicHref === 'string') {
|
|
290
|
+
return publicHref;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const href = ctx?.location?.href;
|
|
294
|
+
if (typeof href === 'string') {
|
|
295
|
+
return href;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const urlHref = ctx?.location?.url?.href;
|
|
299
|
+
return typeof urlHref === 'string' ? urlHref : '';
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function getLoaderParams(ctx: any): Record<string, string> {
|
|
303
|
+
return typeof ctx?.params === 'object' && ctx.params !== null ? ctx.params : {};
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function handleModernLoaderResult<LoaderResult>(result: LoaderResult): LoaderResult {
|
|
307
|
+
if (isResponse(result)) {
|
|
308
|
+
if (isRedirectResponse(result)) {
|
|
309
|
+
const location = result.headers.get('Location') ?? '/';
|
|
310
|
+
throwTanstackRedirect(location);
|
|
311
|
+
}
|
|
312
|
+
if (result.status === 404) {
|
|
313
|
+
throw notFound();
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return result;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function handleModernLoaderError(err: unknown): never {
|
|
321
|
+
if (isResponse(err)) {
|
|
322
|
+
if (isRedirectResponse(err)) {
|
|
323
|
+
const location = err.headers.get('Location') ?? '/';
|
|
324
|
+
throwTanstackRedirect(location);
|
|
325
|
+
}
|
|
326
|
+
if (err.status === 404) {
|
|
327
|
+
throw notFound();
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
throw err;
|
|
241
332
|
}
|
|
242
333
|
|
|
243
334
|
function modernLoaderToTanstack<TLoader extends (args: any) => any>(
|
|
@@ -246,57 +337,31 @@ function modernLoaderToTanstack<TLoader extends (args: any) => any>(
|
|
|
246
337
|
) {
|
|
247
338
|
type LoaderResult = Awaited<ReturnType<TLoader>>;
|
|
248
339
|
|
|
249
|
-
return
|
|
340
|
+
return (ctx: any): Promise<LoaderResult> => {
|
|
250
341
|
try {
|
|
251
|
-
const signal
|
|
252
|
-
ctx?.abortController?.signal ||
|
|
253
|
-
ctx?.signal ||
|
|
254
|
-
new AbortController().signal;
|
|
342
|
+
const signal = getLoaderSignal(ctx);
|
|
255
343
|
const baseRequest: Request | undefined =
|
|
256
344
|
ctx?.context?.request instanceof Request ? ctx.context.request : undefined;
|
|
257
345
|
|
|
258
|
-
const href =
|
|
259
|
-
typeof ctx?.location === 'string'
|
|
260
|
-
? ctx.location
|
|
261
|
-
: ctx?.location?.publicHref ||
|
|
262
|
-
ctx?.location?.href ||
|
|
263
|
-
ctx?.location?.url?.href ||
|
|
264
|
-
'';
|
|
346
|
+
const href = getLoaderHref(ctx);
|
|
265
347
|
|
|
266
|
-
const request = baseRequest
|
|
348
|
+
const request = baseRequest !== undefined
|
|
267
349
|
? new Request(baseRequest, { signal })
|
|
268
350
|
: new Request(href, { signal });
|
|
269
351
|
|
|
270
|
-
const params = mapParamsForModernLoader(ctx
|
|
271
|
-
|
|
272
|
-
const result = await (modernLoader as any)({
|
|
273
|
-
request,
|
|
274
|
-
params,
|
|
275
|
-
context: ctx?.context?.requestContext,
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
if (isResponse(result)) {
|
|
279
|
-
if (isRedirectResponse(result)) {
|
|
280
|
-
const location = result.headers.get('Location') || '/';
|
|
281
|
-
throwTanstackRedirect(location);
|
|
282
|
-
}
|
|
283
|
-
if (result.status === 404) {
|
|
284
|
-
throw notFound();
|
|
285
|
-
}
|
|
286
|
-
}
|
|
352
|
+
const params = mapParamsForModernLoader(getLoaderParams(ctx), opts.hasSplat);
|
|
287
353
|
|
|
288
|
-
return
|
|
354
|
+
return Promise.resolve(
|
|
355
|
+
(modernLoader as any)({
|
|
356
|
+
request,
|
|
357
|
+
params,
|
|
358
|
+
context: ctx?.context?.requestContext,
|
|
359
|
+
}),
|
|
360
|
+
)
|
|
361
|
+
.then((result: LoaderResult) => handleModernLoaderResult(result))
|
|
362
|
+
.catch(handleModernLoaderError);
|
|
289
363
|
} catch (err) {
|
|
290
|
-
|
|
291
|
-
if (isRedirectResponse(err)) {
|
|
292
|
-
const location = err.headers.get('Location') || '/';
|
|
293
|
-
throwTanstackRedirect(location);
|
|
294
|
-
}
|
|
295
|
-
if (err.status === 404) {
|
|
296
|
-
throw notFound();
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
throw err;
|
|
364
|
+
handleModernLoaderError(err);
|
|
300
365
|
}
|
|
301
366
|
};
|
|
302
367
|
}
|
|
@@ -100,7 +100,20 @@ const fileSystemRoutes = async ({ metaName, routes, ssrMode, nestedRoutesEntry,
|
|
|
100
100
|
const loadersMapFile = path.join(internalDirectory, entryName, TEMP_LOADERS_DIR, 'map.json');
|
|
101
101
|
const importLazyCode = `
|
|
102
102
|
import { lazy } from "react";
|
|
103
|
-
import
|
|
103
|
+
import * as loadableModule from "@${metaName}/runtime/loadable"
|
|
104
|
+
|
|
105
|
+
const resolveLoadableExport = module => {
|
|
106
|
+
const candidates = [module, module.default, module.default?.default];
|
|
107
|
+
const loadable = candidates.find(candidate => typeof candidate === 'function');
|
|
108
|
+
|
|
109
|
+
if (!loadable) {
|
|
110
|
+
throw new TypeError('Modern.js runtime loadable export must resolve to a function');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return loadable;
|
|
114
|
+
};
|
|
115
|
+
const loadable = resolveLoadableExport(loadableModule);
|
|
116
|
+
const loadableLazy = loadableModule.lazy || loadableModule.default?.lazy || loadable.lazy;
|
|
104
117
|
`;
|
|
105
118
|
let rootLayoutCode = "";
|
|
106
119
|
const getDataLoaderPath = ({ loaderId, clientData, action, inline, routeId, inValidSSRRoute })=>{
|
|
@@ -170,16 +183,9 @@ const fileSystemRoutes = async ({ metaName, routes, ssrMode, nestedRoutesEntry,
|
|
|
170
183
|
webpackChunkName: true
|
|
171
184
|
});
|
|
172
185
|
component = 'string' === ssrMode ? `loadable(${lazyImport})` : `lazy(${lazyImport})`;
|
|
173
|
-
} else
|
|
186
|
+
} else {
|
|
174
187
|
components.push(route._component);
|
|
175
188
|
component = `component_${components.length - 1}`;
|
|
176
|
-
} else {
|
|
177
|
-
lazyImport = createLazyImport({
|
|
178
|
-
componentPath: route._component,
|
|
179
|
-
routeId: route.id,
|
|
180
|
-
eager: true
|
|
181
|
-
});
|
|
182
|
-
component = `lazy(${lazyImport})`;
|
|
183
189
|
}
|
|
184
190
|
} else if (route._component) if (splitRouteChunks) {
|
|
185
191
|
lazyImport = `() => import('${route._component}')`;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Suspense } from "react";
|
|
3
|
+
function wrapTanstackSsrHydrationBoundary(routerContent, shouldWrap) {
|
|
4
|
+
if (shouldWrap) return /*#__PURE__*/ jsx(Suspense, {
|
|
5
|
+
fallback: null,
|
|
6
|
+
children: routerContent
|
|
7
|
+
});
|
|
8
|
+
return routerContent;
|
|
9
|
+
}
|
|
10
|
+
export { wrapTanstackSsrHydrationBoundary };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Outlet } from "@tanstack/react-router";
|
|
3
|
+
import { createElement, memo } from "react";
|
|
4
|
+
const outlet_Outlet = /*#__PURE__*/ memo(function() {
|
|
5
|
+
return /*#__PURE__*/ jsx(Outlet, {});
|
|
6
|
+
});
|
|
7
|
+
function withModernRouteMatchContext(component, _routeId) {
|
|
8
|
+
if (!component) return component;
|
|
9
|
+
const Component = component;
|
|
10
|
+
const WrappedRouteComponent = (props)=>/*#__PURE__*/ createElement(Component, props);
|
|
11
|
+
const preloadable = component;
|
|
12
|
+
if ('function' == typeof preloadable.load) WrappedRouteComponent.load = preloadable.load.bind(preloadable);
|
|
13
|
+
if ('function' == typeof preloadable.preload) WrappedRouteComponent.preload = preloadable.preload.bind(preloadable);
|
|
14
|
+
else if ('function' == typeof preloadable.load) WrappedRouteComponent.preload = WrappedRouteComponent.load;
|
|
15
|
+
return WrappedRouteComponent;
|
|
16
|
+
}
|
|
17
|
+
export { outlet_Outlet as Outlet, withModernRouteMatchContext };
|
|
@@ -2,15 +2,18 @@ import { jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { merge } from "@modern-js/runtime-utils/merge";
|
|
3
3
|
import { normalizePathname } from "@modern-js/runtime-utils/url";
|
|
4
4
|
import { RouterProvider, createBrowserHistory, createHashHistory, createRouter, useLocation, useMatches, useNavigate, useRouter } from "@tanstack/react-router";
|
|
5
|
-
import {
|
|
5
|
+
import { hydrate } from "@tanstack/react-router/ssr/client";
|
|
6
|
+
import { useContext, useMemo } from "react";
|
|
6
7
|
import { InternalRuntimeContext, getGlobalEnableRsc, getGlobalLayoutApp, getGlobalRoutes } from "../../../core/context/index.mjs";
|
|
7
8
|
import { onAfterCreateRouter, onAfterHydrateRouter, onBeforeCreateRouter, onBeforeHydrateRouter } from "../hooks.mjs";
|
|
8
9
|
import { applyRouterRuntimeState } from "../lifecycle.mjs";
|
|
9
10
|
import { createRouteObjectsFromConfig, urlJoin } from "../utils.mjs";
|
|
10
11
|
import { createModernBasepathRewrite } from "./basepathRewrite.mjs";
|
|
12
|
+
import { wrapTanstackSsrHydrationBoundary } from "./hydrationBoundary.mjs";
|
|
13
|
+
import { withModernRouteMatchContext } from "./outlet.mjs";
|
|
14
|
+
import { Link } from "./prefetchLink.mjs";
|
|
11
15
|
import { createRouteTreeFromRouteObjects } from "./routeTree.mjs";
|
|
12
16
|
import { getTanstackRscSerializationAdapters } from "./rsc/client.mjs";
|
|
13
|
-
import * as __rspack_external_react from "react";
|
|
14
17
|
const BLOCKING_SUBSCRIBE_SYMBOL = Symbol.for('@modern-js/plugin-runtime:tanstack-blocking-subscribe');
|
|
15
18
|
const BLOCKING_STATE_SYMBOL = Symbol.for('@modern-js/plugin-runtime:tanstack-blocking-state');
|
|
16
19
|
function normalizeBase(b) {
|
|
@@ -38,6 +41,85 @@ function wrapRouterSubscribeWithBlockState(router, getBlockNavState) {
|
|
|
38
41
|
};
|
|
39
42
|
target[BLOCKING_SUBSCRIBE_SYMBOL] = true;
|
|
40
43
|
}
|
|
44
|
+
const routerHydrationRecords = new WeakMap();
|
|
45
|
+
const routeModulesKey = '_routeModules';
|
|
46
|
+
function pickRouteModuleComponent(routeModule, seen = new Set()) {
|
|
47
|
+
if ('function' == typeof routeModule || routeModule && 'object' == typeof routeModule && '$$typeof' in routeModule) return routeModule;
|
|
48
|
+
if (!routeModule || 'object' != typeof routeModule) return;
|
|
49
|
+
if (seen.has(routeModule)) return;
|
|
50
|
+
seen.add(routeModule);
|
|
51
|
+
const module = routeModule;
|
|
52
|
+
for (const candidate of [
|
|
53
|
+
module.default,
|
|
54
|
+
module.Component
|
|
55
|
+
]){
|
|
56
|
+
const component = pickRouteModuleComponent(candidate, seen);
|
|
57
|
+
if (component) return component;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function getCachedRouteModule(routeId) {
|
|
61
|
+
if ("u" < typeof window) return;
|
|
62
|
+
return window[routeModulesKey]?.[routeId];
|
|
63
|
+
}
|
|
64
|
+
async function preloadHydratedRouteComponents(router) {
|
|
65
|
+
const preloadableRouter = router;
|
|
66
|
+
const routesById = preloadableRouter.routesById || {};
|
|
67
|
+
const matches = preloadableRouter.stores.matches.get();
|
|
68
|
+
await Promise.all(matches.map((match)=>{
|
|
69
|
+
if (!match.routeId) return;
|
|
70
|
+
const route = routesById[match.routeId];
|
|
71
|
+
const component = route?.options?.component;
|
|
72
|
+
const preload = component?.load || component?.preload;
|
|
73
|
+
if ('function' != typeof preload) return;
|
|
74
|
+
return Promise.resolve(preload.call(component)).then((routeModule)=>{
|
|
75
|
+
const modernRouteId = route?.options?.staticData?.modernRouteId;
|
|
76
|
+
const resolvedComponent = pickRouteModuleComponent(modernRouteId && getCachedRouteModule(modernRouteId) || routeModule);
|
|
77
|
+
if (resolvedComponent && modernRouteId) route.options.component = withModernRouteMatchContext(resolvedComponent, modernRouteId);
|
|
78
|
+
});
|
|
79
|
+
}));
|
|
80
|
+
}
|
|
81
|
+
function getTanstackSsrHydrationRecord(router) {
|
|
82
|
+
let hydrationRecord = routerHydrationRecords.get(router);
|
|
83
|
+
if (!hydrationRecord) {
|
|
84
|
+
hydrationRecord = {
|
|
85
|
+
promise: Promise.resolve(),
|
|
86
|
+
status: 'pending'
|
|
87
|
+
};
|
|
88
|
+
routerHydrationRecords.set(router, hydrationRecord);
|
|
89
|
+
try {
|
|
90
|
+
hydrationRecord.promise = hydrate(router).then(async (value)=>{
|
|
91
|
+
await preloadHydratedRouteComponents(router);
|
|
92
|
+
return value;
|
|
93
|
+
}).then((value)=>{
|
|
94
|
+
hydrationRecord.status = 'fulfilled';
|
|
95
|
+
return value;
|
|
96
|
+
}, (error)=>{
|
|
97
|
+
hydrationRecord.status = 'rejected';
|
|
98
|
+
hydrationRecord.error = error;
|
|
99
|
+
throw error;
|
|
100
|
+
});
|
|
101
|
+
} catch (error) {
|
|
102
|
+
hydrationRecord.status = 'rejected';
|
|
103
|
+
hydrationRecord.error = error;
|
|
104
|
+
hydrationRecord.promise = Promise.reject(error);
|
|
105
|
+
hydrationRecord.promise.catch(()=>{});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return hydrationRecord;
|
|
109
|
+
}
|
|
110
|
+
function getTanstackSsrHydrationPromise(router) {
|
|
111
|
+
return getTanstackSsrHydrationRecord(router).promise;
|
|
112
|
+
}
|
|
113
|
+
function hasTanstackSsrHydrationRecord(router) {
|
|
114
|
+
return routerHydrationRecords.has(router);
|
|
115
|
+
}
|
|
116
|
+
function ModernRouterClient({ router }) {
|
|
117
|
+
const hydrationRecord = getTanstackSsrHydrationRecord(router);
|
|
118
|
+
if ('rejected' === hydrationRecord.status) throw hydrationRecord.error;
|
|
119
|
+
return /*#__PURE__*/ jsx(RouterProvider, {
|
|
120
|
+
router: router
|
|
121
|
+
});
|
|
122
|
+
}
|
|
41
123
|
function stripSyntheticNotFoundRoute(routes) {
|
|
42
124
|
return routes.filter((route)=>!('*' === route.path && !route.id && !route.loader)).map((route)=>{
|
|
43
125
|
if (!route.children?.length) return route;
|
|
@@ -56,9 +138,94 @@ const tanstackRouterPlugin = (userConfig = {})=>({
|
|
|
56
138
|
onBeforeHydrateRouter: onBeforeHydrateRouter
|
|
57
139
|
},
|
|
58
140
|
setup: (api)=>{
|
|
59
|
-
api.
|
|
141
|
+
const hooks = api.getHooks();
|
|
142
|
+
let cachedRouteObjects;
|
|
143
|
+
let cachedRouteTree = null;
|
|
144
|
+
let cachedRouter = null;
|
|
145
|
+
let cachedRouterBasepath = null;
|
|
146
|
+
const getMergedConfig = ()=>{
|
|
60
147
|
const pluginConfig = api.getRuntimeConfig();
|
|
61
|
-
|
|
148
|
+
return merge(pluginConfig.router || {}, userConfig);
|
|
149
|
+
};
|
|
150
|
+
const getRouteObjects = ()=>{
|
|
151
|
+
if (void 0 !== cachedRouteObjects) return cachedRouteObjects;
|
|
152
|
+
const mergedConfig = getMergedConfig();
|
|
153
|
+
const { routesConfig, createRoutes } = mergedConfig;
|
|
154
|
+
const finalRouteConfig = {
|
|
155
|
+
routes: getGlobalRoutes(),
|
|
156
|
+
globalApp: getGlobalLayoutApp(),
|
|
157
|
+
...routesConfig
|
|
158
|
+
};
|
|
159
|
+
const routeObjects = createRoutes ? createRoutes() : createRouteObjectsFromConfig({
|
|
160
|
+
routesConfig: finalRouteConfig
|
|
161
|
+
}) || [];
|
|
162
|
+
const normalizedRouteObjects = createRoutes ? routeObjects : stripSyntheticNotFoundRoute(routeObjects);
|
|
163
|
+
cachedRouteObjects = hooks.modifyRoutes.call(normalizedRouteObjects);
|
|
164
|
+
return cachedRouteObjects;
|
|
165
|
+
};
|
|
166
|
+
const getRouteTree = ()=>{
|
|
167
|
+
if (cachedRouteTree) return cachedRouteTree;
|
|
168
|
+
const routeObjects = getRouteObjects();
|
|
169
|
+
if (!routeObjects.length) return null;
|
|
170
|
+
cachedRouteTree = createRouteTreeFromRouteObjects(routeObjects);
|
|
171
|
+
return cachedRouteTree;
|
|
172
|
+
};
|
|
173
|
+
const selectBasePath = (pathname)=>{
|
|
174
|
+
const { serverBase = [] } = getMergedConfig();
|
|
175
|
+
const match = serverBase.find((baseUrl)=>isSegmentPrefix(pathname, baseUrl));
|
|
176
|
+
return match || '/';
|
|
177
|
+
};
|
|
178
|
+
const getClientBasename = (runtimeContext)=>{
|
|
179
|
+
const { basename = '' } = getMergedConfig();
|
|
180
|
+
const baseUrl = selectBasePath(location.pathname).replace(/^\/*/, '/');
|
|
181
|
+
return '/' === baseUrl ? urlJoin(baseUrl, runtimeContext._internalRouterBaseName || basename || '') : baseUrl;
|
|
182
|
+
};
|
|
183
|
+
const getRouter = (runtimeContext, _basename)=>{
|
|
184
|
+
const routeTree = getRouteTree();
|
|
185
|
+
if (!routeTree) return null;
|
|
186
|
+
const lifecycleContext = {
|
|
187
|
+
framework: 'tanstack',
|
|
188
|
+
phase: 'client-create',
|
|
189
|
+
routes: getRouteObjects(),
|
|
190
|
+
runtimeContext,
|
|
191
|
+
basename: _basename
|
|
192
|
+
};
|
|
193
|
+
hooks.onBeforeCreateRouter.call(lifecycleContext);
|
|
194
|
+
if (cachedRouter && cachedRouterBasepath === _basename) {
|
|
195
|
+
wrapRouterSubscribeWithBlockState(cachedRouter, runtimeContext.unstable_getBlockNavState);
|
|
196
|
+
hooks.onAfterCreateRouter.call({
|
|
197
|
+
...lifecycleContext,
|
|
198
|
+
router: cachedRouter,
|
|
199
|
+
runtimeContext
|
|
200
|
+
});
|
|
201
|
+
return cachedRouter;
|
|
202
|
+
}
|
|
203
|
+
const mergedConfig = getMergedConfig();
|
|
204
|
+
const { supportHtml5History = true } = mergedConfig;
|
|
205
|
+
const history = supportHtml5History ? createBrowserHistory() : createHashHistory();
|
|
206
|
+
const rewrite = createModernBasepathRewrite(_basename);
|
|
207
|
+
const serializationAdapters = getGlobalEnableRsc() ? getTanstackRscSerializationAdapters() : void 0;
|
|
208
|
+
cachedRouter = createRouter({
|
|
209
|
+
routeTree,
|
|
210
|
+
basepath: '/',
|
|
211
|
+
rewrite,
|
|
212
|
+
history,
|
|
213
|
+
context: {},
|
|
214
|
+
...serializationAdapters ? {
|
|
215
|
+
serializationAdapters
|
|
216
|
+
} : {}
|
|
217
|
+
});
|
|
218
|
+
cachedRouterBasepath = _basename;
|
|
219
|
+
wrapRouterSubscribeWithBlockState(cachedRouter, runtimeContext.unstable_getBlockNavState);
|
|
220
|
+
hooks.onAfterCreateRouter.call({
|
|
221
|
+
...lifecycleContext,
|
|
222
|
+
router: cachedRouter,
|
|
223
|
+
runtimeContext
|
|
224
|
+
});
|
|
225
|
+
return cachedRouter;
|
|
226
|
+
};
|
|
227
|
+
api.onBeforeRender(async (context)=>{
|
|
228
|
+
const mergedConfig = getMergedConfig();
|
|
62
229
|
if ("u" > typeof window && window._SSR_DATA && mergedConfig.unstable_reloadOnURLMismatch) {
|
|
63
230
|
const { ssrContext } = context;
|
|
64
231
|
const currentPathname = normalizePathname(window.location.pathname);
|
|
@@ -70,96 +237,32 @@ const tanstackRouterPlugin = (userConfig = {})=>({
|
|
|
70
237
|
}
|
|
71
238
|
}
|
|
72
239
|
context.router = {
|
|
240
|
+
Link: Link,
|
|
73
241
|
useMatches: useMatches,
|
|
74
242
|
useLocation: useLocation,
|
|
75
243
|
useNavigate: useNavigate,
|
|
76
244
|
useRouter: useRouter
|
|
77
245
|
};
|
|
246
|
+
const hasSSRBootstrap = "u" > typeof window && Boolean(window.$_TSR);
|
|
247
|
+
if (hasSSRBootstrap && getRouteObjects().length) {
|
|
248
|
+
const runtimeContext = context;
|
|
249
|
+
const router = getRouter(runtimeContext, getClientBasename(runtimeContext));
|
|
250
|
+
if (router) await getTanstackSsrHydrationPromise(router);
|
|
251
|
+
}
|
|
78
252
|
});
|
|
79
253
|
api.wrapRoot((App)=>{
|
|
80
|
-
|
|
81
|
-
const { serverBase = [], supportHtml5History = true, basename = '', routesConfig, createRoutes } = mergedConfig;
|
|
82
|
-
const finalRouteConfig = {
|
|
83
|
-
routes: getGlobalRoutes(),
|
|
84
|
-
globalApp: getGlobalLayoutApp(),
|
|
85
|
-
...routesConfig
|
|
86
|
-
};
|
|
87
|
-
if (!finalRouteConfig.routes && !createRoutes) return App;
|
|
88
|
-
const hooks = api.getHooks();
|
|
89
|
-
let cachedRouteObjects;
|
|
90
|
-
const getRouteObjects = ()=>{
|
|
91
|
-
if (void 0 !== cachedRouteObjects) return cachedRouteObjects;
|
|
92
|
-
const routeObjects = createRoutes ? createRoutes() : createRouteObjectsFromConfig({
|
|
93
|
-
routesConfig: finalRouteConfig
|
|
94
|
-
}) || [];
|
|
95
|
-
const normalizedRouteObjects = createRoutes ? routeObjects : stripSyntheticNotFoundRoute(routeObjects);
|
|
96
|
-
cachedRouteObjects = hooks.modifyRoutes.call(normalizedRouteObjects);
|
|
97
|
-
return cachedRouteObjects;
|
|
98
|
-
};
|
|
99
|
-
const selectBasePath = (pathname)=>{
|
|
100
|
-
const match = serverBase.find((baseUrl)=>isSegmentPrefix(pathname, baseUrl));
|
|
101
|
-
return match || '/';
|
|
102
|
-
};
|
|
103
|
-
let cachedRouteTree = null;
|
|
104
|
-
let cachedRouter = null;
|
|
105
|
-
let cachedRouterBasepath = null;
|
|
254
|
+
if (!getRouteObjects().length) return App;
|
|
106
255
|
const RouterWrapper = ()=>{
|
|
107
|
-
const runtimeContext =
|
|
108
|
-
const
|
|
109
|
-
const
|
|
110
|
-
const routeTree = (0, __rspack_external_react.useMemo)(()=>{
|
|
111
|
-
if (cachedRouteTree) return cachedRouteTree;
|
|
112
|
-
const routeObjects = getRouteObjects();
|
|
113
|
-
if (!routeObjects.length) return null;
|
|
114
|
-
cachedRouteTree = createRouteTreeFromRouteObjects(routeObjects);
|
|
115
|
-
return cachedRouteTree;
|
|
116
|
-
}, []);
|
|
256
|
+
const runtimeContext = useContext(InternalRuntimeContext);
|
|
257
|
+
const _basename = getClientBasename(runtimeContext);
|
|
258
|
+
const routeTree = useMemo(()=>getRouteTree(), []);
|
|
117
259
|
if (!routeTree) return App ? /*#__PURE__*/ jsx(App, {}) : null;
|
|
118
|
-
const router =
|
|
119
|
-
const lifecycleContext = {
|
|
120
|
-
framework: 'tanstack',
|
|
121
|
-
phase: 'client-create',
|
|
122
|
-
routes: getRouteObjects(),
|
|
123
|
-
runtimeContext,
|
|
124
|
-
basename: _basename
|
|
125
|
-
};
|
|
126
|
-
hooks.onBeforeCreateRouter.call(lifecycleContext);
|
|
127
|
-
if (cachedRouter && cachedRouterBasepath === _basename) {
|
|
128
|
-
wrapRouterSubscribeWithBlockState(cachedRouter, runtimeContext.unstable_getBlockNavState);
|
|
129
|
-
hooks.onAfterCreateRouter.call({
|
|
130
|
-
...lifecycleContext,
|
|
131
|
-
router: cachedRouter,
|
|
132
|
-
runtimeContext
|
|
133
|
-
});
|
|
134
|
-
return cachedRouter;
|
|
135
|
-
}
|
|
136
|
-
const history = supportHtml5History ? createBrowserHistory() : createHashHistory();
|
|
137
|
-
const rewrite = createModernBasepathRewrite(_basename);
|
|
138
|
-
const serializationAdapters = getGlobalEnableRsc() ? getTanstackRscSerializationAdapters() : void 0;
|
|
139
|
-
cachedRouter = createRouter({
|
|
140
|
-
routeTree,
|
|
141
|
-
basepath: '/',
|
|
142
|
-
rewrite,
|
|
143
|
-
history,
|
|
144
|
-
context: {},
|
|
145
|
-
...serializationAdapters ? {
|
|
146
|
-
serializationAdapters
|
|
147
|
-
} : {}
|
|
148
|
-
});
|
|
149
|
-
cachedRouterBasepath = _basename;
|
|
150
|
-
wrapRouterSubscribeWithBlockState(cachedRouter, runtimeContext.unstable_getBlockNavState);
|
|
151
|
-
hooks.onAfterCreateRouter.call({
|
|
152
|
-
...lifecycleContext,
|
|
153
|
-
router: cachedRouter,
|
|
154
|
-
runtimeContext
|
|
155
|
-
});
|
|
156
|
-
return cachedRouter;
|
|
157
|
-
}, [
|
|
260
|
+
const router = useMemo(()=>getRouter(runtimeContext, _basename), [
|
|
158
261
|
_basename,
|
|
159
262
|
routeTree,
|
|
160
|
-
supportHtml5History,
|
|
161
263
|
runtimeContext
|
|
162
264
|
]);
|
|
265
|
+
if (!router) return App ? /*#__PURE__*/ jsx(App, {}) : null;
|
|
163
266
|
const runtimeState = applyRouterRuntimeState(runtimeContext, {
|
|
164
267
|
framework: 'tanstack',
|
|
165
268
|
basename: _basename,
|
|
@@ -173,30 +276,29 @@ const tanstackRouterPlugin = (userConfig = {})=>({
|
|
|
173
276
|
basename: _basename,
|
|
174
277
|
router
|
|
175
278
|
};
|
|
176
|
-
const hasSSRBootstrap = "u" > typeof window && Boolean(window.$_TSR);
|
|
177
|
-
|
|
279
|
+
const hasSSRBootstrap = "u" > typeof window && (Boolean(window.$_TSR) || hasTanstackSsrHydrationRecord(router));
|
|
280
|
+
const needsRouterClient = hasSSRBootstrap;
|
|
281
|
+
if (needsRouterClient) hooks.onBeforeHydrateRouter.call({
|
|
178
282
|
...lifecycleContext,
|
|
179
283
|
phase: 'hydrate',
|
|
180
284
|
router,
|
|
181
285
|
runtimeContext: runtimeState
|
|
182
286
|
});
|
|
183
|
-
const RouterContent =
|
|
184
|
-
|
|
185
|
-
children: /*#__PURE__*/ jsx(RouterClient, {
|
|
186
|
-
router: router
|
|
187
|
-
})
|
|
287
|
+
const RouterContent = needsRouterClient ? /*#__PURE__*/ jsx(ModernRouterClient, {
|
|
288
|
+
router: router
|
|
188
289
|
}) : /*#__PURE__*/ jsx(RouterProvider, {
|
|
189
290
|
router: router
|
|
190
291
|
});
|
|
191
|
-
|
|
292
|
+
const HydratableRouterContent = wrapTanstackSsrHydrationBoundary(RouterContent, hasSSRBootstrap);
|
|
293
|
+
if (needsRouterClient) hooks.onAfterHydrateRouter.call({
|
|
192
294
|
...lifecycleContext,
|
|
193
295
|
phase: 'hydrate',
|
|
194
296
|
router,
|
|
195
297
|
runtimeContext: runtimeState
|
|
196
298
|
});
|
|
197
299
|
return App ? /*#__PURE__*/ jsx(App, {
|
|
198
|
-
children:
|
|
199
|
-
}) :
|
|
300
|
+
children: HydratableRouterContent
|
|
301
|
+
}) : HydratableRouterContent;
|
|
200
302
|
};
|
|
201
303
|
return RouterWrapper;
|
|
202
304
|
});
|