@bleedingdev/modern-js-plugin-tanstack 3.5.0-ultramodern.30 → 3.5.0-ultramodern.31
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/artifacts.js +157 -0
- package/dist/cjs/cli/index.js +6 -103
- package/dist/cjs/cli/tanstackTypes/canonicalRoutes.js +113 -0
- package/dist/cjs/cli/tanstackTypes/shared.js +130 -0
- package/dist/cjs/cli/tanstackTypes/source.js +251 -0
- package/dist/cjs/cli/tanstackTypes.js +4 -350
- package/dist/cjs/runtime/blockingSubscribe.js +64 -0
- package/dist/cjs/runtime/{pluginCore.js → clientBasepath.js} +12 -19
- package/dist/cjs/runtime/clientHydration.js +129 -0
- package/dist/cjs/runtime/dataMutation.js +11 -176
- package/dist/cjs/runtime/formData.js +116 -0
- package/dist/cjs/runtime/loaderBridge.js +4 -1
- package/dist/cjs/runtime/plugin.js +21 -125
- package/dist/cjs/runtime/plugin.node.js +38 -119
- package/dist/cjs/runtime/pluginShared.js +90 -0
- package/dist/cjs/runtime/routeTree/components.js +102 -0
- package/dist/cjs/runtime/routeTree/construction.js +152 -0
- package/dist/cjs/runtime/routeTree/index.js +47 -0
- package/dist/cjs/runtime/routeTree/loaders.js +158 -0
- package/dist/cjs/runtime/routeTree/paths.js +57 -0
- package/dist/cjs/runtime/routeTree/staticData.js +63 -0
- package/dist/cjs/runtime/routeTree/tanstackRoutes.js +57 -0
- package/dist/cjs/runtime/routeTree/types.js +18 -0
- package/dist/cjs/runtime/routeTree.js +7 -320
- package/dist/cjs/runtime/rsc/CompositeComponent.js +18 -13
- package/dist/cjs/runtime/rsc/RscNodeRenderer.js +5 -16
- package/dist/cjs/runtime/rsc/client.js +8 -25
- package/dist/cjs/runtime/rsc/flightSerialization.js +132 -0
- package/dist/cjs/runtime/rsc/payloadErrors.js +99 -0
- package/dist/cjs/runtime/rsc/payloadFetch.js +117 -0
- package/dist/cjs/runtime/rsc/payloadRouter.js +21 -142
- package/dist/cjs/runtime/rsc/payloadRoutes.js +106 -0
- package/dist/cjs/runtime/rsc/payloadStorage.js +58 -0
- package/dist/cjs/runtime/rsc/server.js +14 -18
- package/dist/cjs/runtime/rsc/shared.js +71 -0
- package/dist/cjs/runtime/rsc/treeGetter.js +72 -0
- package/dist/cjs/runtime/ssrManagedTags.js +103 -0
- package/dist/cjs/runtime/ssrPreload.js +89 -0
- package/dist/cjs/runtime/ssrTypes.js +18 -0
- package/dist/cjs/runtime/submitAction.js +161 -0
- package/dist/cjs/runtime/utils.js +49 -86
- package/dist/esm/cli/artifacts.mjs +103 -0
- package/dist/esm/cli/index.mjs +4 -101
- package/dist/esm/cli/tanstackTypes/canonicalRoutes.mjs +75 -0
- package/dist/esm/cli/tanstackTypes/shared.mjs +68 -0
- package/dist/esm/cli/tanstackTypes/source.mjs +203 -0
- package/dist/esm/cli/tanstackTypes.mjs +2 -339
- package/dist/esm/runtime/blockingSubscribe.mjs +19 -0
- package/dist/esm/runtime/clientBasepath.mjs +10 -0
- package/dist/esm/runtime/clientHydration.mjs +70 -0
- package/dist/esm/runtime/dataMutation.mjs +2 -167
- package/dist/esm/runtime/formData.mjs +63 -0
- package/dist/esm/runtime/loaderBridge.mjs +4 -1
- package/dist/esm/runtime/plugin.mjs +14 -118
- package/dist/esm/runtime/plugin.node.mjs +33 -114
- package/dist/esm/runtime/pluginShared.mjs +40 -0
- package/dist/esm/runtime/routeTree/components.mjs +55 -0
- package/dist/esm/runtime/routeTree/construction.mjs +111 -0
- package/dist/esm/runtime/routeTree/index.mjs +2 -0
- package/dist/esm/runtime/routeTree/loaders.mjs +117 -0
- package/dist/esm/runtime/routeTree/paths.mjs +16 -0
- package/dist/esm/runtime/routeTree/staticData.mjs +22 -0
- package/dist/esm/runtime/routeTree/tanstackRoutes.mjs +13 -0
- package/dist/esm/runtime/routeTree/types.mjs +0 -0
- package/dist/esm/runtime/routeTree.mjs +1 -318
- package/dist/esm/runtime/rsc/CompositeComponent.mjs +18 -13
- package/dist/esm/runtime/rsc/RscNodeRenderer.mjs +4 -15
- package/dist/esm/runtime/rsc/client.mjs +6 -26
- package/dist/esm/runtime/rsc/flightSerialization.mjs +88 -0
- package/dist/esm/runtime/rsc/payloadErrors.mjs +49 -0
- package/dist/esm/runtime/rsc/payloadFetch.mjs +61 -0
- package/dist/esm/runtime/rsc/payloadRouter.mjs +12 -133
- package/dist/esm/runtime/rsc/payloadRoutes.mjs +50 -0
- package/dist/esm/runtime/rsc/payloadStorage.mjs +14 -0
- package/dist/esm/runtime/rsc/server.mjs +17 -21
- package/dist/esm/runtime/rsc/shared.mjs +21 -0
- package/dist/esm/runtime/rsc/treeGetter.mjs +34 -0
- package/dist/esm/runtime/ssrManagedTags.mjs +53 -0
- package/dist/esm/runtime/ssrPreload.mjs +51 -0
- package/dist/esm/runtime/ssrTypes.mjs +0 -0
- package/dist/esm/runtime/submitAction.mjs +120 -0
- package/dist/esm/runtime/utils.mjs +47 -75
- package/dist/esm-node/cli/artifacts.mjs +104 -0
- package/dist/esm-node/cli/index.mjs +4 -101
- package/dist/esm-node/cli/tanstackTypes/canonicalRoutes.mjs +76 -0
- package/dist/esm-node/cli/tanstackTypes/shared.mjs +69 -0
- package/dist/esm-node/cli/tanstackTypes/source.mjs +204 -0
- package/dist/esm-node/cli/tanstackTypes.mjs +2 -339
- package/dist/esm-node/runtime/blockingSubscribe.mjs +20 -0
- package/dist/esm-node/runtime/clientBasepath.mjs +11 -0
- package/dist/esm-node/runtime/clientHydration.mjs +71 -0
- package/dist/esm-node/runtime/dataMutation.mjs +2 -167
- package/dist/esm-node/runtime/formData.mjs +64 -0
- package/dist/esm-node/runtime/loaderBridge.mjs +4 -1
- package/dist/esm-node/runtime/plugin.mjs +14 -118
- package/dist/esm-node/runtime/plugin.node.mjs +33 -114
- package/dist/esm-node/runtime/pluginShared.mjs +41 -0
- package/dist/esm-node/runtime/routeTree/components.mjs +56 -0
- package/dist/esm-node/runtime/routeTree/construction.mjs +112 -0
- package/dist/esm-node/runtime/routeTree/index.mjs +3 -0
- package/dist/esm-node/runtime/routeTree/loaders.mjs +118 -0
- package/dist/esm-node/runtime/routeTree/paths.mjs +17 -0
- package/dist/esm-node/runtime/routeTree/staticData.mjs +23 -0
- package/dist/esm-node/runtime/routeTree/tanstackRoutes.mjs +14 -0
- package/dist/esm-node/runtime/routeTree/types.mjs +1 -0
- package/dist/esm-node/runtime/routeTree.mjs +1 -318
- package/dist/esm-node/runtime/rsc/CompositeComponent.mjs +18 -13
- package/dist/esm-node/runtime/rsc/RscNodeRenderer.mjs +4 -15
- package/dist/esm-node/runtime/rsc/client.mjs +6 -26
- package/dist/esm-node/runtime/rsc/flightSerialization.mjs +89 -0
- package/dist/esm-node/runtime/rsc/payloadErrors.mjs +50 -0
- package/dist/esm-node/runtime/rsc/payloadFetch.mjs +62 -0
- package/dist/esm-node/runtime/rsc/payloadRouter.mjs +12 -133
- package/dist/esm-node/runtime/rsc/payloadRoutes.mjs +51 -0
- package/dist/esm-node/runtime/rsc/payloadStorage.mjs +15 -0
- package/dist/esm-node/runtime/rsc/server.mjs +17 -21
- package/dist/esm-node/runtime/rsc/shared.mjs +22 -0
- package/dist/esm-node/runtime/rsc/treeGetter.mjs +35 -0
- package/dist/esm-node/runtime/ssrManagedTags.mjs +54 -0
- package/dist/esm-node/runtime/ssrPreload.mjs +52 -0
- package/dist/esm-node/runtime/ssrTypes.mjs +1 -0
- package/dist/esm-node/runtime/submitAction.mjs +121 -0
- package/dist/esm-node/runtime/utils.mjs +47 -75
- package/dist/types/cli/artifacts.d.ts +33 -0
- package/dist/types/cli/index.d.ts +2 -33
- package/dist/types/cli/tanstackTypes/canonicalRoutes.d.ts +22 -0
- package/dist/types/cli/tanstackTypes/shared.d.ts +20 -0
- package/dist/types/cli/tanstackTypes/source.d.ts +10 -0
- package/dist/types/cli/tanstackTypes.d.ts +3 -31
- package/dist/types/runtime/blockingSubscribe.d.ts +3 -0
- package/dist/types/runtime/clientBasepath.d.ts +1 -0
- package/dist/types/runtime/clientHydration.d.ts +19 -0
- package/dist/types/runtime/dataMutation.d.ts +3 -12
- package/dist/types/runtime/formData.d.ts +23 -0
- package/dist/types/runtime/plugin.d.ts +1 -1
- package/dist/types/runtime/plugin.node.d.ts +1 -1
- package/dist/types/runtime/{pluginCore.d.ts → pluginShared.d.ts} +14 -0
- package/dist/types/runtime/routeTree/components.d.ts +7 -0
- package/dist/types/runtime/routeTree/construction.d.ts +5 -0
- package/dist/types/runtime/routeTree/index.d.ts +2 -0
- package/dist/types/runtime/routeTree/loaders.d.ts +4 -0
- package/dist/types/runtime/routeTree/paths.d.ts +3 -0
- package/dist/types/runtime/routeTree/staticData.d.ts +19 -0
- package/dist/types/runtime/routeTree/tanstackRoutes.d.ts +4 -0
- package/dist/types/runtime/routeTree/types.d.ts +75 -0
- package/dist/types/runtime/routeTree.d.ts +1 -9
- package/dist/types/runtime/rsc/CompositeComponent.d.ts +1 -2
- package/dist/types/runtime/rsc/RscNodeRenderer.d.ts +2 -3
- package/dist/types/runtime/rsc/client.d.ts +2 -0
- package/dist/types/runtime/rsc/flightSerialization.d.ts +3 -0
- package/dist/types/runtime/rsc/payloadErrors.d.ts +6 -0
- package/dist/types/runtime/rsc/payloadFetch.d.ts +10 -0
- package/dist/types/runtime/rsc/payloadRouter.d.ts +2 -10
- package/dist/types/runtime/rsc/payloadRoutes.d.ts +43 -0
- package/dist/types/runtime/rsc/payloadStorage.d.ts +5 -0
- package/dist/types/runtime/rsc/shared.d.ts +19 -0
- package/dist/types/runtime/rsc/treeGetter.d.ts +1 -0
- package/dist/types/runtime/ssrManagedTags.d.ts +7 -0
- package/dist/types/runtime/ssrPreload.d.ts +2 -0
- package/dist/types/runtime/ssrTypes.d.ts +43 -0
- package/dist/types/runtime/state.d.ts +1 -1
- package/dist/types/runtime/submitAction.d.ts +14 -0
- package/dist/types/runtime/types.d.ts +3 -46
- package/dist/types/runtime/utils.d.ts +1 -22
- package/package.json +30 -9
- package/rstest.config.mts +1 -0
- package/src/cli/artifacts.ts +255 -0
- package/src/cli/index.ts +6 -246
- package/src/cli/tanstackTypes/canonicalRoutes.ts +157 -0
- package/src/cli/tanstackTypes/shared.ts +119 -0
- package/src/cli/tanstackTypes/source.ts +405 -0
- package/src/cli/tanstackTypes.ts +4 -647
- package/src/runtime/blockingSubscribe.ts +48 -0
- package/src/runtime/clientBasepath.ts +12 -0
- package/src/runtime/clientHydration.ts +151 -0
- package/src/runtime/dataMutation.tsx +9 -306
- package/src/runtime/formData.ts +153 -0
- package/src/runtime/loaderBridge.ts +8 -3
- package/src/runtime/plugin.node.tsx +60 -284
- package/src/runtime/plugin.tsx +21 -257
- package/src/runtime/pluginShared.ts +112 -0
- package/src/runtime/routeTree/components.ts +130 -0
- package/src/runtime/routeTree/construction.ts +238 -0
- package/src/runtime/routeTree/index.ts +7 -0
- package/src/runtime/routeTree/loaders.ts +232 -0
- package/src/runtime/routeTree/paths.ts +36 -0
- package/src/runtime/routeTree/staticData.ts +66 -0
- package/src/runtime/routeTree/tanstackRoutes.ts +36 -0
- package/src/runtime/routeTree/types.ts +87 -0
- package/src/runtime/routeTree.ts +5 -750
- package/src/runtime/rsc/CompositeComponent.tsx +29 -20
- package/src/runtime/rsc/RscNodeRenderer.tsx +9 -27
- package/src/runtime/rsc/client.tsx +12 -40
- package/src/runtime/rsc/flightSerialization.ts +158 -0
- package/src/runtime/rsc/payloadErrors.ts +73 -0
- package/src/runtime/rsc/payloadFetch.ts +97 -0
- package/src/runtime/rsc/payloadRouter.ts +29 -234
- package/src/runtime/rsc/payloadRoutes.ts +122 -0
- package/src/runtime/rsc/payloadStorage.ts +35 -0
- package/src/runtime/rsc/server.tsx +20 -29
- package/src/runtime/rsc/shared.ts +70 -0
- package/src/runtime/rsc/treeGetter.tsx +52 -0
- package/src/runtime/ssrManagedTags.ts +107 -0
- package/src/runtime/ssrPreload.ts +125 -0
- package/src/runtime/ssrTypes.ts +51 -0
- package/src/runtime/state.ts +4 -2
- package/src/runtime/submitAction.ts +194 -0
- package/src/runtime/types.ts +14 -51
- package/src/runtime/utils.tsx +72 -108
- package/src/types/react-server-dom-rspack.d.ts +56 -0
- package/tests/castRatchet.test.ts +85 -0
- package/tests/router/dataMutation.test.tsx +59 -0
- package/tests/router/fixtures/router-gen.golden.txt +72 -0
- package/tests/router/loaderBridge.test.ts +21 -0
- package/tests/router/routeTree.test.ts +46 -11
- package/tests/router/rsc.test.tsx +189 -0
- package/tests/router/ssrPreload.test.ts +30 -0
- package/tests/router/tanstackTypes.test.ts +254 -1
- package/dist/esm/runtime/pluginCore.mjs +0 -14
- package/dist/esm-node/runtime/pluginCore.mjs +0 -15
- package/src/runtime/pluginCore.ts +0 -56
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// @effect-diagnostics asyncFunction:off newPromise:off strictBooleanExpressions:off
|
|
2
|
+
/// <reference path="./ssr-shim.d.ts" />
|
|
3
|
+
|
|
4
|
+
import type { AnyRouter } from '@tanstack/react-router';
|
|
5
|
+
import type {
|
|
6
|
+
RouterManagedTag,
|
|
7
|
+
RouterMatchWithError,
|
|
8
|
+
TanstackRouterWithServerSsr,
|
|
9
|
+
} from './ssrTypes';
|
|
10
|
+
|
|
11
|
+
export async function waitForRouterSerialization(
|
|
12
|
+
tanstackRouter: TanstackRouterWithServerSsr,
|
|
13
|
+
) {
|
|
14
|
+
const serverSsr = tanstackRouter.serverSsr;
|
|
15
|
+
if (
|
|
16
|
+
!serverSsr ||
|
|
17
|
+
typeof serverSsr.onSerializationFinished !== 'function' ||
|
|
18
|
+
serverSsr.isSerializationFinished?.()
|
|
19
|
+
) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
await new Promise<void>(resolve => {
|
|
24
|
+
serverSsr.onSerializationFinished?.(resolve);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function htmlEscapeAttr(value: string) {
|
|
29
|
+
return value.replace(/&/g, '&').replace(/"/g, '"');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function routerManagedTagToHtml(tag: unknown): string {
|
|
33
|
+
if (!tag || typeof tag !== 'object') {
|
|
34
|
+
return '';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const managedTag = tag as RouterManagedTag;
|
|
38
|
+
if (!managedTag || managedTag.tag !== 'script') {
|
|
39
|
+
return '';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const attrs: Record<string, unknown> = managedTag.attrs || {};
|
|
43
|
+
const attrsStr = Object.entries(attrs)
|
|
44
|
+
.filter(([, v]) => v != null && v !== false)
|
|
45
|
+
.map(([k, v]) => {
|
|
46
|
+
const name = k === 'className' ? 'class' : k;
|
|
47
|
+
if (v === true) {
|
|
48
|
+
return name;
|
|
49
|
+
}
|
|
50
|
+
return `${name}="${htmlEscapeAttr(String(v))}"`;
|
|
51
|
+
})
|
|
52
|
+
.join(' ');
|
|
53
|
+
|
|
54
|
+
const open = attrsStr.length ? `<script ${attrsStr}>` : '<script>';
|
|
55
|
+
const children =
|
|
56
|
+
typeof managedTag.children === 'string' ? managedTag.children : '';
|
|
57
|
+
return `${open}${children}</script>`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function routerManagedTagsToHtml(tags: unknown): string[] {
|
|
61
|
+
const normalizedTags = Array.isArray(tags) ? tags : [tags];
|
|
62
|
+
return normalizedTags.map(routerManagedTagToHtml).filter(Boolean);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function createGetSsrHref(request: Request): string {
|
|
66
|
+
const url = new URL(request.url);
|
|
67
|
+
return `${url.pathname}${url.search}${url.hash}`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function collectRouterErrors(
|
|
71
|
+
tanstackRouter: AnyRouter,
|
|
72
|
+
): Record<string, unknown> | undefined {
|
|
73
|
+
const state = tanstackRouter.state as { matches?: unknown };
|
|
74
|
+
const matches = Array.isArray(state.matches)
|
|
75
|
+
? (state.matches as RouterMatchWithError[])
|
|
76
|
+
: [];
|
|
77
|
+
const errors = matches.reduce((acc: Record<string, unknown>, match) => {
|
|
78
|
+
if (!match.error) {
|
|
79
|
+
return acc;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const routeId =
|
|
83
|
+
typeof match.routeId === 'string'
|
|
84
|
+
? match.routeId
|
|
85
|
+
: typeof match.route?.id === 'string'
|
|
86
|
+
? match.route.id
|
|
87
|
+
: `match-${Object.keys(acc).length}`;
|
|
88
|
+
|
|
89
|
+
acc[routeId] = match.error;
|
|
90
|
+
return acc;
|
|
91
|
+
}, {});
|
|
92
|
+
|
|
93
|
+
return Object.keys(errors).length > 0 ? errors : undefined;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export async function attachServerSsrUtils(
|
|
97
|
+
router: TanstackRouterWithServerSsr,
|
|
98
|
+
) {
|
|
99
|
+
const { attachRouterServerSsrUtils } = await import(
|
|
100
|
+
'@tanstack/router-core/ssr/server'
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
attachRouterServerSsrUtils({
|
|
104
|
+
router,
|
|
105
|
+
manifest: undefined,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// @effect-diagnostics asyncFunction:off strictBooleanExpressions:off
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
RouterMatchWithError,
|
|
5
|
+
TanstackRouterWithServerSsr,
|
|
6
|
+
} from './ssrTypes';
|
|
7
|
+
|
|
8
|
+
type PreloadableRouteComponent = {
|
|
9
|
+
load?: (props?: Record<string, unknown>) => Promise<unknown> | unknown;
|
|
10
|
+
preload?: (props?: Record<string, unknown>) => Promise<unknown> | unknown;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
type ReactLazyRouteComponent = {
|
|
14
|
+
_init?: (payload: unknown) => unknown;
|
|
15
|
+
_payload?: unknown;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
function isPromiseLike(value: unknown): value is PromiseLike<unknown> {
|
|
19
|
+
return Boolean(
|
|
20
|
+
value && typeof (value as PromiseLike<unknown>).then === 'function',
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function isPreloadableRouteComponent(
|
|
25
|
+
component: unknown,
|
|
26
|
+
): component is PreloadableRouteComponent {
|
|
27
|
+
if (!component || typeof component !== 'function') {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const preloadable = component as PreloadableRouteComponent;
|
|
32
|
+
return (
|
|
33
|
+
typeof preloadable.load === 'function' ||
|
|
34
|
+
typeof preloadable.preload === 'function'
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function isReactLazyRouteComponent(
|
|
39
|
+
component: unknown,
|
|
40
|
+
): component is ReactLazyRouteComponent {
|
|
41
|
+
return (
|
|
42
|
+
component !== null &&
|
|
43
|
+
component !== undefined &&
|
|
44
|
+
typeof component === 'object' &&
|
|
45
|
+
typeof (component as ReactLazyRouteComponent)._init === 'function' &&
|
|
46
|
+
'_payload' in component
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function preloadReactLazyRouteComponent(
|
|
51
|
+
component: ReactLazyRouteComponent,
|
|
52
|
+
) {
|
|
53
|
+
try {
|
|
54
|
+
component._init?.(component._payload);
|
|
55
|
+
} catch (thrown) {
|
|
56
|
+
if (!isPromiseLike(thrown)) {
|
|
57
|
+
throw thrown;
|
|
58
|
+
}
|
|
59
|
+
await thrown;
|
|
60
|
+
component._init?.(component._payload);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async function preloadRouteComponent(
|
|
65
|
+
component: unknown,
|
|
66
|
+
preloadedComponents: Set<unknown>,
|
|
67
|
+
) {
|
|
68
|
+
if (isReactLazyRouteComponent(component)) {
|
|
69
|
+
if (preloadedComponents.has(component)) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
preloadedComponents.add(component);
|
|
73
|
+
await preloadReactLazyRouteComponent(component);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (!isPreloadableRouteComponent(component)) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (preloadedComponents.has(component)) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
preloadedComponents.add(component);
|
|
85
|
+
|
|
86
|
+
if (typeof component.load === 'function') {
|
|
87
|
+
await component.load({});
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
await component.preload?.({});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export async function preloadMatchedRouteComponents(
|
|
95
|
+
tanstackRouter: TanstackRouterWithServerSsr,
|
|
96
|
+
) {
|
|
97
|
+
const matches = Array.isArray(tanstackRouter.state.matches)
|
|
98
|
+
? (tanstackRouter.state.matches as RouterMatchWithError[])
|
|
99
|
+
: [];
|
|
100
|
+
const routesById = tanstackRouter.routesById || {};
|
|
101
|
+
const preloadedComponents = new Set<unknown>();
|
|
102
|
+
|
|
103
|
+
await Promise.all(
|
|
104
|
+
matches.map(async match => {
|
|
105
|
+
const routeId =
|
|
106
|
+
typeof match.routeId === 'string'
|
|
107
|
+
? match.routeId
|
|
108
|
+
: typeof match.route?.id === 'string'
|
|
109
|
+
? match.route.id
|
|
110
|
+
: undefined;
|
|
111
|
+
const route = routeId ? routesById[routeId] : match.route;
|
|
112
|
+
const options = route?.options;
|
|
113
|
+
if (!options) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
await Promise.all([
|
|
118
|
+
preloadRouteComponent(options.component, preloadedComponents),
|
|
119
|
+
preloadRouteComponent(options.pendingComponent, preloadedComponents),
|
|
120
|
+
preloadRouteComponent(options.errorComponent, preloadedComponents),
|
|
121
|
+
preloadRouteComponent(options.notFoundComponent, preloadedComponents),
|
|
122
|
+
]);
|
|
123
|
+
}),
|
|
124
|
+
);
|
|
125
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/// <reference path="./ssr-shim.d.ts" />
|
|
2
|
+
|
|
3
|
+
import type { RequestContext } from '@modern-js/runtime-utils/node';
|
|
4
|
+
import type { AnyRouter } from '@tanstack/react-router';
|
|
5
|
+
|
|
6
|
+
export type ModernTanstackRouterContext = {
|
|
7
|
+
request: Request;
|
|
8
|
+
requestContext: RequestContext<Record<string, unknown>>;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type RouterManagedTag = {
|
|
12
|
+
attrs?: Record<string, unknown>;
|
|
13
|
+
children?: unknown;
|
|
14
|
+
tag?: unknown;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type RouterMatchWithError = {
|
|
18
|
+
error?: unknown;
|
|
19
|
+
route?: {
|
|
20
|
+
id?: unknown;
|
|
21
|
+
options?: RouterRouteOptions;
|
|
22
|
+
};
|
|
23
|
+
routeId?: unknown;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export type RouterRouteOptions = {
|
|
27
|
+
component?: unknown;
|
|
28
|
+
errorComponent?: unknown;
|
|
29
|
+
notFoundComponent?: unknown;
|
|
30
|
+
pendingComponent?: unknown;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type RouterRouteWithOptions = {
|
|
34
|
+
options?: RouterRouteOptions;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export type TanstackRouterWithServerSsr = AnyRouter & {
|
|
38
|
+
resolveRedirect?: (redirect: Response) => Response;
|
|
39
|
+
routesById?: Record<string, RouterRouteWithOptions>;
|
|
40
|
+
serverSsr?: {
|
|
41
|
+
cleanup?: () => void;
|
|
42
|
+
dehydrate?: () => Promise<void> | void;
|
|
43
|
+
isSerializationFinished?: () => boolean;
|
|
44
|
+
onSerializationFinished?: (listener: () => void) => void;
|
|
45
|
+
takeBufferedScripts?: () => unknown;
|
|
46
|
+
};
|
|
47
|
+
state: AnyRouter['state'] & {
|
|
48
|
+
matches?: unknown;
|
|
49
|
+
redirect?: Response;
|
|
50
|
+
};
|
|
51
|
+
};
|
package/src/runtime/state.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
getRouterRuntimeState,
|
|
3
|
+
type InternalRouterRuntimeState,
|
|
4
|
+
} from '@modern-js/runtime/context';
|
|
2
5
|
import type { AnyRouter } from '@tanstack/react-router';
|
|
3
|
-
import type { InternalRouterRuntimeState } from './types';
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* Router runtime state as published by the TanStack router provider into the
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
// @effect-diagnostics asyncFunction:off extendsNativeError:off strictBooleanExpressions:off
|
|
2
|
+
import type { AnyRouter } from '@tanstack/react-router';
|
|
3
|
+
import type { SubmitOptions, SubmitTarget } from './formData';
|
|
4
|
+
import {
|
|
5
|
+
formDataToTextPlain,
|
|
6
|
+
formDataToUrlSearchParams,
|
|
7
|
+
toFormData,
|
|
8
|
+
} from './formData';
|
|
9
|
+
|
|
10
|
+
export class RouteActionResponseError<TData = unknown> extends Error {
|
|
11
|
+
readonly response: Response;
|
|
12
|
+
readonly data: TData;
|
|
13
|
+
|
|
14
|
+
constructor(response: Response, data: TData) {
|
|
15
|
+
super(`Route action failed with status ${response.status}`);
|
|
16
|
+
this.name = 'RouteActionResponseError';
|
|
17
|
+
this.response = response;
|
|
18
|
+
this.data = data;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
type RouteAction = (args: {
|
|
23
|
+
request: Request;
|
|
24
|
+
params: Record<string, string>;
|
|
25
|
+
context?: unknown;
|
|
26
|
+
}) => Promise<unknown> | unknown;
|
|
27
|
+
|
|
28
|
+
type RouteLoader = (args: {
|
|
29
|
+
request: Request;
|
|
30
|
+
params: Record<string, string>;
|
|
31
|
+
context?: unknown;
|
|
32
|
+
}) => Promise<unknown> | unknown;
|
|
33
|
+
|
|
34
|
+
function resolveRouteHandlers(router: AnyRouter, actionTo: string) {
|
|
35
|
+
const builtLocation = router.buildLocation({
|
|
36
|
+
to: actionTo as any,
|
|
37
|
+
} as any);
|
|
38
|
+
const href = router.getParsedLocationHref(builtLocation as any);
|
|
39
|
+
const matchedRoutes = router.getMatchedRoutes(
|
|
40
|
+
(builtLocation as any).pathname,
|
|
41
|
+
);
|
|
42
|
+
const routeStaticData = matchedRoutes.foundRoute?.options?.staticData as
|
|
43
|
+
| Record<string, unknown>
|
|
44
|
+
| undefined;
|
|
45
|
+
const action = routeStaticData?.modernRouteAction as RouteAction | undefined;
|
|
46
|
+
const loader = routeStaticData?.modernRouteLoader as RouteLoader | undefined;
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
action,
|
|
50
|
+
loader,
|
|
51
|
+
href,
|
|
52
|
+
params: (matchedRoutes.routeParams || {}) as Record<string, string>,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function isRedirectResponse(value: unknown): value is Response {
|
|
57
|
+
if (!(value instanceof Response)) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
return [301, 302, 303, 307, 308].includes(value.status);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function parseResponseData(response: Response) {
|
|
64
|
+
if (response.status === 204) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const contentType = response.headers.get('Content-Type') || '';
|
|
69
|
+
if (contentType.includes('application/json')) {
|
|
70
|
+
return response.json();
|
|
71
|
+
}
|
|
72
|
+
return response.text();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async function parseResponseResultOrThrow(response: Response) {
|
|
76
|
+
const parsed = await parseResponseData(response);
|
|
77
|
+
if (!response.ok) {
|
|
78
|
+
throw new RouteActionResponseError(response, parsed);
|
|
79
|
+
}
|
|
80
|
+
return parsed;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export async function submitRouteAction({
|
|
84
|
+
router,
|
|
85
|
+
target,
|
|
86
|
+
options = {},
|
|
87
|
+
isFetcher = false,
|
|
88
|
+
onInvalidateStart,
|
|
89
|
+
}: {
|
|
90
|
+
router: AnyRouter;
|
|
91
|
+
target: SubmitTarget;
|
|
92
|
+
options?: SubmitOptions;
|
|
93
|
+
isFetcher?: boolean;
|
|
94
|
+
onInvalidateStart?: () => void;
|
|
95
|
+
}) {
|
|
96
|
+
const method = (options.method || 'post').toLowerCase();
|
|
97
|
+
const encType = options.encType || 'application/x-www-form-urlencoded';
|
|
98
|
+
const actionTo = options.action || '.';
|
|
99
|
+
const formData = toFormData(target);
|
|
100
|
+
const resolved = resolveRouteHandlers(router, actionTo);
|
|
101
|
+
|
|
102
|
+
if (method === 'get') {
|
|
103
|
+
const search = formDataToUrlSearchParams(formData).toString();
|
|
104
|
+
const requestUrl = new URL(resolved.href, window.location.origin);
|
|
105
|
+
requestUrl.search = search;
|
|
106
|
+
|
|
107
|
+
if (isFetcher && resolved.loader) {
|
|
108
|
+
const result = await resolved.loader({
|
|
109
|
+
request: new Request(requestUrl, {
|
|
110
|
+
method: 'GET',
|
|
111
|
+
}),
|
|
112
|
+
params: resolved.params,
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
if (result instanceof Response) {
|
|
116
|
+
const redirectTo =
|
|
117
|
+
result.headers.get('X-Modernjs-Redirect') ||
|
|
118
|
+
result.headers.get('Location');
|
|
119
|
+
if (redirectTo || isRedirectResponse(result)) {
|
|
120
|
+
await router.navigate({
|
|
121
|
+
to: (redirectTo || '/') as any,
|
|
122
|
+
} as any);
|
|
123
|
+
return parseResponseData(result);
|
|
124
|
+
}
|
|
125
|
+
return parseResponseResultOrThrow(result);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return result;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
await router.navigate({
|
|
132
|
+
href: `${requestUrl.pathname}${requestUrl.search}${requestUrl.hash}`,
|
|
133
|
+
} as any);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (!resolved.action) {
|
|
138
|
+
throw new Error(`No route action found for "${actionTo}"`);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const headers = new Headers();
|
|
142
|
+
let body: BodyInit | null = null;
|
|
143
|
+
if (encType.includes('application/json')) {
|
|
144
|
+
headers.set('Content-Type', 'application/json');
|
|
145
|
+
body = JSON.stringify(
|
|
146
|
+
Object.fromEntries(formDataToUrlSearchParams(formData).entries()),
|
|
147
|
+
);
|
|
148
|
+
} else if (encType.includes('text/plain')) {
|
|
149
|
+
headers.set('Content-Type', 'text/plain;charset=UTF-8');
|
|
150
|
+
body = formDataToTextPlain(formData);
|
|
151
|
+
} else if (encType.includes('application/x-www-form-urlencoded')) {
|
|
152
|
+
headers.set(
|
|
153
|
+
'Content-Type',
|
|
154
|
+
'application/x-www-form-urlencoded;charset=UTF-8',
|
|
155
|
+
);
|
|
156
|
+
body = formDataToUrlSearchParams(formData);
|
|
157
|
+
} else {
|
|
158
|
+
body = formData;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const request = new Request(new URL(resolved.href, window.location.origin), {
|
|
162
|
+
method: method.toUpperCase(),
|
|
163
|
+
headers,
|
|
164
|
+
body,
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
const result = await resolved.action({
|
|
168
|
+
request,
|
|
169
|
+
params: resolved.params,
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
if (result instanceof Response) {
|
|
173
|
+
const redirectTo =
|
|
174
|
+
result.headers.get('X-Modernjs-Redirect') ||
|
|
175
|
+
result.headers.get('Location');
|
|
176
|
+
if (redirectTo || isRedirectResponse(result)) {
|
|
177
|
+
await router.navigate({
|
|
178
|
+
to: (redirectTo || '/') as any,
|
|
179
|
+
} as any);
|
|
180
|
+
return parseResponseData(result);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const parsed = isFetcher
|
|
184
|
+
? await parseResponseResultOrThrow(result)
|
|
185
|
+
: await parseResponseData(result);
|
|
186
|
+
onInvalidateStart?.();
|
|
187
|
+
await router.invalidate();
|
|
188
|
+
return parsed;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
onInvalidateStart?.();
|
|
192
|
+
await router.invalidate();
|
|
193
|
+
return result;
|
|
194
|
+
}
|
package/src/runtime/types.ts
CHANGED
|
@@ -1,57 +1,20 @@
|
|
|
1
|
+
import type { ModernRoute, RouterFramework } from '@modern-js/runtime/context';
|
|
1
2
|
import type { RouteObject } from '@modern-js/runtime-utils/router';
|
|
2
3
|
import type React from 'react';
|
|
3
4
|
|
|
4
|
-
export type
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
routeId: string;
|
|
18
|
-
assetRouteId?: string;
|
|
19
|
-
pathname?: string;
|
|
20
|
-
params?: Record<string, string>;
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
export type InternalRouterServerSnapshot = {
|
|
24
|
-
framework?: RouterFramework;
|
|
25
|
-
basename?: string;
|
|
26
|
-
statusCode?: number;
|
|
27
|
-
errors?: Record<string, unknown>;
|
|
28
|
-
routerData?: {
|
|
29
|
-
loaderData?: Record<string, unknown>;
|
|
30
|
-
errors?: Record<string, unknown>;
|
|
31
|
-
};
|
|
32
|
-
hydrationScript?: string;
|
|
33
|
-
hydrationScripts?: string[];
|
|
34
|
-
matchedRouteIds?: string[];
|
|
35
|
-
matches?: RouterRouteMatchSnapshot[];
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export type InternalRouterRuntimeState = {
|
|
39
|
-
framework: RouterFramework;
|
|
40
|
-
basename?: string;
|
|
41
|
-
instance?: unknown;
|
|
42
|
-
hydrationScript?: string;
|
|
43
|
-
hydrationScripts?: string[];
|
|
44
|
-
matchedRouteIds?: string[];
|
|
45
|
-
matches?: RouterRouteMatchSnapshot[];
|
|
46
|
-
serverSnapshot?: InternalRouterServerSnapshot;
|
|
47
|
-
cleanup?: () => void | Promise<void>;
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* TanStack-specific router config. Unlike the react-router provider config,
|
|
52
|
-
* this intentionally has no `oldVersion`/`future` fields — those are
|
|
53
|
-
* react-router-only knobs with no meaning here.
|
|
54
|
-
*/
|
|
5
|
+
export type {
|
|
6
|
+
BuiltInRouterFramework,
|
|
7
|
+
InternalRouterRuntimeState,
|
|
8
|
+
InternalRouterServerSnapshot,
|
|
9
|
+
LoaderFunction,
|
|
10
|
+
LoaderFunctionArgs,
|
|
11
|
+
ModernRoute,
|
|
12
|
+
RouterFramework,
|
|
13
|
+
RouterRouteMatchSnapshot,
|
|
14
|
+
RouterServerPrepareResult,
|
|
15
|
+
} from '@modern-js/runtime/context';
|
|
16
|
+
|
|
17
|
+
/** TanStack-specific router config. */
|
|
55
18
|
export type RouterConfig = {
|
|
56
19
|
framework?: RouterFramework;
|
|
57
20
|
routesConfig: {
|