@bleedingdev/modern-js-plugin-tanstack 3.5.0-ultramodern.102 → 3.5.0-ultramodern.103
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/cli/index.js +4 -0
- package/dist/cjs/cli/tanstackTypes/source.js +7 -17
- package/dist/cjs/runtime/plugin.node.js +12 -5
- package/dist/cjs/runtime/pluginShared.js +3 -3
- package/dist/cjs/runtime/rsc/payloadErrors.js +2 -2
- package/dist/cjs/runtime/rsc/shared.js +1 -1
- package/dist/cjs/runtime/rsc/treeGetter.js +5 -9
- package/dist/cjs/runtime/submitAction.js +4 -5
- package/dist/esm/cli/index.mjs +4 -0
- package/dist/esm/cli/tanstackTypes/source.mjs +7 -7
- package/dist/esm/runtime/plugin.node.mjs +12 -5
- package/dist/esm/runtime/pluginShared.mjs +3 -3
- package/dist/esm/runtime/rsc/payloadErrors.mjs +1 -1
- package/dist/esm/runtime/rsc/shared.mjs +1 -1
- package/dist/esm/runtime/rsc/treeGetter.mjs +5 -9
- package/dist/esm/runtime/submitAction.mjs +4 -5
- package/dist/esm-node/cli/index.mjs +4 -0
- package/dist/esm-node/cli/tanstackTypes/source.mjs +7 -7
- package/dist/esm-node/runtime/plugin.node.mjs +12 -5
- package/dist/esm-node/runtime/pluginShared.mjs +3 -3
- package/dist/esm-node/runtime/rsc/payloadErrors.mjs +1 -1
- package/dist/esm-node/runtime/rsc/shared.mjs +1 -1
- package/dist/esm-node/runtime/rsc/treeGetter.mjs +5 -9
- package/dist/esm-node/runtime/submitAction.mjs +4 -5
- package/dist/types/runtime/clientHydration.d.ts +1 -1
- package/dist/types/runtime/ssrTypes.d.ts +0 -2
- package/package.json +26 -20
- package/rstest.config.mts +2 -0
- package/src/cli/index.ts +6 -0
- package/src/cli/tanstackTypes/canonicalRoutes.ts +0 -1
- package/src/cli/tanstackTypes/shared.ts +0 -1
- package/src/cli/tanstackTypes/source.ts +1 -1
- package/src/runtime/plugin.node.tsx +17 -11
- package/src/runtime/plugin.tsx +0 -2
- package/src/runtime/pluginShared.ts +8 -7
- package/src/runtime/rsc/payloadErrors.ts +1 -1
- package/src/runtime/rsc/shared.ts +1 -1
- package/src/runtime/rsc/treeGetter.tsx +9 -8
- package/src/runtime/ssrManagedTags.ts +0 -2
- package/src/runtime/ssrTypes.ts +0 -4
- package/src/runtime/submitAction.ts +6 -11
- package/src/types/react-server-dom-rspack.d.ts +4 -52
- package/tests/router/cli.test.ts +2 -0
- package/tests/router/clientHydration.test.tsx +140 -1
- package/tests/router/dataMutation.test.tsx +50 -9
- package/tests/router/fixtures/rscDecoderSecurityChild.cjs +162 -0
- package/tests/router/preloadRedirect.test.ts +3 -8
- package/tests/router/routeTree.test.ts +73 -19
- package/tests/router/rscDecoderSecurity.test.ts +113 -0
- package/tests/router/serverPlugin.test.ts +115 -0
- package/tests/router/tanstackTypes.test.ts +351 -26
- package/src/runtime/ssr-shim.d.ts +0 -10
package/dist/cjs/cli/index.js
CHANGED
|
@@ -171,6 +171,8 @@ var __webpack_exports__ = {};
|
|
|
171
171
|
const routesByEntry = await handleGeneratorEntryCode(api, tanstackEntrypoints, {
|
|
172
172
|
entrypointsKey: ENTRYPOINTS_KEY,
|
|
173
173
|
hydrateRscClientRoutes: true,
|
|
174
|
+
includeRouteServerLoadersInSsrEntry: false,
|
|
175
|
+
isolateRouteDataInRscLayer: true,
|
|
174
176
|
serverRoutesFileName: 'tanstack-routes.server.js'
|
|
175
177
|
});
|
|
176
178
|
await (0, external_artifacts_js_namespaceObject.writeTanstackRouterTypesForEntries)({
|
|
@@ -193,6 +195,8 @@ var __webpack_exports__ = {};
|
|
|
193
195
|
const routesByEntry = await handleGeneratorEntryCode(api, entrypoints, {
|
|
194
196
|
entrypointsKey: ENTRYPOINTS_KEY,
|
|
195
197
|
hydrateRscClientRoutes: true,
|
|
198
|
+
includeRouteServerLoadersInSsrEntry: false,
|
|
199
|
+
isolateRouteDataInRscLayer: true,
|
|
196
200
|
serverRoutesFileName: 'tanstack-routes.server.js'
|
|
197
201
|
});
|
|
198
202
|
await (0, external_artifacts_js_namespaceObject.writeTanstackRouterTypesForEntries)({
|
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __webpack_require__ = {};
|
|
3
|
-
(()=>{
|
|
4
|
-
__webpack_require__.n = (module)=>{
|
|
5
|
-
var getter = module && module.__esModule ? ()=>module['default'] : ()=>module;
|
|
6
|
-
__webpack_require__.d(getter, {
|
|
7
|
-
a: getter
|
|
8
|
-
});
|
|
9
|
-
return getter;
|
|
10
|
-
};
|
|
11
|
-
})();
|
|
12
3
|
(()=>{
|
|
13
4
|
__webpack_require__.d = (exports1, getters, values)=>{
|
|
14
5
|
var define = (defs, kind)=>{
|
|
@@ -39,13 +30,12 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
39
30
|
__webpack_require__.d(__webpack_exports__, {
|
|
40
31
|
generateTanstackRouterTypesSourceForEntry: ()=>generateTanstackRouterTypesSourceForEntry
|
|
41
32
|
});
|
|
42
|
-
const external_node_path_namespaceObject = require("node:path");
|
|
43
|
-
var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_node_path_namespaceObject);
|
|
44
33
|
const cli_namespaceObject = require("@modern-js/runtime/cli");
|
|
34
|
+
const utils_namespaceObject = require("@modern-js/utils");
|
|
45
35
|
const external_shared_js_namespaceObject = require("./shared.js");
|
|
46
36
|
async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
47
37
|
const { appContext, entryName, generatedDirName = 'modern-tanstack', routes } = opts;
|
|
48
|
-
const outDir =
|
|
38
|
+
const outDir = utils_namespaceObject.upath.join(appContext.srcDirectory, generatedDirName, entryName);
|
|
49
39
|
const rootModern = routes.find((r)=>{
|
|
50
40
|
const extras = r;
|
|
51
41
|
return r && 'nested' === extras.type && extras.isRoot;
|
|
@@ -70,7 +60,7 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
70
60
|
pendingImportName = (async ()=>{
|
|
71
61
|
const resolvedNoExt = await resolveRouteModuleNoExt(componentPath);
|
|
72
62
|
if (!resolvedNoExt) return null;
|
|
73
|
-
const relImport = (0, external_shared_js_namespaceObject.normalizeRelativeImport)(
|
|
63
|
+
const relImport = (0, external_shared_js_namespaceObject.normalizeRelativeImport)(utils_namespaceObject.upath.relative(outDir, resolvedNoExt));
|
|
74
64
|
const componentName = `component_${componentIndex++}`;
|
|
75
65
|
imports.push(`import ${componentName} from ${(0, external_shared_js_namespaceObject.quote)(relImport)};`);
|
|
76
66
|
return componentName;
|
|
@@ -84,8 +74,8 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
84
74
|
let absNoExt;
|
|
85
75
|
if (aliasedNoExtPath.startsWith(prefix)) {
|
|
86
76
|
const rel = aliasedNoExtPath.slice(prefix.length);
|
|
87
|
-
absNoExt =
|
|
88
|
-
} else absNoExt =
|
|
77
|
+
absNoExt = utils_namespaceObject.upath.join(appContext.srcDirectory, rel);
|
|
78
|
+
} else absNoExt = utils_namespaceObject.upath.isAbsolute(aliasedNoExtPath) ? aliasedNoExtPath : utils_namespaceObject.upath.join(appContext.srcDirectory, aliasedNoExtPath);
|
|
89
79
|
return (0, external_shared_js_namespaceObject.resolveFileNoExt)(absNoExt);
|
|
90
80
|
};
|
|
91
81
|
const getImportNamesForLoader = async (aliasedNoExtPath, inline, hasAction)=>{
|
|
@@ -97,7 +87,7 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
97
87
|
};
|
|
98
88
|
const resolvedNoExt = await resolveRouteModuleNoExt(aliasedNoExtPath);
|
|
99
89
|
if (!resolvedNoExt) return null;
|
|
100
|
-
const relImport = (0, external_shared_js_namespaceObject.normalizeRelativeImport)(
|
|
90
|
+
const relImport = (0, external_shared_js_namespaceObject.normalizeRelativeImport)(utils_namespaceObject.upath.relative(outDir, resolvedNoExt));
|
|
101
91
|
const importName = `loader_${loaderIndex++}`;
|
|
102
92
|
const actionName = hasAction ? importName.replace(/^loader_/, 'action_') : null;
|
|
103
93
|
if (inline) {
|
|
@@ -119,7 +109,7 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
119
109
|
if (existing) return existing;
|
|
120
110
|
const resolvedNoExt = await resolveRouteModuleNoExt(aliasedNoExtPath);
|
|
121
111
|
if (!resolvedNoExt) return null;
|
|
122
|
-
const relImport = (0, external_shared_js_namespaceObject.normalizeRelativeImport)(
|
|
112
|
+
const relImport = (0, external_shared_js_namespaceObject.normalizeRelativeImport)(utils_namespaceObject.upath.relative(outDir, resolvedNoExt));
|
|
123
113
|
const importName = 'validateSearch' === exportName ? `validateSearch_${validateSearchIndex++}` : `loaderDeps_${loaderDepsIndex++}`;
|
|
124
114
|
imports.push(`import { ${exportName} as ${importName} } from ${(0, external_shared_js_namespaceObject.quote)(relImport)};`);
|
|
125
115
|
searchContractImportMap.set(key, importName);
|
|
@@ -127,12 +127,19 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
127
127
|
const cost = end();
|
|
128
128
|
context.ssrContext?.onTiming?.(constants_namespaceObject.LOADER_REPORTER_NAME, cost);
|
|
129
129
|
}
|
|
130
|
-
|
|
131
|
-
|
|
130
|
+
const serverLoadResult = serverRouter._serverResult;
|
|
131
|
+
if (!serverLoadResult) {
|
|
132
132
|
try {
|
|
133
133
|
serverRouter.serverSsr?.cleanup?.();
|
|
134
134
|
} catch {}
|
|
135
|
-
|
|
135
|
+
throw new Error('TanStack Router completed an SSR load without a server result.');
|
|
136
|
+
}
|
|
137
|
+
if ('redirect' === serverLoadResult.type) {
|
|
138
|
+
const { redirect } = serverLoadResult;
|
|
139
|
+
try {
|
|
140
|
+
serverRouter.serverSsr?.cleanup?.();
|
|
141
|
+
} catch {}
|
|
142
|
+
return interrupt(isRSCNavigation ? (0, payloadRouter_js_namespaceObject.handleTanstackRscRedirect)(redirect.headers, _basename, redirect.status) : redirect);
|
|
136
143
|
}
|
|
137
144
|
const routerErrors = (0, external_ssrManagedTags_js_namespaceObject.collectRouterErrors)(tanstackRouter);
|
|
138
145
|
if (routerErrors && 'clientRender' === loaderFailureMode) {
|
|
@@ -143,7 +150,7 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
143
150
|
throw Object.values(routerErrors)[0];
|
|
144
151
|
}
|
|
145
152
|
await (0, external_ssrPreload_js_namespaceObject.preloadMatchedRouteComponents)(serverRouter);
|
|
146
|
-
context.ssrContext?.response?.status(
|
|
153
|
+
context.ssrContext?.response?.status(serverLoadResult.status);
|
|
147
154
|
await serverRouter.serverSsr?.dehydrate?.();
|
|
148
155
|
if (enableRsc) {
|
|
149
156
|
if (isRSCNavigation) await (0, external_ssrManagedTags_js_namespaceObject.waitForRouterSerialization)(serverRouter);
|
|
@@ -157,7 +164,7 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
157
164
|
const routerServerSnapshot = (0, external_lifecycle_js_namespaceObject.createRouterServerSnapshot)({
|
|
158
165
|
framework: 'tanstack',
|
|
159
166
|
basename: _basename,
|
|
160
|
-
statusCode:
|
|
167
|
+
statusCode: serverLoadResult.status,
|
|
161
168
|
errors: routerErrors,
|
|
162
169
|
matchedRouteIds,
|
|
163
170
|
hydrationScripts
|
|
@@ -58,10 +58,10 @@ function getTanstackRouteConfig(api, userConfig) {
|
|
|
58
58
|
}
|
|
59
59
|
function createTanstackRouteObjects({ hooks, routeConfig, ssrMode }) {
|
|
60
60
|
const { mergedConfig, finalRouteConfig } = routeConfig;
|
|
61
|
-
const routeObjects = mergedConfig.createRoutes ? mergedConfig.createRoutes() : (0, external_utils_js_namespaceObject.createTanstackRouteObjectsFromConfig)({
|
|
61
|
+
const routeObjects = void 0 !== mergedConfig.createRoutes ? mergedConfig.createRoutes() : (0, external_utils_js_namespaceObject.createTanstackRouteObjectsFromConfig)({
|
|
62
62
|
routesConfig: finalRouteConfig,
|
|
63
63
|
ssrMode
|
|
64
|
-
})
|
|
64
|
+
}) ?? [];
|
|
65
65
|
return hooks.modifyRoutes.call(routeObjects);
|
|
66
66
|
}
|
|
67
67
|
function joinBasename(baseUrl, basename) {
|
|
@@ -69,7 +69,7 @@ function joinBasename(baseUrl, basename) {
|
|
|
69
69
|
const normalizedBase = base.startsWith('/') ? base : `/${base}`;
|
|
70
70
|
const trimmedBase = normalizedBase.length > 1 ? normalizedBase.replace(/\/+$/g, '') : normalizedBase;
|
|
71
71
|
const trimmedBasename = basename.replace(/^\/+|\/+$/g, '');
|
|
72
|
-
if (
|
|
72
|
+
if (0 === trimmedBasename.length) return trimmedBase || '/';
|
|
73
73
|
return `${trimmedBase}/${trimmedBasename}`.replace(/\/{2,}/g, '/');
|
|
74
74
|
}
|
|
75
75
|
exports.createTanstackRouteObjects = __webpack_exports__.createTanstackRouteObjects;
|
|
@@ -34,12 +34,12 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
34
34
|
toRouteErrors: ()=>toRouteErrors,
|
|
35
35
|
toRouteLoaderData: ()=>toRouteLoaderData
|
|
36
36
|
});
|
|
37
|
-
const
|
|
37
|
+
const routerHelper_namespaceObject = require("@modern-js/runtime/routerHelper");
|
|
38
38
|
function shouldRedactServerError(status = 500) {
|
|
39
39
|
return status >= 500 && 'development' !== process.env.NODE_ENV && 'test' !== process.env.NODE_ENV;
|
|
40
40
|
}
|
|
41
41
|
function serializePayloadError(error) {
|
|
42
|
-
if ((0,
|
|
42
|
+
if ((0, routerHelper_namespaceObject.isRouteErrorResponse)(error)) {
|
|
43
43
|
if (shouldRedactServerError(error.status)) return {
|
|
44
44
|
status: error.status,
|
|
45
45
|
statusText: 'Internal Server Error',
|
|
@@ -50,7 +50,7 @@ function selectTreePath(tree, path) {
|
|
|
50
50
|
return current;
|
|
51
51
|
}
|
|
52
52
|
function renderSelectedTree(src, { getTree = src[external_symbols_js_namespaceObject.RSC_PROXY_GET_TREE], missingTreeError }) {
|
|
53
|
-
if (
|
|
53
|
+
if (void 0 === getTree) throw new Error(missingTreeError);
|
|
54
54
|
return selectTreePath(getTree(), src[external_symbols_js_namespaceObject.RSC_PROXY_PATH] || []);
|
|
55
55
|
}
|
|
56
56
|
exports.EmptyFallback = __webpack_exports__.EmptyFallback;
|
|
@@ -40,15 +40,11 @@ function loadModernRscClientRuntime() {
|
|
|
40
40
|
});
|
|
41
41
|
return modernRscClientRuntimePromise;
|
|
42
42
|
}
|
|
43
|
-
|
|
44
|
-
if ("u" < typeof window)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const runtime = await loadModernRscClientRuntime();
|
|
49
|
-
return runtime.createFromReadableStream(stream, {
|
|
50
|
-
callServer: runtime.callServer
|
|
51
|
-
});
|
|
43
|
+
function createFromFlightStream(stream) {
|
|
44
|
+
if ("u" < typeof window) return import("react-server-dom-rspack/client.edge").then((runtime)=>runtime.createFromReadableStream(stream));
|
|
45
|
+
return loadModernRscClientRuntime().then((runtime)=>runtime.createFromReadableStream(stream, {
|
|
46
|
+
callServer: runtime.callServer
|
|
47
|
+
}));
|
|
52
48
|
}
|
|
53
49
|
function createTreeGetterFromFlightStream(stream) {
|
|
54
50
|
let ready = false;
|
|
@@ -44,16 +44,15 @@ function resolveRouteHandlers(router, actionTo) {
|
|
|
44
44
|
const builtLocation = router.buildLocation({
|
|
45
45
|
to: actionTo
|
|
46
46
|
});
|
|
47
|
-
const
|
|
48
|
-
const
|
|
49
|
-
const routeStaticData = matchedRoutes.foundRoute?.options?.staticData;
|
|
47
|
+
const [, routeParams, foundRoute] = router.getMatchedRoutes(builtLocation.pathname);
|
|
48
|
+
const routeStaticData = foundRoute?.options?.staticData;
|
|
50
49
|
const action = routeStaticData?.modernRouteAction;
|
|
51
50
|
const loader = routeStaticData?.modernRouteLoader;
|
|
52
51
|
return {
|
|
53
52
|
action,
|
|
54
53
|
loader,
|
|
55
|
-
href,
|
|
56
|
-
params:
|
|
54
|
+
href: builtLocation.href,
|
|
55
|
+
params: routeParams
|
|
57
56
|
};
|
|
58
57
|
}
|
|
59
58
|
function isRedirectResponse(value) {
|
package/dist/esm/cli/index.mjs
CHANGED
|
@@ -112,6 +112,8 @@ function tanstackRouterPlugin(options = {}) {
|
|
|
112
112
|
const routesByEntry = await handleGeneratorEntryCode(api, tanstackEntrypoints, {
|
|
113
113
|
entrypointsKey: ENTRYPOINTS_KEY,
|
|
114
114
|
hydrateRscClientRoutes: true,
|
|
115
|
+
includeRouteServerLoadersInSsrEntry: false,
|
|
116
|
+
isolateRouteDataInRscLayer: true,
|
|
115
117
|
serverRoutesFileName: 'tanstack-routes.server.js'
|
|
116
118
|
});
|
|
117
119
|
await writeTanstackRouterTypesForEntries({
|
|
@@ -134,6 +136,8 @@ function tanstackRouterPlugin(options = {}) {
|
|
|
134
136
|
const routesByEntry = await handleGeneratorEntryCode(api, entrypoints, {
|
|
135
137
|
entrypointsKey: ENTRYPOINTS_KEY,
|
|
136
138
|
hydrateRscClientRoutes: true,
|
|
139
|
+
includeRouteServerLoadersInSsrEntry: false,
|
|
140
|
+
isolateRouteDataInRscLayer: true,
|
|
137
141
|
serverRoutesFileName: 'tanstack-routes.server.js'
|
|
138
142
|
});
|
|
139
143
|
await writeTanstackRouterTypesForEntries({
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import node_path from "node:path";
|
|
2
1
|
import { makeLegalIdentifier } from "@modern-js/runtime/cli";
|
|
2
|
+
import { upath } from "@modern-js/utils";
|
|
3
3
|
import { createRouteStaticDataSnippet, isIndexRoute, isPathlessLayout, normalizeRelativeImport, pickModernLoaderModule, pickRouteSearchContractModules, quote, resolveFileNoExt, toTanstackPath } from "./shared.mjs";
|
|
4
4
|
async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
5
5
|
const { appContext, entryName, generatedDirName = 'modern-tanstack', routes } = opts;
|
|
6
|
-
const outDir =
|
|
6
|
+
const outDir = upath.join(appContext.srcDirectory, generatedDirName, entryName);
|
|
7
7
|
const rootModern = routes.find((r)=>{
|
|
8
8
|
const extras = r;
|
|
9
9
|
return r && 'nested' === extras.type && extras.isRoot;
|
|
@@ -28,7 +28,7 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
28
28
|
pendingImportName = (async ()=>{
|
|
29
29
|
const resolvedNoExt = await resolveRouteModuleNoExt(componentPath);
|
|
30
30
|
if (!resolvedNoExt) return null;
|
|
31
|
-
const relImport = normalizeRelativeImport(
|
|
31
|
+
const relImport = normalizeRelativeImport(upath.relative(outDir, resolvedNoExt));
|
|
32
32
|
const componentName = `component_${componentIndex++}`;
|
|
33
33
|
imports.push(`import ${componentName} from ${quote(relImport)};`);
|
|
34
34
|
return componentName;
|
|
@@ -42,8 +42,8 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
42
42
|
let absNoExt;
|
|
43
43
|
if (aliasedNoExtPath.startsWith(prefix)) {
|
|
44
44
|
const rel = aliasedNoExtPath.slice(prefix.length);
|
|
45
|
-
absNoExt =
|
|
46
|
-
} else absNoExt =
|
|
45
|
+
absNoExt = upath.join(appContext.srcDirectory, rel);
|
|
46
|
+
} else absNoExt = upath.isAbsolute(aliasedNoExtPath) ? aliasedNoExtPath : upath.join(appContext.srcDirectory, aliasedNoExtPath);
|
|
47
47
|
return resolveFileNoExt(absNoExt);
|
|
48
48
|
};
|
|
49
49
|
const getImportNamesForLoader = async (aliasedNoExtPath, inline, hasAction)=>{
|
|
@@ -55,7 +55,7 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
55
55
|
};
|
|
56
56
|
const resolvedNoExt = await resolveRouteModuleNoExt(aliasedNoExtPath);
|
|
57
57
|
if (!resolvedNoExt) return null;
|
|
58
|
-
const relImport = normalizeRelativeImport(
|
|
58
|
+
const relImport = normalizeRelativeImport(upath.relative(outDir, resolvedNoExt));
|
|
59
59
|
const importName = `loader_${loaderIndex++}`;
|
|
60
60
|
const actionName = hasAction ? importName.replace(/^loader_/, 'action_') : null;
|
|
61
61
|
if (inline) {
|
|
@@ -77,7 +77,7 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
77
77
|
if (existing) return existing;
|
|
78
78
|
const resolvedNoExt = await resolveRouteModuleNoExt(aliasedNoExtPath);
|
|
79
79
|
if (!resolvedNoExt) return null;
|
|
80
|
-
const relImport = normalizeRelativeImport(
|
|
80
|
+
const relImport = normalizeRelativeImport(upath.relative(outDir, resolvedNoExt));
|
|
81
81
|
const importName = 'validateSearch' === exportName ? `validateSearch_${validateSearchIndex++}` : `loaderDeps_${loaderDepsIndex++}`;
|
|
82
82
|
imports.push(`import { ${exportName} as ${importName} } from ${quote(relImport)};`);
|
|
83
83
|
searchContractImportMap.set(key, importName);
|
|
@@ -94,12 +94,19 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
94
94
|
const cost = end();
|
|
95
95
|
context.ssrContext?.onTiming?.(LOADER_REPORTER_NAME, cost);
|
|
96
96
|
}
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
const serverLoadResult = serverRouter._serverResult;
|
|
98
|
+
if (!serverLoadResult) {
|
|
99
99
|
try {
|
|
100
100
|
serverRouter.serverSsr?.cleanup?.();
|
|
101
101
|
} catch {}
|
|
102
|
-
|
|
102
|
+
throw new Error('TanStack Router completed an SSR load without a server result.');
|
|
103
|
+
}
|
|
104
|
+
if ('redirect' === serverLoadResult.type) {
|
|
105
|
+
const { redirect } = serverLoadResult;
|
|
106
|
+
try {
|
|
107
|
+
serverRouter.serverSsr?.cleanup?.();
|
|
108
|
+
} catch {}
|
|
109
|
+
return interrupt(isRSCNavigation ? handleTanstackRscRedirect(redirect.headers, _basename, redirect.status) : redirect);
|
|
103
110
|
}
|
|
104
111
|
const routerErrors = collectRouterErrors(tanstackRouter);
|
|
105
112
|
if (routerErrors && 'clientRender' === loaderFailureMode) {
|
|
@@ -110,7 +117,7 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
110
117
|
throw Object.values(routerErrors)[0];
|
|
111
118
|
}
|
|
112
119
|
await preloadMatchedRouteComponents(serverRouter);
|
|
113
|
-
context.ssrContext?.response?.status(
|
|
120
|
+
context.ssrContext?.response?.status(serverLoadResult.status);
|
|
114
121
|
await serverRouter.serverSsr?.dehydrate?.();
|
|
115
122
|
if (enableRsc) {
|
|
116
123
|
if (isRSCNavigation) await waitForRouterSerialization(serverRouter);
|
|
@@ -124,7 +131,7 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
124
131
|
const routerServerSnapshot = createRouterServerSnapshot({
|
|
125
132
|
framework: 'tanstack',
|
|
126
133
|
basename: _basename,
|
|
127
|
-
statusCode:
|
|
134
|
+
statusCode: serverLoadResult.status,
|
|
128
135
|
errors: routerErrors,
|
|
129
136
|
matchedRouteIds,
|
|
130
137
|
hydrationScripts
|
|
@@ -23,10 +23,10 @@ function getTanstackRouteConfig(api, userConfig) {
|
|
|
23
23
|
}
|
|
24
24
|
function createTanstackRouteObjects({ hooks, routeConfig, ssrMode }) {
|
|
25
25
|
const { mergedConfig, finalRouteConfig } = routeConfig;
|
|
26
|
-
const routeObjects = mergedConfig.createRoutes ? mergedConfig.createRoutes() : createTanstackRouteObjectsFromConfig({
|
|
26
|
+
const routeObjects = void 0 !== mergedConfig.createRoutes ? mergedConfig.createRoutes() : createTanstackRouteObjectsFromConfig({
|
|
27
27
|
routesConfig: finalRouteConfig,
|
|
28
28
|
ssrMode
|
|
29
|
-
})
|
|
29
|
+
}) ?? [];
|
|
30
30
|
return hooks.modifyRoutes.call(routeObjects);
|
|
31
31
|
}
|
|
32
32
|
function joinBasename(baseUrl, basename) {
|
|
@@ -34,7 +34,7 @@ function joinBasename(baseUrl, basename) {
|
|
|
34
34
|
const normalizedBase = base.startsWith('/') ? base : `/${base}`;
|
|
35
35
|
const trimmedBase = normalizedBase.length > 1 ? normalizedBase.replace(/\/+$/g, '') : normalizedBase;
|
|
36
36
|
const trimmedBasename = basename.replace(/^\/+|\/+$/g, '');
|
|
37
|
-
if (
|
|
37
|
+
if (0 === trimmedBasename.length) return trimmedBase || '/';
|
|
38
38
|
return `${trimmedBase}/${trimmedBasename}`.replace(/\/{2,}/g, '/');
|
|
39
39
|
}
|
|
40
40
|
export { createTanstackRouteObjects, getMergedRouterConfig, getTanstackRouteConfig, joinBasename };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isRouteErrorResponse } from "@modern-js/runtime
|
|
1
|
+
import { isRouteErrorResponse } from "@modern-js/runtime/routerHelper";
|
|
2
2
|
function shouldRedactServerError(status = 500) {
|
|
3
3
|
return status >= 500 && 'development' !== process.env.NODE_ENV && 'test' !== process.env.NODE_ENV;
|
|
4
4
|
}
|
|
@@ -15,7 +15,7 @@ function selectTreePath(tree, path) {
|
|
|
15
15
|
return current;
|
|
16
16
|
}
|
|
17
17
|
function renderSelectedTree(src, { getTree = src[RSC_PROXY_GET_TREE], missingTreeError }) {
|
|
18
|
-
if (
|
|
18
|
+
if (void 0 === getTree) throw new Error(missingTreeError);
|
|
19
19
|
return selectTreePath(getTree(), src[RSC_PROXY_PATH] || []);
|
|
20
20
|
}
|
|
21
21
|
export { EmptyFallback, TANSTACK_RSC_FLIGHT_VALUE, isSerializedTanstackRscFlightValue, renderSelectedTree };
|
|
@@ -8,15 +8,11 @@ function loadModernRscClientRuntime() {
|
|
|
8
8
|
});
|
|
9
9
|
return modernRscClientRuntimePromise;
|
|
10
10
|
}
|
|
11
|
-
|
|
12
|
-
if ("u" < typeof window)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const runtime = await loadModernRscClientRuntime();
|
|
17
|
-
return runtime.createFromReadableStream(stream, {
|
|
18
|
-
callServer: runtime.callServer
|
|
19
|
-
});
|
|
11
|
+
function createFromFlightStream(stream) {
|
|
12
|
+
if ("u" < typeof window) return import("react-server-dom-rspack/client.edge").then((runtime)=>runtime.createFromReadableStream(stream));
|
|
13
|
+
return loadModernRscClientRuntime().then((runtime)=>runtime.createFromReadableStream(stream, {
|
|
14
|
+
callServer: runtime.callServer
|
|
15
|
+
}));
|
|
20
16
|
}
|
|
21
17
|
function createTreeGetterFromFlightStream(stream) {
|
|
22
18
|
let ready = false;
|
|
@@ -11,16 +11,15 @@ function resolveRouteHandlers(router, actionTo) {
|
|
|
11
11
|
const builtLocation = router.buildLocation({
|
|
12
12
|
to: actionTo
|
|
13
13
|
});
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const routeStaticData = matchedRoutes.foundRoute?.options?.staticData;
|
|
14
|
+
const [, routeParams, foundRoute] = router.getMatchedRoutes(builtLocation.pathname);
|
|
15
|
+
const routeStaticData = foundRoute?.options?.staticData;
|
|
17
16
|
const action = routeStaticData?.modernRouteAction;
|
|
18
17
|
const loader = routeStaticData?.modernRouteLoader;
|
|
19
18
|
return {
|
|
20
19
|
action,
|
|
21
20
|
loader,
|
|
22
|
-
href,
|
|
23
|
-
params:
|
|
21
|
+
href: builtLocation.href,
|
|
22
|
+
params: routeParams
|
|
24
23
|
};
|
|
25
24
|
}
|
|
26
25
|
function isRedirectResponse(value) {
|
|
@@ -116,6 +116,8 @@ function tanstackRouterPlugin(options = {}) {
|
|
|
116
116
|
const routesByEntry = await handleGeneratorEntryCode(api, tanstackEntrypoints, {
|
|
117
117
|
entrypointsKey: ENTRYPOINTS_KEY,
|
|
118
118
|
hydrateRscClientRoutes: true,
|
|
119
|
+
includeRouteServerLoadersInSsrEntry: false,
|
|
120
|
+
isolateRouteDataInRscLayer: true,
|
|
119
121
|
serverRoutesFileName: 'tanstack-routes.server.js'
|
|
120
122
|
});
|
|
121
123
|
await writeTanstackRouterTypesForEntries({
|
|
@@ -138,6 +140,8 @@ function tanstackRouterPlugin(options = {}) {
|
|
|
138
140
|
const routesByEntry = await handleGeneratorEntryCode(api, entrypoints, {
|
|
139
141
|
entrypointsKey: ENTRYPOINTS_KEY,
|
|
140
142
|
hydrateRscClientRoutes: true,
|
|
143
|
+
includeRouteServerLoadersInSsrEntry: false,
|
|
144
|
+
isolateRouteDataInRscLayer: true,
|
|
141
145
|
serverRoutesFileName: 'tanstack-routes.server.js'
|
|
142
146
|
});
|
|
143
147
|
await writeTanstackRouterTypesForEntries({
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import "node:module";
|
|
2
|
-
import node_path from "node:path";
|
|
3
2
|
import { makeLegalIdentifier } from "@modern-js/runtime/cli";
|
|
3
|
+
import { upath } from "@modern-js/utils";
|
|
4
4
|
import { createRouteStaticDataSnippet, isIndexRoute, isPathlessLayout, normalizeRelativeImport, pickModernLoaderModule, pickRouteSearchContractModules, quote, resolveFileNoExt, toTanstackPath } from "./shared.mjs";
|
|
5
5
|
async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
6
6
|
const { appContext, entryName, generatedDirName = 'modern-tanstack', routes } = opts;
|
|
7
|
-
const outDir =
|
|
7
|
+
const outDir = upath.join(appContext.srcDirectory, generatedDirName, entryName);
|
|
8
8
|
const rootModern = routes.find((r)=>{
|
|
9
9
|
const extras = r;
|
|
10
10
|
return r && 'nested' === extras.type && extras.isRoot;
|
|
@@ -29,7 +29,7 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
29
29
|
pendingImportName = (async ()=>{
|
|
30
30
|
const resolvedNoExt = await resolveRouteModuleNoExt(componentPath);
|
|
31
31
|
if (!resolvedNoExt) return null;
|
|
32
|
-
const relImport = normalizeRelativeImport(
|
|
32
|
+
const relImport = normalizeRelativeImport(upath.relative(outDir, resolvedNoExt));
|
|
33
33
|
const componentName = `component_${componentIndex++}`;
|
|
34
34
|
imports.push(`import ${componentName} from ${quote(relImport)};`);
|
|
35
35
|
return componentName;
|
|
@@ -43,8 +43,8 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
43
43
|
let absNoExt;
|
|
44
44
|
if (aliasedNoExtPath.startsWith(prefix)) {
|
|
45
45
|
const rel = aliasedNoExtPath.slice(prefix.length);
|
|
46
|
-
absNoExt =
|
|
47
|
-
} else absNoExt =
|
|
46
|
+
absNoExt = upath.join(appContext.srcDirectory, rel);
|
|
47
|
+
} else absNoExt = upath.isAbsolute(aliasedNoExtPath) ? aliasedNoExtPath : upath.join(appContext.srcDirectory, aliasedNoExtPath);
|
|
48
48
|
return resolveFileNoExt(absNoExt);
|
|
49
49
|
};
|
|
50
50
|
const getImportNamesForLoader = async (aliasedNoExtPath, inline, hasAction)=>{
|
|
@@ -56,7 +56,7 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
56
56
|
};
|
|
57
57
|
const resolvedNoExt = await resolveRouteModuleNoExt(aliasedNoExtPath);
|
|
58
58
|
if (!resolvedNoExt) return null;
|
|
59
|
-
const relImport = normalizeRelativeImport(
|
|
59
|
+
const relImport = normalizeRelativeImport(upath.relative(outDir, resolvedNoExt));
|
|
60
60
|
const importName = `loader_${loaderIndex++}`;
|
|
61
61
|
const actionName = hasAction ? importName.replace(/^loader_/, 'action_') : null;
|
|
62
62
|
if (inline) {
|
|
@@ -78,7 +78,7 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
78
78
|
if (existing) return existing;
|
|
79
79
|
const resolvedNoExt = await resolveRouteModuleNoExt(aliasedNoExtPath);
|
|
80
80
|
if (!resolvedNoExt) return null;
|
|
81
|
-
const relImport = normalizeRelativeImport(
|
|
81
|
+
const relImport = normalizeRelativeImport(upath.relative(outDir, resolvedNoExt));
|
|
82
82
|
const importName = 'validateSearch' === exportName ? `validateSearch_${validateSearchIndex++}` : `loaderDeps_${loaderDepsIndex++}`;
|
|
83
83
|
imports.push(`import { ${exportName} as ${importName} } from ${quote(relImport)};`);
|
|
84
84
|
searchContractImportMap.set(key, importName);
|
|
@@ -95,12 +95,19 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
95
95
|
const cost = end();
|
|
96
96
|
context.ssrContext?.onTiming?.(LOADER_REPORTER_NAME, cost);
|
|
97
97
|
}
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
const serverLoadResult = serverRouter._serverResult;
|
|
99
|
+
if (!serverLoadResult) {
|
|
100
100
|
try {
|
|
101
101
|
serverRouter.serverSsr?.cleanup?.();
|
|
102
102
|
} catch {}
|
|
103
|
-
|
|
103
|
+
throw new Error('TanStack Router completed an SSR load without a server result.');
|
|
104
|
+
}
|
|
105
|
+
if ('redirect' === serverLoadResult.type) {
|
|
106
|
+
const { redirect } = serverLoadResult;
|
|
107
|
+
try {
|
|
108
|
+
serverRouter.serverSsr?.cleanup?.();
|
|
109
|
+
} catch {}
|
|
110
|
+
return interrupt(isRSCNavigation ? handleTanstackRscRedirect(redirect.headers, _basename, redirect.status) : redirect);
|
|
104
111
|
}
|
|
105
112
|
const routerErrors = collectRouterErrors(tanstackRouter);
|
|
106
113
|
if (routerErrors && 'clientRender' === loaderFailureMode) {
|
|
@@ -111,7 +118,7 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
111
118
|
throw Object.values(routerErrors)[0];
|
|
112
119
|
}
|
|
113
120
|
await preloadMatchedRouteComponents(serverRouter);
|
|
114
|
-
context.ssrContext?.response?.status(
|
|
121
|
+
context.ssrContext?.response?.status(serverLoadResult.status);
|
|
115
122
|
await serverRouter.serverSsr?.dehydrate?.();
|
|
116
123
|
if (enableRsc) {
|
|
117
124
|
if (isRSCNavigation) await waitForRouterSerialization(serverRouter);
|
|
@@ -125,7 +132,7 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
125
132
|
const routerServerSnapshot = createRouterServerSnapshot({
|
|
126
133
|
framework: 'tanstack',
|
|
127
134
|
basename: _basename,
|
|
128
|
-
statusCode:
|
|
135
|
+
statusCode: serverLoadResult.status,
|
|
129
136
|
errors: routerErrors,
|
|
130
137
|
matchedRouteIds,
|
|
131
138
|
hydrationScripts
|
|
@@ -24,10 +24,10 @@ function getTanstackRouteConfig(api, userConfig) {
|
|
|
24
24
|
}
|
|
25
25
|
function createTanstackRouteObjects({ hooks, routeConfig, ssrMode }) {
|
|
26
26
|
const { mergedConfig, finalRouteConfig } = routeConfig;
|
|
27
|
-
const routeObjects = mergedConfig.createRoutes ? mergedConfig.createRoutes() : createTanstackRouteObjectsFromConfig({
|
|
27
|
+
const routeObjects = void 0 !== mergedConfig.createRoutes ? mergedConfig.createRoutes() : createTanstackRouteObjectsFromConfig({
|
|
28
28
|
routesConfig: finalRouteConfig,
|
|
29
29
|
ssrMode
|
|
30
|
-
})
|
|
30
|
+
}) ?? [];
|
|
31
31
|
return hooks.modifyRoutes.call(routeObjects);
|
|
32
32
|
}
|
|
33
33
|
function joinBasename(baseUrl, basename) {
|
|
@@ -35,7 +35,7 @@ function joinBasename(baseUrl, basename) {
|
|
|
35
35
|
const normalizedBase = base.startsWith('/') ? base : `/${base}`;
|
|
36
36
|
const trimmedBase = normalizedBase.length > 1 ? normalizedBase.replace(/\/+$/g, '') : normalizedBase;
|
|
37
37
|
const trimmedBasename = basename.replace(/^\/+|\/+$/g, '');
|
|
38
|
-
if (
|
|
38
|
+
if (0 === trimmedBasename.length) return trimmedBase || '/';
|
|
39
39
|
return `${trimmedBase}/${trimmedBasename}`.replace(/\/{2,}/g, '/');
|
|
40
40
|
}
|
|
41
41
|
export { createTanstackRouteObjects, getMergedRouterConfig, getTanstackRouteConfig, joinBasename };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "node:module";
|
|
2
|
-
import { isRouteErrorResponse } from "@modern-js/runtime
|
|
2
|
+
import { isRouteErrorResponse } from "@modern-js/runtime/routerHelper";
|
|
3
3
|
function shouldRedactServerError(status = 500) {
|
|
4
4
|
return status >= 500 && 'development' !== process.env.NODE_ENV && 'test' !== process.env.NODE_ENV;
|
|
5
5
|
}
|
|
@@ -16,7 +16,7 @@ function selectTreePath(tree, path) {
|
|
|
16
16
|
return current;
|
|
17
17
|
}
|
|
18
18
|
function renderSelectedTree(src, { getTree = src[RSC_PROXY_GET_TREE], missingTreeError }) {
|
|
19
|
-
if (
|
|
19
|
+
if (void 0 === getTree) throw new Error(missingTreeError);
|
|
20
20
|
return selectTreePath(getTree(), src[RSC_PROXY_PATH] || []);
|
|
21
21
|
}
|
|
22
22
|
export { EmptyFallback, TANSTACK_RSC_FLIGHT_VALUE, isSerializedTanstackRscFlightValue, renderSelectedTree };
|
|
@@ -9,15 +9,11 @@ function loadModernRscClientRuntime() {
|
|
|
9
9
|
});
|
|
10
10
|
return modernRscClientRuntimePromise;
|
|
11
11
|
}
|
|
12
|
-
|
|
13
|
-
if ("u" < typeof window)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const runtime = await loadModernRscClientRuntime();
|
|
18
|
-
return runtime.createFromReadableStream(stream, {
|
|
19
|
-
callServer: runtime.callServer
|
|
20
|
-
});
|
|
12
|
+
function createFromFlightStream(stream) {
|
|
13
|
+
if ("u" < typeof window) return import("react-server-dom-rspack/client.edge").then((runtime)=>runtime.createFromReadableStream(stream));
|
|
14
|
+
return loadModernRscClientRuntime().then((runtime)=>runtime.createFromReadableStream(stream, {
|
|
15
|
+
callServer: runtime.callServer
|
|
16
|
+
}));
|
|
21
17
|
}
|
|
22
18
|
function createTreeGetterFromFlightStream(stream) {
|
|
23
19
|
let ready = false;
|
|
@@ -12,16 +12,15 @@ function resolveRouteHandlers(router, actionTo) {
|
|
|
12
12
|
const builtLocation = router.buildLocation({
|
|
13
13
|
to: actionTo
|
|
14
14
|
});
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const routeStaticData = matchedRoutes.foundRoute?.options?.staticData;
|
|
15
|
+
const [, routeParams, foundRoute] = router.getMatchedRoutes(builtLocation.pathname);
|
|
16
|
+
const routeStaticData = foundRoute?.options?.staticData;
|
|
18
17
|
const action = routeStaticData?.modernRouteAction;
|
|
19
18
|
const loader = routeStaticData?.modernRouteLoader;
|
|
20
19
|
return {
|
|
21
20
|
action,
|
|
22
21
|
loader,
|
|
23
|
-
href,
|
|
24
|
-
params:
|
|
22
|
+
href: builtLocation.href,
|
|
23
|
+
params: routeParams
|
|
25
24
|
};
|
|
26
25
|
}
|
|
27
26
|
function isRedirectResponse(value) {
|
|
@@ -2,7 +2,7 @@ import { type AnyRouter } from '@tanstack/react-router';
|
|
|
2
2
|
export type WindowWithTanstackSsr = Window & {
|
|
3
3
|
$_TSR?: unknown;
|
|
4
4
|
};
|
|
5
|
-
export declare function hydrateTanstackRouter(router: AnyRouter): Promise<
|
|
5
|
+
export declare function hydrateTanstackRouter(router: AnyRouter): Promise<void>;
|
|
6
6
|
export declare function getTanstackSsrHydrationPromise(router: AnyRouter): Promise<unknown>;
|
|
7
7
|
export declare function hasTanstackSsrHydrationRecord(router: AnyRouter): boolean;
|
|
8
8
|
export declare function ModernRouterClient({ router }: {
|