@modern-js/runtime 2.6.0 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/dist/cjs/common.js +6 -0
- package/dist/cjs/core/{app-config.js → appConfig.js} +3 -3
- package/dist/cjs/core/compatible.js +4 -4
- package/dist/cjs/core/index.js +6 -6
- package/dist/cjs/core/loader/useLoader.js +2 -2
- package/dist/cjs/core/types.js +15 -0
- package/dist/cjs/router/runtime/DeferredDataScripts.js +165 -0
- package/dist/cjs/router/runtime/index.js +116 -3
- package/dist/cjs/router/runtime/plugin.js +14 -1
- package/dist/cjs/router/runtime/plugin.node.js +12 -52
- package/dist/cjs/router/runtime/utils.js +68 -69
- package/dist/cjs/{runtime-context.js → runtimeContext.js} +3 -3
- package/dist/cjs/ssr/cli/index.js +2 -0
- package/dist/cjs/ssr/index.node.js +1 -0
- package/dist/cjs/ssr/serverRender/renderToStream/buildTemplate.after.js +2 -14
- package/dist/cjs/ssr/serverRender/renderToStream/renderToPipe.js +22 -7
- package/dist/cjs/ssr/serverRender/renderToStream/template.js +2 -1
- package/dist/cjs/ssr/serverRender/renderToString/entry.js +19 -8
- package/dist/esm/common.js +3 -1
- package/dist/esm/core/compatible.js +1 -1
- package/dist/esm/core/index.js +2 -2
- package/dist/esm/core/loader/useLoader.js +1 -1
- package/dist/esm/core/types.js +1 -0
- package/dist/esm/router/runtime/DeferredDataScripts.js +166 -0
- package/dist/esm/router/runtime/index.js +3 -2
- package/dist/esm/router/runtime/plugin.js +11 -3
- package/dist/esm/router/runtime/plugin.node.js +11 -68
- package/dist/esm/router/runtime/utils.js +138 -81
- package/dist/esm/ssr/cli/index.js +2 -0
- package/dist/esm/ssr/index.node.js +1 -0
- package/dist/esm/ssr/serverRender/renderToStream/buildTemplate.after.js +2 -4
- package/dist/esm/ssr/serverRender/renderToStream/renderToPipe.js +19 -8
- package/dist/esm/ssr/serverRender/renderToStream/template.js +2 -1
- package/dist/esm/ssr/serverRender/renderToString/entry.js +15 -7
- package/dist/esm-node/common.js +4 -0
- package/dist/esm-node/core/compatible.js +1 -1
- package/dist/esm-node/core/index.js +2 -2
- package/dist/esm-node/core/loader/useLoader.js +1 -1
- package/dist/esm-node/core/types.js +0 -0
- package/dist/esm-node/router/runtime/DeferredDataScripts.js +148 -0
- package/dist/esm-node/router/runtime/index.js +113 -2
- package/dist/esm-node/router/runtime/plugin.js +15 -2
- package/dist/esm-node/router/runtime/plugin.node.js +12 -55
- package/dist/esm-node/router/runtime/utils.js +59 -69
- package/dist/esm-node/ssr/cli/index.js +2 -0
- package/dist/esm-node/ssr/index.node.js +1 -0
- package/dist/esm-node/ssr/serverRender/renderToStream/buildTemplate.after.js +2 -4
- package/dist/esm-node/ssr/serverRender/renderToStream/renderToPipe.js +22 -7
- package/dist/esm-node/ssr/serverRender/renderToStream/template.js +2 -1
- package/dist/esm-node/ssr/serverRender/renderToString/entry.js +19 -8
- package/dist/types/common.d.ts +3 -1
- package/dist/types/core/compatible.d.ts +1 -1
- package/dist/types/core/index.d.ts +4 -3
- package/dist/types/core/loader/index.d.ts +1 -2
- package/dist/types/core/loader/useLoader.d.ts +1 -15
- package/dist/types/core/plugin.d.ts +15 -15
- package/dist/types/core/types.d.ts +22 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/router/runtime/DeferredDataScripts.d.ts +8 -0
- package/dist/types/router/runtime/index.d.ts +4 -2
- package/dist/types/router/runtime/utils.d.ts +23 -4
- package/dist/types/{runtime-context.d.ts → runtimeContext.d.ts} +2 -0
- package/dist/types/ssr/serverRender/renderToStream/buildTemplate.after.d.ts +2 -0
- package/package.json +12 -15
- /package/dist/esm/core/{app-config.js → appConfig.js} +0 -0
- /package/dist/esm/{runtime-context.js → runtimeContext.js} +0 -0
- /package/dist/esm-node/core/{app-config.js → appConfig.js} +0 -0
- /package/dist/esm-node/{runtime-context.js → runtimeContext.js} +0 -0
- /package/dist/types/core/{app-config.d.ts → appConfig.d.ts} +0 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Suspense, useEffect, useRef, useMemo, useContext } from "react";
|
|
3
|
+
import {
|
|
4
|
+
Await,
|
|
5
|
+
UNSAFE_DataRouterContext as DataRouterContext,
|
|
6
|
+
useAsyncError
|
|
7
|
+
} from "react-router-dom";
|
|
8
|
+
import { serializeJson } from "@modern-js/utils/serialize";
|
|
9
|
+
import { JSX_SHELL_STREAM_END_MARK } from "../../common";
|
|
10
|
+
import { serializeErrors } from "./utils";
|
|
11
|
+
const setupFnStr = `function s(r,e){_ROUTER_DATA.r=_ROUTER_DATA.r||{},_ROUTER_DATA.r[r]=_ROUTER_DATA.r[r]||{};return new Promise((function(A,R){_ROUTER_DATA.r[r][e]={resolve:A,reject:R}}))};`;
|
|
12
|
+
const resolveFnStr = `function r(e,r,o,A){A?_ROUTER_DATA.r[e][r].reject(A):_ROUTER_DATA.r[e][r].resolve(o)};`;
|
|
13
|
+
const preResolvedFnStr = `function p(e,r){return void 0!==r?Promise.reject(new Error(r.message)):Promise.resovle(e)};`;
|
|
14
|
+
const DeferredDataScripts = () => {
|
|
15
|
+
const context = useContext(DataRouterContext);
|
|
16
|
+
const { staticContext } = context || {};
|
|
17
|
+
const hydratedRef = useRef(false);
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
hydratedRef.current = true;
|
|
20
|
+
}, []);
|
|
21
|
+
const deferredScripts = useMemo(() => {
|
|
22
|
+
if (!staticContext) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
const activeDeferreds = staticContext.activeDeferreds || [];
|
|
26
|
+
const _ROUTER_DATA = {
|
|
27
|
+
loaderData: staticContext.loaderData,
|
|
28
|
+
errors: serializeErrors(staticContext.errors)
|
|
29
|
+
};
|
|
30
|
+
let initialScripts = [
|
|
31
|
+
`_ROUTER_DATA = ${serializeJson(_ROUTER_DATA)};`,
|
|
32
|
+
`_ROUTER_DATA.s = ${setupFnStr}`,
|
|
33
|
+
`_ROUTER_DATA.r = ${resolveFnStr}`,
|
|
34
|
+
`_ROUTER_DATA.p = ${preResolvedFnStr}`
|
|
35
|
+
].join("\n");
|
|
36
|
+
const deferredDataScripts = [];
|
|
37
|
+
initialScripts += Object.entries(activeDeferreds).map(([routeId, deferredData]) => {
|
|
38
|
+
const pendingKeys = new Set(deferredData.pendingKeys);
|
|
39
|
+
const { deferredKeys } = deferredData;
|
|
40
|
+
const deferredKeyPromiseStr = deferredKeys.map((key) => {
|
|
41
|
+
if (pendingKeys.has(key)) {
|
|
42
|
+
deferredDataScripts.push(
|
|
43
|
+
/* @__PURE__ */ jsx(
|
|
44
|
+
DeferredDataScript,
|
|
45
|
+
{
|
|
46
|
+
data: deferredData.data[key],
|
|
47
|
+
dataKey: key,
|
|
48
|
+
routeId
|
|
49
|
+
},
|
|
50
|
+
`${routeId} | ${key}`
|
|
51
|
+
)
|
|
52
|
+
);
|
|
53
|
+
return `${JSON.stringify(key)}: _ROUTER_DATA.s(${JSON.stringify(
|
|
54
|
+
routeId
|
|
55
|
+
)},${JSON.stringify(key)}) `;
|
|
56
|
+
} else {
|
|
57
|
+
const trackedPromise = deferredData.data[key];
|
|
58
|
+
if (typeof trackedPromise._error !== "undefined") {
|
|
59
|
+
const error = {
|
|
60
|
+
message: trackedPromise._error.message,
|
|
61
|
+
stack: process.env.NODE_ENV !== "production" ? trackedPromise._error.stack : void 0
|
|
62
|
+
};
|
|
63
|
+
return `${JSON.stringify(
|
|
64
|
+
key
|
|
65
|
+
)}: _ROUTER_DATA.p(${void 0}, ${serializeJson(error)})`;
|
|
66
|
+
} else {
|
|
67
|
+
if (typeof trackedPromise._data === "undefined") {
|
|
68
|
+
throw new Error(
|
|
69
|
+
`The deferred data for ${key} was not resolved, did you forget to return data from a deferred promise`
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
return `${JSON.stringify(key)}: _ROUTER_DATA.p(${serializeJson(
|
|
73
|
+
trackedPromise._data
|
|
74
|
+
)})`;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}).join(",\n");
|
|
78
|
+
return `Object.assign(_ROUTER_DATA.loaderData[${JSON.stringify(
|
|
79
|
+
routeId
|
|
80
|
+
)}], {${deferredKeyPromiseStr}});`;
|
|
81
|
+
}).join("\n");
|
|
82
|
+
return [initialScripts, deferredDataScripts];
|
|
83
|
+
}, []);
|
|
84
|
+
if (!deferredScripts) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
88
|
+
!hydratedRef.current && /* @__PURE__ */ jsx(
|
|
89
|
+
"script",
|
|
90
|
+
{
|
|
91
|
+
async: true,
|
|
92
|
+
suppressHydrationWarning: true,
|
|
93
|
+
dangerouslySetInnerHTML: { __html: deferredScripts[0] }
|
|
94
|
+
}
|
|
95
|
+
),
|
|
96
|
+
!hydratedRef.current && deferredScripts[1],
|
|
97
|
+
JSX_SHELL_STREAM_END_MARK
|
|
98
|
+
] });
|
|
99
|
+
};
|
|
100
|
+
const DeferredDataScript = ({
|
|
101
|
+
data,
|
|
102
|
+
routeId,
|
|
103
|
+
dataKey
|
|
104
|
+
}) => {
|
|
105
|
+
return /* @__PURE__ */ jsx(Suspense, { children: typeof document === "undefined" && data && dataKey && routeId ? /* @__PURE__ */ jsx(
|
|
106
|
+
Await,
|
|
107
|
+
{
|
|
108
|
+
resolve: data,
|
|
109
|
+
errorElement: /* @__PURE__ */ jsx(ErrorDeferredDataScript, { routeId, dataKey }),
|
|
110
|
+
children: (data2) => /* @__PURE__ */ jsx(
|
|
111
|
+
"script",
|
|
112
|
+
{
|
|
113
|
+
async: true,
|
|
114
|
+
suppressHydrationWarning: true,
|
|
115
|
+
dangerouslySetInnerHTML: {
|
|
116
|
+
__html: `_ROUTER_DATA.r(${JSON.stringify(
|
|
117
|
+
routeId
|
|
118
|
+
)}, ${JSON.stringify(dataKey)}, ${serializeJson(data2)});`
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
) : null });
|
|
124
|
+
};
|
|
125
|
+
const ErrorDeferredDataScript = ({
|
|
126
|
+
routeId,
|
|
127
|
+
dataKey
|
|
128
|
+
}) => {
|
|
129
|
+
const error = useAsyncError();
|
|
130
|
+
return /* @__PURE__ */ jsx(
|
|
131
|
+
"script",
|
|
132
|
+
{
|
|
133
|
+
suppressHydrationWarning: true,
|
|
134
|
+
dangerouslySetInnerHTML: {
|
|
135
|
+
__html: `_ROUTER_DATA.r(${JSON.stringify(routeId)}, ${JSON.stringify(
|
|
136
|
+
dataKey
|
|
137
|
+
)}, ${void 0}, ${serializeJson({
|
|
138
|
+
message: error.message,
|
|
139
|
+
stack: error.stack
|
|
140
|
+
})});`
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
);
|
|
144
|
+
};
|
|
145
|
+
var DeferredDataScripts_default = DeferredDataScripts;
|
|
146
|
+
export {
|
|
147
|
+
DeferredDataScripts_default as default
|
|
148
|
+
};
|
|
@@ -1,9 +1,120 @@
|
|
|
1
1
|
import { routerPlugin } from "./plugin";
|
|
2
2
|
var runtime_default = routerPlugin;
|
|
3
3
|
import { modifyRoutes } from "./plugin";
|
|
4
|
-
export * from "react-router-dom";
|
|
5
4
|
export * from "./withRouter";
|
|
5
|
+
import {
|
|
6
|
+
createBrowserRouter,
|
|
7
|
+
createHashRouter,
|
|
8
|
+
createMemoryRouter,
|
|
9
|
+
RouterProvider,
|
|
10
|
+
BrowserRouter,
|
|
11
|
+
HashRouter,
|
|
12
|
+
MemoryRouter,
|
|
13
|
+
Router,
|
|
14
|
+
Await,
|
|
15
|
+
Form,
|
|
16
|
+
Link,
|
|
17
|
+
NavLink,
|
|
18
|
+
Navigate,
|
|
19
|
+
Outlet,
|
|
20
|
+
Route,
|
|
21
|
+
Routes,
|
|
22
|
+
ScrollRestoration,
|
|
23
|
+
useActionData,
|
|
24
|
+
useAsyncError,
|
|
25
|
+
useAsyncValue,
|
|
26
|
+
useBeforeUnload,
|
|
27
|
+
useFetcher,
|
|
28
|
+
useFetchers,
|
|
29
|
+
useFormAction,
|
|
30
|
+
useHref,
|
|
31
|
+
useInRouterContext,
|
|
32
|
+
useLinkClickHandler,
|
|
33
|
+
useLoaderData,
|
|
34
|
+
useLocation,
|
|
35
|
+
useMatch,
|
|
36
|
+
useMatches,
|
|
37
|
+
useNavigate,
|
|
38
|
+
useNavigation,
|
|
39
|
+
useNavigationType,
|
|
40
|
+
useOutlet,
|
|
41
|
+
useOutletContext,
|
|
42
|
+
useParams,
|
|
43
|
+
useResolvedPath,
|
|
44
|
+
useRevalidator,
|
|
45
|
+
useRouteError,
|
|
46
|
+
useRouteLoaderData,
|
|
47
|
+
useRoutes,
|
|
48
|
+
useSearchParams,
|
|
49
|
+
useSubmit,
|
|
50
|
+
createRoutesFromChildren,
|
|
51
|
+
createRoutesFromElements,
|
|
52
|
+
createSearchParams,
|
|
53
|
+
generatePath,
|
|
54
|
+
isRouteErrorResponse,
|
|
55
|
+
matchPath,
|
|
56
|
+
matchRoutes,
|
|
57
|
+
renderMatches,
|
|
58
|
+
resolvePath
|
|
59
|
+
} from "react-router-dom";
|
|
60
|
+
import { defer, json, redirect } from "@modern-js/utils/remix-router";
|
|
6
61
|
export {
|
|
62
|
+
Await,
|
|
63
|
+
BrowserRouter,
|
|
64
|
+
Form,
|
|
65
|
+
HashRouter,
|
|
66
|
+
Link,
|
|
67
|
+
MemoryRouter,
|
|
68
|
+
NavLink,
|
|
69
|
+
Navigate,
|
|
70
|
+
Outlet,
|
|
71
|
+
Route,
|
|
72
|
+
Router,
|
|
73
|
+
RouterProvider,
|
|
74
|
+
Routes,
|
|
75
|
+
ScrollRestoration,
|
|
76
|
+
createBrowserRouter,
|
|
77
|
+
createHashRouter,
|
|
78
|
+
createMemoryRouter,
|
|
79
|
+
createRoutesFromChildren,
|
|
80
|
+
createRoutesFromElements,
|
|
81
|
+
createSearchParams,
|
|
7
82
|
runtime_default as default,
|
|
8
|
-
|
|
83
|
+
defer,
|
|
84
|
+
generatePath,
|
|
85
|
+
isRouteErrorResponse,
|
|
86
|
+
json,
|
|
87
|
+
matchPath,
|
|
88
|
+
matchRoutes,
|
|
89
|
+
modifyRoutes,
|
|
90
|
+
redirect,
|
|
91
|
+
renderMatches,
|
|
92
|
+
resolvePath,
|
|
93
|
+
useActionData,
|
|
94
|
+
useAsyncError,
|
|
95
|
+
useAsyncValue,
|
|
96
|
+
useBeforeUnload,
|
|
97
|
+
useFetcher,
|
|
98
|
+
useFetchers,
|
|
99
|
+
useFormAction,
|
|
100
|
+
useHref,
|
|
101
|
+
useInRouterContext,
|
|
102
|
+
useLinkClickHandler,
|
|
103
|
+
useLoaderData,
|
|
104
|
+
useLocation,
|
|
105
|
+
useMatch,
|
|
106
|
+
useMatches,
|
|
107
|
+
useNavigate,
|
|
108
|
+
useNavigation,
|
|
109
|
+
useNavigationType,
|
|
110
|
+
useOutlet,
|
|
111
|
+
useOutletContext,
|
|
112
|
+
useParams,
|
|
113
|
+
useResolvedPath,
|
|
114
|
+
useRevalidator,
|
|
115
|
+
useRouteError,
|
|
116
|
+
useRouteLoaderData,
|
|
117
|
+
useRoutes,
|
|
118
|
+
useSearchParams,
|
|
119
|
+
useSubmit
|
|
9
120
|
};
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
useLocation
|
|
9
9
|
} from "react-router-dom";
|
|
10
10
|
import hoistNonReactStatics from "hoist-non-react-statics";
|
|
11
|
-
import { renderRoutes, urlJoin } from "./utils";
|
|
11
|
+
import { deserializeErrors, renderRoutes, urlJoin } from "./utils";
|
|
12
12
|
let finalRouteConfig = {
|
|
13
13
|
routes: []
|
|
14
14
|
};
|
|
@@ -55,7 +55,20 @@ const routerPlugin = ({
|
|
|
55
55
|
const routes = createRoutes ? createRoutes() : createRoutesFromElements(renderRoutes(finalRouteConfig));
|
|
56
56
|
const baseUrl = ((_a = window._SERVER_DATA) == null ? void 0 : _a.router.baseUrl) || select(location.pathname);
|
|
57
57
|
const _basename = baseUrl === "/" ? urlJoin(baseUrl, basename) : baseUrl;
|
|
58
|
-
|
|
58
|
+
let hydrationData = window._ROUTER_DATA;
|
|
59
|
+
if (hydrationData == null ? void 0 : hydrationData.errors) {
|
|
60
|
+
hydrationData = {
|
|
61
|
+
...hydrationData,
|
|
62
|
+
errors: deserializeErrors(hydrationData.errors)
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
const router = supportHtml5History ? createBrowserRouter(routes, {
|
|
66
|
+
basename: _basename,
|
|
67
|
+
hydrationData
|
|
68
|
+
}) : createHashRouter(routes, {
|
|
69
|
+
basename: _basename,
|
|
70
|
+
hydrationData
|
|
71
|
+
});
|
|
59
72
|
return /* @__PURE__ */ jsx(App, { ...props, children: /* @__PURE__ */ jsx(RouterProvider, { router }) });
|
|
60
73
|
};
|
|
61
74
|
};
|
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
import { jsx
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useContext } from "react";
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
createStaticHandler,
|
|
6
|
-
isRouteErrorResponse
|
|
7
|
-
} from "@remix-run/router";
|
|
3
|
+
import { createStaticHandler } from "@modern-js/utils/remix-router";
|
|
8
4
|
import {
|
|
9
5
|
createStaticRouter,
|
|
10
6
|
StaticRouterProvider
|
|
@@ -41,26 +37,6 @@ function createFetchHeaders(requestHeaders) {
|
|
|
41
37
|
}
|
|
42
38
|
return headers;
|
|
43
39
|
}
|
|
44
|
-
function serializeErrors(errors) {
|
|
45
|
-
if (!errors) {
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
const entries = Object.entries(errors);
|
|
49
|
-
const serialized = {};
|
|
50
|
-
for (const [key, val] of entries) {
|
|
51
|
-
if (isRouteErrorResponse(val)) {
|
|
52
|
-
serialized[key] = { ...val, __type: "RouteErrorResponse" };
|
|
53
|
-
} else if (val instanceof Error) {
|
|
54
|
-
serialized[key] = {
|
|
55
|
-
message: val.message,
|
|
56
|
-
__type: "Error"
|
|
57
|
-
};
|
|
58
|
-
} else {
|
|
59
|
-
serialized[key] = val;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
return serialized;
|
|
63
|
-
}
|
|
64
40
|
const routerPlugin = ({
|
|
65
41
|
basename = "",
|
|
66
42
|
routesConfig,
|
|
@@ -74,10 +50,10 @@ const routerPlugin = ({
|
|
|
74
50
|
if (!routesConfig && !createRoutes) {
|
|
75
51
|
return next({ context });
|
|
76
52
|
}
|
|
77
|
-
const { request } = context.ssrContext;
|
|
53
|
+
const { request, mode: ssrMode } = context.ssrContext;
|
|
78
54
|
const baseUrl = request.baseUrl;
|
|
79
55
|
const _basename = baseUrl === "/" ? urlJoin(baseUrl, basename) : baseUrl;
|
|
80
|
-
const routes = createRoutes ? createRoutes() : createRoutesFromElements(renderRoutes(routesConfig));
|
|
56
|
+
const routes = createRoutes ? createRoutes() : createRoutesFromElements(renderRoutes(routesConfig, ssrMode));
|
|
81
57
|
const { query } = createStaticHandler(routes, {
|
|
82
58
|
basename: _basename
|
|
83
59
|
});
|
|
@@ -100,33 +76,14 @@ const routerPlugin = ({
|
|
|
100
76
|
const getRouteApp = () => {
|
|
101
77
|
return (props) => {
|
|
102
78
|
const { router, routerContext } = useContext(RuntimeReactContext);
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
)};`;
|
|
112
|
-
return /* @__PURE__ */ jsxs(App, { ...props, children: [
|
|
113
|
-
/* @__PURE__ */ jsx(
|
|
114
|
-
StaticRouterProvider,
|
|
115
|
-
{
|
|
116
|
-
router,
|
|
117
|
-
context: routerContext,
|
|
118
|
-
hydrate: false
|
|
119
|
-
}
|
|
120
|
-
),
|
|
121
|
-
/* @__PURE__ */ jsx(
|
|
122
|
-
"script",
|
|
123
|
-
{
|
|
124
|
-
suppressHydrationWarning: true,
|
|
125
|
-
id: "the-nonce",
|
|
126
|
-
dangerouslySetInnerHTML: { __html: hydrateScript }
|
|
127
|
-
}
|
|
128
|
-
)
|
|
129
|
-
] });
|
|
79
|
+
return /* @__PURE__ */ jsx(App, { ...props, children: /* @__PURE__ */ jsx(
|
|
80
|
+
StaticRouterProvider,
|
|
81
|
+
{
|
|
82
|
+
router,
|
|
83
|
+
context: routerContext,
|
|
84
|
+
hydrate: false
|
|
85
|
+
}
|
|
86
|
+
) });
|
|
130
87
|
};
|
|
131
88
|
};
|
|
132
89
|
const RouteApp = getRouteApp();
|
|
@@ -1,54 +1,16 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
|
-
import { Suspense } from "react";
|
|
3
2
|
import { Route } from "react-router-dom";
|
|
3
|
+
import { renderNestedRoute } from "@modern-js/utils/nestedRoutes";
|
|
4
|
+
import {
|
|
5
|
+
ErrorResponse,
|
|
6
|
+
isRouteErrorResponse
|
|
7
|
+
} from "@modern-js/utils/remix-router";
|
|
4
8
|
import { DefaultNotFound } from "./DefaultNotFound";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
path: nestedRoute.path,
|
|
11
|
-
id: nestedRoute.id,
|
|
12
|
-
loader: createLoader(nestedRoute),
|
|
13
|
-
action: nestedRoute.action,
|
|
14
|
-
hasErrorBoundary: nestedRoute.hasErrorBoundary,
|
|
15
|
-
shouldRevalidate: nestedRoute.shouldRevalidate,
|
|
16
|
-
handle: nestedRoute.handle,
|
|
17
|
-
index: nestedRoute.index,
|
|
18
|
-
element: nestedRoute.element,
|
|
19
|
-
errorElement: nestedRoute.errorElement
|
|
20
|
-
};
|
|
21
|
-
if (nestedRoute.error) {
|
|
22
|
-
const errorElement = /* @__PURE__ */ jsx(nestedRoute.error, {});
|
|
23
|
-
routeProps.errorElement = errorElement;
|
|
24
|
-
}
|
|
25
|
-
let element;
|
|
26
|
-
if (Component) {
|
|
27
|
-
if (parent == null ? void 0 : parent.loading) {
|
|
28
|
-
const Loading = parent.loading;
|
|
29
|
-
if (isLoadableComponent(Component)) {
|
|
30
|
-
element = /* @__PURE__ */ jsx(Component, { fallback: /* @__PURE__ */ jsx(Loading, {}) });
|
|
31
|
-
} else {
|
|
32
|
-
element = /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(Loading, {}), children: /* @__PURE__ */ jsx(Component, {}) });
|
|
33
|
-
}
|
|
34
|
-
} else if (isLoadableComponent(Component) || isRoot) {
|
|
35
|
-
element = /* @__PURE__ */ jsx(Component, {});
|
|
36
|
-
} else {
|
|
37
|
-
element = /* @__PURE__ */ jsx(Suspense, { fallback: null, children: /* @__PURE__ */ jsx(Component, {}) });
|
|
38
|
-
}
|
|
39
|
-
} else {
|
|
40
|
-
nestedRoute.loading = parent == null ? void 0 : parent.loading;
|
|
41
|
-
}
|
|
42
|
-
if (element) {
|
|
43
|
-
routeProps.element = element;
|
|
44
|
-
}
|
|
45
|
-
const childElements = children == null ? void 0 : children.map((childRoute) => {
|
|
46
|
-
return renderNestedRoute(childRoute, nestedRoute);
|
|
47
|
-
});
|
|
48
|
-
const routeElement = index ? /* @__PURE__ */ jsx(Route, { ...routeProps, index: true }, id) : /* @__PURE__ */ jsx(Route, { ...routeProps, index: false, children: childElements }, id);
|
|
49
|
-
return routeElement;
|
|
50
|
-
};
|
|
51
|
-
function getRouteComponents(routes, globalApp) {
|
|
9
|
+
import DeferredDataScripts from "./DeferredDataScripts";
|
|
10
|
+
function getRouteComponents(routes, {
|
|
11
|
+
globalApp,
|
|
12
|
+
ssrMode
|
|
13
|
+
}) {
|
|
52
14
|
const Layout = ({ Component, ...props }) => {
|
|
53
15
|
const GlobalLayout = globalApp;
|
|
54
16
|
if (!GlobalLayout) {
|
|
@@ -59,7 +21,9 @@ function getRouteComponents(routes, globalApp) {
|
|
|
59
21
|
const routeElements = [];
|
|
60
22
|
for (const route of routes) {
|
|
61
23
|
if (route.type === "nested") {
|
|
62
|
-
const routeElement = renderNestedRoute(route
|
|
24
|
+
const routeElement = renderNestedRoute(route, {
|
|
25
|
+
DeferredDataComponent: ssrMode === "stream" ? DeferredDataScripts : void 0
|
|
26
|
+
});
|
|
63
27
|
routeElements.push(routeElement);
|
|
64
28
|
} else {
|
|
65
29
|
const routeElement = /* @__PURE__ */ jsx(
|
|
@@ -76,7 +40,7 @@ function getRouteComponents(routes, globalApp) {
|
|
|
76
40
|
routeElements.push(/* @__PURE__ */ jsx(Route, { path: "*", element: /* @__PURE__ */ jsx(DefaultNotFound, {}) }, "*"));
|
|
77
41
|
return routeElements;
|
|
78
42
|
}
|
|
79
|
-
function renderRoutes(routesConfig) {
|
|
43
|
+
function renderRoutes(routesConfig, ssrMode) {
|
|
80
44
|
if (!routesConfig) {
|
|
81
45
|
return null;
|
|
82
46
|
}
|
|
@@ -84,7 +48,7 @@ function renderRoutes(routesConfig) {
|
|
|
84
48
|
if (!routes) {
|
|
85
49
|
return null;
|
|
86
50
|
}
|
|
87
|
-
const routeElements = getRouteComponents(routes, globalApp);
|
|
51
|
+
const routeElements = getRouteComponents(routes, { globalApp, ssrMode });
|
|
88
52
|
return routeElements;
|
|
89
53
|
}
|
|
90
54
|
function getLocation(serverContext) {
|
|
@@ -118,31 +82,57 @@ function standardSlash(str) {
|
|
|
118
82
|
}
|
|
119
83
|
return addr;
|
|
120
84
|
}
|
|
121
|
-
function
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
return (args) => {
|
|
125
|
-
if (typeof route.lazyImport === "function") {
|
|
126
|
-
route.lazyImport();
|
|
127
|
-
}
|
|
128
|
-
return loader(args);
|
|
129
|
-
};
|
|
130
|
-
} else {
|
|
131
|
-
return () => {
|
|
132
|
-
if (typeof route.lazyImport === "function") {
|
|
133
|
-
route.lazyImport();
|
|
134
|
-
}
|
|
135
|
-
return null;
|
|
136
|
-
};
|
|
85
|
+
function serializeErrors(errors) {
|
|
86
|
+
if (!errors) {
|
|
87
|
+
return null;
|
|
137
88
|
}
|
|
89
|
+
const entries = Object.entries(errors);
|
|
90
|
+
const serialized = {};
|
|
91
|
+
for (const [key, val] of entries) {
|
|
92
|
+
if (isRouteErrorResponse(val)) {
|
|
93
|
+
serialized[key] = { ...val, __type: "RouteErrorResponse" };
|
|
94
|
+
} else if (val instanceof Error) {
|
|
95
|
+
serialized[key] = {
|
|
96
|
+
message: val.message,
|
|
97
|
+
stack: val.stack,
|
|
98
|
+
__type: "Error"
|
|
99
|
+
};
|
|
100
|
+
} else {
|
|
101
|
+
serialized[key] = val;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return serialized;
|
|
138
105
|
}
|
|
139
|
-
function
|
|
140
|
-
|
|
106
|
+
function deserializeErrors(errors) {
|
|
107
|
+
if (!errors) {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
const entries = Object.entries(errors);
|
|
111
|
+
const serialized = {};
|
|
112
|
+
for (const [key, val] of entries) {
|
|
113
|
+
if (val && val.__type === "RouteErrorResponse") {
|
|
114
|
+
serialized[key] = new ErrorResponse(
|
|
115
|
+
val.status,
|
|
116
|
+
val.statusText,
|
|
117
|
+
val.data,
|
|
118
|
+
val.internal === true
|
|
119
|
+
);
|
|
120
|
+
} else if (val && val.__type === "Error") {
|
|
121
|
+
const error = new Error(val.message);
|
|
122
|
+
error.stack = val.stack;
|
|
123
|
+
serialized[key] = error;
|
|
124
|
+
} else {
|
|
125
|
+
serialized[key] = val;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return serialized;
|
|
141
129
|
}
|
|
142
130
|
export {
|
|
131
|
+
deserializeErrors,
|
|
143
132
|
getLocation,
|
|
144
133
|
getRouteComponents,
|
|
145
134
|
renderRoutes,
|
|
135
|
+
serializeErrors,
|
|
146
136
|
standardSlash,
|
|
147
137
|
urlJoin
|
|
148
138
|
};
|
|
@@ -39,6 +39,8 @@ var cli_default = () => ({
|
|
|
39
39
|
return {
|
|
40
40
|
source: {
|
|
41
41
|
alias: {
|
|
42
|
+
// ensure that all packages use the same storage in @modern-js/utils/ssr
|
|
43
|
+
"@modern-js/utils/ssr": require.resolve("@modern-js/utils/ssr"),
|
|
42
44
|
"@modern-js/runtime/plugins": pluginsExportsUtils.getPath()
|
|
43
45
|
}
|
|
44
46
|
},
|
|
@@ -15,6 +15,7 @@ const ssr = (config = {}) => ({
|
|
|
15
15
|
init({ context }, next) {
|
|
16
16
|
const { request } = context.ssrContext;
|
|
17
17
|
context.ssrContext.request = formatServer(request);
|
|
18
|
+
context.ssrContext.mode = config.mode;
|
|
18
19
|
return next({ context });
|
|
19
20
|
},
|
|
20
21
|
pickContext: ({ context, pickedContext }, next) => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { serializeJson } from "@modern-js/utils/serialize";
|
|
2
2
|
import { buildTemplate } from "./buildTemplate.share";
|
|
3
3
|
function buildShellAfterTemplate(afterAppTemplate, options) {
|
|
4
4
|
const callbacks = [injectSSRDataScript];
|
|
@@ -26,9 +26,7 @@ function buildShellAfterTemplate(afterAppTemplate, options) {
|
|
|
26
26
|
renderLevel
|
|
27
27
|
};
|
|
28
28
|
return `
|
|
29
|
-
<script>window._SSR_DATA = ${
|
|
30
|
-
isJSON: true
|
|
31
|
-
})}</script>
|
|
29
|
+
<script>window._SSR_DATA = ${serializeJson(SSRData)}</script>
|
|
32
30
|
`;
|
|
33
31
|
}
|
|
34
32
|
}
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import { Transform } from "stream";
|
|
2
2
|
import { RenderLevel } from "../types";
|
|
3
|
+
import { ESCAPED_SHELL_STREAM_END_MARK } from "../../../common";
|
|
3
4
|
import { getTemplates } from "./template";
|
|
5
|
+
var ShellChunkStatus = /* @__PURE__ */ ((ShellChunkStatus2) => {
|
|
6
|
+
ShellChunkStatus2[ShellChunkStatus2["IDLE"] = 0] = "IDLE";
|
|
7
|
+
ShellChunkStatus2[ShellChunkStatus2["START"] = 1] = "START";
|
|
8
|
+
ShellChunkStatus2[ShellChunkStatus2["FINIESH"] = 2] = "FINIESH";
|
|
9
|
+
return ShellChunkStatus2;
|
|
10
|
+
})(ShellChunkStatus || {});
|
|
4
11
|
function renderToPipe(rootElement, context, options) {
|
|
5
|
-
let
|
|
12
|
+
let shellChunkStatus = 0 /* IDLE */;
|
|
6
13
|
const { ssrContext } = context;
|
|
7
14
|
const forUserPipe = (stream) => {
|
|
8
15
|
return new Promise((resolve) => {
|
|
@@ -23,9 +30,20 @@ function renderToPipe(rootElement, context, options) {
|
|
|
23
30
|
const injectableTransform = new Transform({
|
|
24
31
|
transform(chunk, _encoding, callback) {
|
|
25
32
|
try {
|
|
26
|
-
if (
|
|
27
|
-
|
|
28
|
-
|
|
33
|
+
if (shellChunkStatus !== 2 /* FINIESH */) {
|
|
34
|
+
let concatedChunk = chunk.toString();
|
|
35
|
+
if (shellChunkStatus === 0 /* IDLE */) {
|
|
36
|
+
concatedChunk = `${shellBefore}${concatedChunk}`;
|
|
37
|
+
shellChunkStatus = 1 /* START */;
|
|
38
|
+
}
|
|
39
|
+
if (shellChunkStatus === 1 /* START */ && concatedChunk.endsWith(ESCAPED_SHELL_STREAM_END_MARK)) {
|
|
40
|
+
concatedChunk = concatedChunk.replace(
|
|
41
|
+
ESCAPED_SHELL_STREAM_END_MARK,
|
|
42
|
+
shellAfter
|
|
43
|
+
);
|
|
44
|
+
shellChunkStatus = 2 /* FINIESH */;
|
|
45
|
+
}
|
|
46
|
+
this.push(concatedChunk);
|
|
29
47
|
} else {
|
|
30
48
|
this.push(chunk);
|
|
31
49
|
}
|
|
@@ -68,9 +86,6 @@ function renderToPipe(rootElement, context, options) {
|
|
|
68
86
|
});
|
|
69
87
|
};
|
|
70
88
|
return forUserPipe;
|
|
71
|
-
function joinChunk(before = "", chunk, after = "") {
|
|
72
|
-
return `${before}${chunk.toString()}${after}`;
|
|
73
|
-
}
|
|
74
89
|
}
|
|
75
90
|
var renderToPipe_default = renderToPipe;
|
|
76
91
|
export {
|
|
@@ -2,7 +2,7 @@ import { buildShellAfterTemplate } from "./buildTemplate.after";
|
|
|
2
2
|
import { buildShellBeforeTemplate } from "./bulidTemplate.before";
|
|
3
3
|
const HTML_SEPARATOR = "<!--<?- html ?>-->";
|
|
4
4
|
const getTemplates = (context, renderLevel) => {
|
|
5
|
-
const { ssrContext } = context;
|
|
5
|
+
const { ssrContext, routerContext } = context;
|
|
6
6
|
const [beforeAppTemplate = "", afterAppHtmlTemplate = ""] = ssrContext.template.split(HTML_SEPARATOR) || [];
|
|
7
7
|
const builtBeforeTemplate = buildShellBeforeTemplate(
|
|
8
8
|
beforeAppTemplate,
|
|
@@ -10,6 +10,7 @@ const getTemplates = (context, renderLevel) => {
|
|
|
10
10
|
);
|
|
11
11
|
const builtAfterTemplate = buildShellAfterTemplate(afterAppHtmlTemplate, {
|
|
12
12
|
ssrContext,
|
|
13
|
+
routerContext,
|
|
13
14
|
renderLevel
|
|
14
15
|
});
|
|
15
16
|
return {
|