vite-react-ssg 0.6.4 → 0.7.0-beta.2
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/index.cjs +30 -1
- package/dist/index.d.cts +6 -0
- package/dist/index.d.mts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.mjs +30 -1
- package/dist/node/cli.cjs +3 -0
- package/dist/node/cli.mjs +3 -0
- package/dist/node.cjs +239 -85
- package/dist/node.mjs +240 -86
- package/dist/shared/vite-react-ssg.0408f7e1.cjs +72 -0
- package/dist/shared/vite-react-ssg.054e813a.mjs +65 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -6,6 +6,7 @@ const reactHelmetAsync = require('react-helmet-async');
|
|
|
6
6
|
const reactRouterDom = require('react-router-dom');
|
|
7
7
|
const ClientOnly = require('./shared/vite-react-ssg.c1d49976.cjs');
|
|
8
8
|
const state = require('./shared/vite-react-ssg.bee8a5a9.cjs');
|
|
9
|
+
const remixRouter = require('./shared/vite-react-ssg.0408f7e1.cjs');
|
|
9
10
|
|
|
10
11
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
11
12
|
|
|
@@ -86,7 +87,7 @@ function ViteReactSSG(routerOptions, fn, options = {}) {
|
|
|
86
87
|
const isClient = typeof window !== "undefined";
|
|
87
88
|
const BASE_URL = routerOptions.basename ?? "/";
|
|
88
89
|
async function createRoot(client = false, routePath) {
|
|
89
|
-
const browserRouter = client ? reactRouterDom.createBrowserRouter(routerOptions.routes, { basename: BASE_URL }) : void 0;
|
|
90
|
+
const browserRouter = client ? reactRouterDom.createBrowserRouter(remixRouter.convertRoutesToDataRoutes(routerOptions.routes, transformStaticLoaderRoute), { basename: BASE_URL }) : void 0;
|
|
90
91
|
const appRenderCallbacks = [];
|
|
91
92
|
const onSSRAppRendered = client ? () => {
|
|
92
93
|
} : (cb) => appRenderCallbacks.push(cb);
|
|
@@ -152,6 +153,34 @@ function ViteReactSSG(routerOptions, fn, options = {}) {
|
|
|
152
153
|
})();
|
|
153
154
|
}
|
|
154
155
|
return createRoot;
|
|
156
|
+
function transformStaticLoaderRoute(route) {
|
|
157
|
+
const loader = async ({ request }) => {
|
|
158
|
+
if (undefined.DEV) {
|
|
159
|
+
const routeId = encodeURIComponent(route.id);
|
|
160
|
+
const dataQuery = `_data=${routeId}`;
|
|
161
|
+
const url = request.url.includes("?") ? `${request.url}&${dataQuery}` : `${request.url}?${dataQuery}`;
|
|
162
|
+
return fetch(url);
|
|
163
|
+
} else {
|
|
164
|
+
let staticLoadData;
|
|
165
|
+
if (window.__VITE_REACT_SSG_STATIC_LOADER_DATA__) {
|
|
166
|
+
staticLoadData = window.__VITE_REACT_SSG_STATIC_LOADER_DATA__;
|
|
167
|
+
} else {
|
|
168
|
+
const manifestUrl = remixRouter.joinUrlSegments(BASE_URL, `static-loader-data-manifest-${window.__VITE_REACT_SSG_HASH__}.json`);
|
|
169
|
+
staticLoadData = await (await fetch(remixRouter.withLeadingSlash(manifestUrl))).json();
|
|
170
|
+
window.__VITE_REACT_SSG_STATIC_LOADER_DATA__ = staticLoadData;
|
|
171
|
+
}
|
|
172
|
+
const { url } = request;
|
|
173
|
+
let { pathname } = new URL(url);
|
|
174
|
+
if (BASE_URL !== "/") {
|
|
175
|
+
pathname = remixRouter.stripBase(pathname, BASE_URL);
|
|
176
|
+
}
|
|
177
|
+
const routeData = staticLoadData?.[pathname]?.[route.id];
|
|
178
|
+
return routeData ?? null;
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
route.loader = loader;
|
|
182
|
+
return route;
|
|
183
|
+
}
|
|
155
184
|
}
|
|
156
185
|
|
|
157
186
|
exports.ClientOnly = ClientOnly.ClientOnly;
|
package/dist/index.d.cts
CHANGED
|
@@ -10,5 +10,11 @@ declare const Link: React.ForwardRefExoticComponent<LinkProps & React.RefAttribu
|
|
|
10
10
|
declare const NavLink: React.ForwardRefExoticComponent<NavLinkProps & React.RefAttributes<HTMLAnchorElement>>;
|
|
11
11
|
|
|
12
12
|
declare function ViteReactSSG(routerOptions: RouterOptions, fn?: (context: ViteReactSSGContext<true>) => Promise<void> | void, options?: ViteReactSSGClientOptions): (client?: boolean, routePath?: string) => Promise<ViteReactSSGContext<true>>;
|
|
13
|
+
declare global {
|
|
14
|
+
interface Window {
|
|
15
|
+
__VITE_REACT_SSG_STATIC_LOADER_DATA__: any;
|
|
16
|
+
__VITE_REACT_SSG_HASH__: string;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
13
19
|
|
|
14
20
|
export { Link, NavLink, RouterOptions, ViteReactSSG, ViteReactSSGClientOptions, ViteReactSSGContext };
|
package/dist/index.d.mts
CHANGED
|
@@ -10,5 +10,11 @@ declare const Link: React.ForwardRefExoticComponent<LinkProps & React.RefAttribu
|
|
|
10
10
|
declare const NavLink: React.ForwardRefExoticComponent<NavLinkProps & React.RefAttributes<HTMLAnchorElement>>;
|
|
11
11
|
|
|
12
12
|
declare function ViteReactSSG(routerOptions: RouterOptions, fn?: (context: ViteReactSSGContext<true>) => Promise<void> | void, options?: ViteReactSSGClientOptions): (client?: boolean, routePath?: string) => Promise<ViteReactSSGContext<true>>;
|
|
13
|
+
declare global {
|
|
14
|
+
interface Window {
|
|
15
|
+
__VITE_REACT_SSG_STATIC_LOADER_DATA__: any;
|
|
16
|
+
__VITE_REACT_SSG_HASH__: string;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
13
19
|
|
|
14
20
|
export { Link, NavLink, RouterOptions, ViteReactSSG, ViteReactSSGClientOptions, ViteReactSSGContext };
|
package/dist/index.d.ts
CHANGED
|
@@ -10,5 +10,11 @@ declare const Link: React.ForwardRefExoticComponent<LinkProps & React.RefAttribu
|
|
|
10
10
|
declare const NavLink: React.ForwardRefExoticComponent<NavLinkProps & React.RefAttributes<HTMLAnchorElement>>;
|
|
11
11
|
|
|
12
12
|
declare function ViteReactSSG(routerOptions: RouterOptions, fn?: (context: ViteReactSSGContext<true>) => Promise<void> | void, options?: ViteReactSSGClientOptions): (client?: boolean, routePath?: string) => Promise<ViteReactSSGContext<true>>;
|
|
13
|
+
declare global {
|
|
14
|
+
interface Window {
|
|
15
|
+
__VITE_REACT_SSG_STATIC_LOADER_DATA__: any;
|
|
16
|
+
__VITE_REACT_SSG_HASH__: string;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
13
19
|
|
|
14
20
|
export { Link, NavLink, RouterOptions, ViteReactSSG, ViteReactSSGClientOptions, ViteReactSSGContext };
|
package/dist/index.mjs
CHANGED
|
@@ -5,6 +5,7 @@ import { useLinkClickHandler, Link as Link$1, NavLink as NavLink$1, matchRoutes,
|
|
|
5
5
|
import { d as documentReady } from './shared/vite-react-ssg.a292c181.mjs';
|
|
6
6
|
export { C as ClientOnly, H as Head } from './shared/vite-react-ssg.a292c181.mjs';
|
|
7
7
|
import { d as deserializeState } from './shared/vite-react-ssg.579feabb.mjs';
|
|
8
|
+
import { c as convertRoutesToDataRoutes, j as joinUrlSegments, w as withLeadingSlash, s as stripBase } from './shared/vite-react-ssg.054e813a.mjs';
|
|
8
9
|
|
|
9
10
|
const Link = forwardRef((props, ref) => {
|
|
10
11
|
const {
|
|
@@ -81,7 +82,7 @@ function ViteReactSSG(routerOptions, fn, options = {}) {
|
|
|
81
82
|
const isClient = typeof window !== "undefined";
|
|
82
83
|
const BASE_URL = routerOptions.basename ?? "/";
|
|
83
84
|
async function createRoot$1(client = false, routePath) {
|
|
84
|
-
const browserRouter = client ? createBrowserRouter(routerOptions.routes, { basename: BASE_URL }) : void 0;
|
|
85
|
+
const browserRouter = client ? createBrowserRouter(convertRoutesToDataRoutes(routerOptions.routes, transformStaticLoaderRoute), { basename: BASE_URL }) : void 0;
|
|
85
86
|
const appRenderCallbacks = [];
|
|
86
87
|
const onSSRAppRendered = client ? () => {
|
|
87
88
|
} : (cb) => appRenderCallbacks.push(cb);
|
|
@@ -147,6 +148,34 @@ function ViteReactSSG(routerOptions, fn, options = {}) {
|
|
|
147
148
|
})();
|
|
148
149
|
}
|
|
149
150
|
return createRoot$1;
|
|
151
|
+
function transformStaticLoaderRoute(route) {
|
|
152
|
+
const loader = async ({ request }) => {
|
|
153
|
+
if (import.meta.env.DEV) {
|
|
154
|
+
const routeId = encodeURIComponent(route.id);
|
|
155
|
+
const dataQuery = `_data=${routeId}`;
|
|
156
|
+
const url = request.url.includes("?") ? `${request.url}&${dataQuery}` : `${request.url}?${dataQuery}`;
|
|
157
|
+
return fetch(url);
|
|
158
|
+
} else {
|
|
159
|
+
let staticLoadData;
|
|
160
|
+
if (window.__VITE_REACT_SSG_STATIC_LOADER_DATA__) {
|
|
161
|
+
staticLoadData = window.__VITE_REACT_SSG_STATIC_LOADER_DATA__;
|
|
162
|
+
} else {
|
|
163
|
+
const manifestUrl = joinUrlSegments(BASE_URL, `static-loader-data-manifest-${window.__VITE_REACT_SSG_HASH__}.json`);
|
|
164
|
+
staticLoadData = await (await fetch(withLeadingSlash(manifestUrl))).json();
|
|
165
|
+
window.__VITE_REACT_SSG_STATIC_LOADER_DATA__ = staticLoadData;
|
|
166
|
+
}
|
|
167
|
+
const { url } = request;
|
|
168
|
+
let { pathname } = new URL(url);
|
|
169
|
+
if (BASE_URL !== "/") {
|
|
170
|
+
pathname = stripBase(pathname, BASE_URL);
|
|
171
|
+
}
|
|
172
|
+
const routeData = staticLoadData?.[pathname]?.[route.id];
|
|
173
|
+
return routeData ?? null;
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
route.loader = loader;
|
|
177
|
+
return route;
|
|
178
|
+
}
|
|
150
179
|
}
|
|
151
180
|
|
|
152
181
|
export { Link, NavLink, ViteReactSSG };
|
package/dist/node/cli.cjs
CHANGED
|
@@ -11,11 +11,14 @@ require('fs-extra');
|
|
|
11
11
|
require('vite');
|
|
12
12
|
require('jsdom');
|
|
13
13
|
require('../shared/vite-react-ssg.bee8a5a9.cjs');
|
|
14
|
+
require('../shared/vite-react-ssg.0408f7e1.cjs');
|
|
14
15
|
require('node:fs');
|
|
15
16
|
require('react');
|
|
16
17
|
require('react-helmet-async');
|
|
17
18
|
require('node:stream');
|
|
18
19
|
require('react-dom/server');
|
|
20
|
+
require('react-router-dom');
|
|
21
|
+
require('node:events');
|
|
19
22
|
|
|
20
23
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
21
24
|
|
package/dist/node/cli.mjs
CHANGED
|
@@ -9,11 +9,14 @@ import 'fs-extra';
|
|
|
9
9
|
import 'vite';
|
|
10
10
|
import 'jsdom';
|
|
11
11
|
import '../shared/vite-react-ssg.579feabb.mjs';
|
|
12
|
+
import '../shared/vite-react-ssg.054e813a.mjs';
|
|
12
13
|
import 'node:fs';
|
|
13
14
|
import 'react';
|
|
14
15
|
import 'react-helmet-async';
|
|
15
16
|
import 'node:stream';
|
|
16
17
|
import 'react-dom/server';
|
|
18
|
+
import 'react-router-dom';
|
|
19
|
+
import 'node:events';
|
|
17
20
|
|
|
18
21
|
function installGlobals() {
|
|
19
22
|
global.Headers = Headers;
|
package/dist/node.cjs
CHANGED
|
@@ -7,11 +7,14 @@ const fs = require('fs-extra');
|
|
|
7
7
|
const vite = require('vite');
|
|
8
8
|
const JSDOM = require('jsdom');
|
|
9
9
|
const state = require('./shared/vite-react-ssg.bee8a5a9.cjs');
|
|
10
|
+
const remixRouter = require('./shared/vite-react-ssg.0408f7e1.cjs');
|
|
10
11
|
const node_fs = require('node:fs');
|
|
11
12
|
const React = require('react');
|
|
12
13
|
const reactHelmetAsync = require('react-helmet-async');
|
|
13
14
|
const node_stream = require('node:stream');
|
|
14
15
|
const server = require('react-dom/server');
|
|
16
|
+
const reactRouterDom = require('react-router-dom');
|
|
17
|
+
const node_events = require('node:events');
|
|
15
18
|
|
|
16
19
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
17
20
|
|
|
@@ -885,6 +888,10 @@ async function routesToPaths(routes) {
|
|
|
885
888
|
}
|
|
886
889
|
if (route.index)
|
|
887
890
|
addEntry(prefix, route.entry);
|
|
891
|
+
if (route.index && !path) {
|
|
892
|
+
addEntry("/", route.entry);
|
|
893
|
+
paths.add("/");
|
|
894
|
+
}
|
|
888
895
|
if (Array.isArray(route.children))
|
|
889
896
|
await getPaths(route.children, path);
|
|
890
897
|
}
|
|
@@ -919,23 +926,6 @@ function createRequest(path) {
|
|
|
919
926
|
url.pathname = path;
|
|
920
927
|
return new Request(url.href);
|
|
921
928
|
}
|
|
922
|
-
function joinUrlSegments(a, b) {
|
|
923
|
-
if (!a || !b)
|
|
924
|
-
return a || b || "";
|
|
925
|
-
if (a[a.length - 1] === "/")
|
|
926
|
-
a = a.substring(0, a.length - 1);
|
|
927
|
-
if (b[0] !== "/")
|
|
928
|
-
b = `/${b}`;
|
|
929
|
-
return a + b;
|
|
930
|
-
}
|
|
931
|
-
function removeLeadingSlash(str) {
|
|
932
|
-
return str[0] === "/" ? str.slice(1) : str;
|
|
933
|
-
}
|
|
934
|
-
function withTrailingSlash(path) {
|
|
935
|
-
if (path[path.length - 1] !== "/")
|
|
936
|
-
return `${path}/`;
|
|
937
|
-
return path;
|
|
938
|
-
}
|
|
939
929
|
const dynamicRE = /[:*?]/;
|
|
940
930
|
function isDynamicSegmentsRoute(route) {
|
|
941
931
|
if (!route)
|
|
@@ -1050,6 +1040,7 @@ function extractHelmet(context, styleCollector) {
|
|
|
1050
1040
|
return { htmlAttributes, bodyAttributes, metaAttributes, styleTag };
|
|
1051
1041
|
}
|
|
1052
1042
|
|
|
1043
|
+
const SCRIPT_COMMENT_PLACEHOLDER = "/* SCRIPT_COMMENT_PLACEHOLDER */";
|
|
1053
1044
|
async function renderHTML({
|
|
1054
1045
|
rootContainerId,
|
|
1055
1046
|
indexHTML,
|
|
@@ -1061,6 +1052,8 @@ async function renderHTML({
|
|
|
1061
1052
|
}) {
|
|
1062
1053
|
const stateScript = initialState ? `
|
|
1063
1054
|
<script>window.__INITIAL_STATE__=${initialState}<\/script>` : "";
|
|
1055
|
+
const scriptPlaceHolder = `
|
|
1056
|
+
<script>${SCRIPT_COMMENT_PLACEHOLDER}<\/script>`;
|
|
1064
1057
|
const headStartTag = "<head>";
|
|
1065
1058
|
const metaTags = metaAttributes.join("");
|
|
1066
1059
|
indexHTML = indexHTML.replace(headStartTag, headStartTag + metaTags);
|
|
@@ -1072,7 +1065,7 @@ async function renderHTML({
|
|
|
1072
1065
|
if (indexHTML.includes(container)) {
|
|
1073
1066
|
return indexHTML.replace(
|
|
1074
1067
|
container,
|
|
1075
|
-
`<div id="${rootContainerId}" data-server-rendered="true">${appHTML}</div>${stateScript}`
|
|
1068
|
+
`<div id="${rootContainerId}" data-server-rendered="true">${appHTML}</div>${stateScript}${scriptPlaceHolder}`
|
|
1076
1069
|
);
|
|
1077
1070
|
}
|
|
1078
1071
|
const html5Parser = await import('html5parser');
|
|
@@ -1166,7 +1159,8 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1166
1159
|
const config = await vite.resolveConfig(viteConfig, "build", mode, mode);
|
|
1167
1160
|
const cwd = process.cwd();
|
|
1168
1161
|
const root = config.root || cwd;
|
|
1169
|
-
const
|
|
1162
|
+
const hash = Math.random().toString(36).substring(2, 12);
|
|
1163
|
+
const ssgOut = node_path.join(root, ".vite-react-ssg-temp", hash);
|
|
1170
1164
|
const outDir = config.build.outDir || "dist";
|
|
1171
1165
|
const out = node_path.isAbsolute(outDir) ? outDir : node_path.join(root, outDir);
|
|
1172
1166
|
const configBase = config.base;
|
|
@@ -1188,6 +1182,13 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1188
1182
|
} = Object.assign({}, config.ssgOptions || {}, ssgOptions);
|
|
1189
1183
|
if (fs__default.existsSync(ssgOut))
|
|
1190
1184
|
await fs__default.remove(ssgOut);
|
|
1185
|
+
const clientLogger = vite.createLogger();
|
|
1186
|
+
const loggerWarn = clientLogger.warn;
|
|
1187
|
+
clientLogger.warn = (msg, options) => {
|
|
1188
|
+
if (msg.includes("vite:resolve") && msg.includes("externalized for browser compatibility"))
|
|
1189
|
+
return;
|
|
1190
|
+
loggerWarn(msg, options);
|
|
1191
|
+
};
|
|
1191
1192
|
buildLog("Build for client...");
|
|
1192
1193
|
await vite.build(vite.mergeConfig(viteConfig, {
|
|
1193
1194
|
build: {
|
|
@@ -1205,7 +1206,9 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1205
1206
|
}
|
|
1206
1207
|
}
|
|
1207
1208
|
},
|
|
1208
|
-
|
|
1209
|
+
customLogger: clientLogger,
|
|
1210
|
+
mode: config.mode,
|
|
1211
|
+
ssr: { noExternal: ["vite-react-ssg"] }
|
|
1209
1212
|
}));
|
|
1210
1213
|
if (mock) {
|
|
1211
1214
|
const { jsdomGlobal } = await import('./chunks/jsdomGlobal.cjs');
|
|
@@ -1230,7 +1233,8 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1230
1233
|
}
|
|
1231
1234
|
}
|
|
1232
1235
|
},
|
|
1233
|
-
mode: config.mode
|
|
1236
|
+
mode: config.mode,
|
|
1237
|
+
ssr: { noExternal: ["vite-react-ssg"] }
|
|
1234
1238
|
}));
|
|
1235
1239
|
const prefix = format === "esm" && process.platform === "win32" ? "file://" : "";
|
|
1236
1240
|
const ext = format === "esm" ? ".mjs" : ".cjs";
|
|
@@ -1254,6 +1258,7 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1254
1258
|
indexHTML = rewriteScripts(indexHTML, script);
|
|
1255
1259
|
const queue = new PQueue({ concurrency });
|
|
1256
1260
|
const crittersQueue = new PQueue({ concurrency: 1 });
|
|
1261
|
+
const staticLoaderDataManifest = {};
|
|
1257
1262
|
for (const path of routesPaths) {
|
|
1258
1263
|
queue.add(async () => {
|
|
1259
1264
|
try {
|
|
@@ -1261,9 +1266,10 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1261
1266
|
const { initialState, base, routes: routes2, triggerOnSSRAppRendered, transformState = state.serializeState, getStyleCollector, app } = appCtx;
|
|
1262
1267
|
const styleCollector = getStyleCollector ? await getStyleCollector() : null;
|
|
1263
1268
|
const transformedIndexHTML = await onBeforePageRender?.(path, indexHTML, appCtx) || indexHTML;
|
|
1264
|
-
const fetchUrl = `${withTrailingSlash(base)}${removeLeadingSlash(path)}`;
|
|
1269
|
+
const fetchUrl = `${remixRouter.withTrailingSlash(base)}${remixRouter.removeLeadingSlash(path)}`;
|
|
1265
1270
|
const request = createRequest(fetchUrl);
|
|
1266
|
-
const { appHTML, bodyAttributes, htmlAttributes, metaAttributes, styleTag } = await render(app ?? [...routes2], request, styleCollector, base);
|
|
1271
|
+
const { appHTML, bodyAttributes, htmlAttributes, metaAttributes, styleTag, routerContext } = await render(app ?? [...routes2], request, styleCollector, base);
|
|
1272
|
+
staticLoaderDataManifest[path] = routerContext?.loaderData;
|
|
1267
1273
|
await triggerOnSSRAppRendered?.(path, appHTML, appCtx);
|
|
1268
1274
|
const renderedHTML = await renderHTML({
|
|
1269
1275
|
rootContainerId,
|
|
@@ -1279,6 +1285,7 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1279
1285
|
renderPreloadLinks(jsdom.window.document, modules, ssrManifest);
|
|
1280
1286
|
const html = jsdom.serialize();
|
|
1281
1287
|
let transformed = await onPageRendered?.(path, html, appCtx) || html;
|
|
1288
|
+
transformed = transformed.replace(SCRIPT_COMMENT_PLACEHOLDER, `window.__VITE_REACT_SSG_HASH__ = '${hash}'`);
|
|
1282
1289
|
if (critters) {
|
|
1283
1290
|
transformed = await crittersQueue.add(() => critters.process(transformed));
|
|
1284
1291
|
transformed = transformed.replace(/<link\srel="stylesheet"/g, '<link rel="stylesheet" crossorigin');
|
|
@@ -1300,6 +1307,12 @@ ${err.stack}`);
|
|
|
1300
1307
|
});
|
|
1301
1308
|
}
|
|
1302
1309
|
await queue.start().onIdle();
|
|
1310
|
+
buildLog("Generating static loader data manifest...");
|
|
1311
|
+
const staticLoaderDataManifestString = JSON.stringify(staticLoaderDataManifest, null, 0);
|
|
1312
|
+
await fs__default.writeFile(node_path.join(out, `static-loader-data-manifest-${hash}.json`), staticLoaderDataManifestString);
|
|
1313
|
+
config.logger.info(
|
|
1314
|
+
`${kolorist.dim(`${outDir}/`)}${kolorist.cyan(`static-loader-data-manifest-${hash}.json`.padEnd(15, " "))} ${kolorist.dim(getSize(staticLoaderDataManifestString))}`
|
|
1315
|
+
);
|
|
1303
1316
|
await fs__default.remove(node_path.join(root, ".vite-react-ssg-temp"));
|
|
1304
1317
|
const pwaPlugin = config.plugins.find((i) => i.name === "vite-plugin-pwa")?.api;
|
|
1305
1318
|
if (pwaPlugin && !pwaPlugin.disabled && pwaPlugin.generateSW) {
|
|
@@ -1397,6 +1410,201 @@ function fromNodeRequest(nodeReq) {
|
|
|
1397
1410
|
};
|
|
1398
1411
|
return new Request(url.href, init);
|
|
1399
1412
|
}
|
|
1413
|
+
async function toNodeRequest(res, nodeRes) {
|
|
1414
|
+
nodeRes.statusCode = res.status;
|
|
1415
|
+
nodeRes.statusMessage = res.statusText;
|
|
1416
|
+
for (const [name, value] of res.headers) {
|
|
1417
|
+
nodeRes.setHeader(name, value);
|
|
1418
|
+
}
|
|
1419
|
+
if (res.body) {
|
|
1420
|
+
const responseBody = res.body;
|
|
1421
|
+
const readable = node_stream.Readable.from(responseBody);
|
|
1422
|
+
readable.pipe(nodeRes);
|
|
1423
|
+
await node_events.once(readable, "end");
|
|
1424
|
+
} else {
|
|
1425
|
+
nodeRes.end();
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
function ssrServerPlugin({
|
|
1430
|
+
template,
|
|
1431
|
+
ssrEntry,
|
|
1432
|
+
onBeforePageRender,
|
|
1433
|
+
entry,
|
|
1434
|
+
rootContainerId,
|
|
1435
|
+
onPageRendered
|
|
1436
|
+
}) {
|
|
1437
|
+
return {
|
|
1438
|
+
name: "vite-react-ssg:dev-server-remix",
|
|
1439
|
+
configureServer(server) {
|
|
1440
|
+
const renderMiddleware = async (req, res, _next) => {
|
|
1441
|
+
try {
|
|
1442
|
+
const url = req.originalUrl;
|
|
1443
|
+
const createRoot = await server.ssrLoadModule(ssrEntry).then((m) => m.createRoot);
|
|
1444
|
+
const appCtx = await createRoot(false, url);
|
|
1445
|
+
const { routes, getStyleCollector, base, app } = appCtx;
|
|
1446
|
+
const searchParams = new URLSearchParams(url.split("?")[1]);
|
|
1447
|
+
if (!app && searchParams.has("_data")) {
|
|
1448
|
+
const request = fromNodeRequest(req);
|
|
1449
|
+
const url2 = new URL(request.url);
|
|
1450
|
+
const routeId = decodeURIComponent(searchParams.get("_data"));
|
|
1451
|
+
const matches = reactRouterDom.matchRoutes(
|
|
1452
|
+
remixRouter.convertRoutesToDataRoutes([...routes], (route) => route),
|
|
1453
|
+
{
|
|
1454
|
+
pathname: url2.pathname,
|
|
1455
|
+
search: url2.search,
|
|
1456
|
+
hash: url2.hash,
|
|
1457
|
+
state: null,
|
|
1458
|
+
key: "default"
|
|
1459
|
+
},
|
|
1460
|
+
base
|
|
1461
|
+
);
|
|
1462
|
+
if (!matches) {
|
|
1463
|
+
res.statusCode = 404;
|
|
1464
|
+
res.end(`Route not found: ${routeId}`);
|
|
1465
|
+
return;
|
|
1466
|
+
}
|
|
1467
|
+
const match = matches.find((m) => m.route.id === routeId);
|
|
1468
|
+
if (!match) {
|
|
1469
|
+
res.statusCode = 404;
|
|
1470
|
+
res.end(`Route not found: ${routeId}`);
|
|
1471
|
+
return;
|
|
1472
|
+
}
|
|
1473
|
+
const loader = match.route.loader ?? await match.route.lazy?.().then((m) => m.loader);
|
|
1474
|
+
if (!loader) {
|
|
1475
|
+
res.statusCode = 200;
|
|
1476
|
+
res.end(`There is no loader for the route: ${routeId}`);
|
|
1477
|
+
return;
|
|
1478
|
+
}
|
|
1479
|
+
const response = await callRouteLoader({
|
|
1480
|
+
loader,
|
|
1481
|
+
params: match.params,
|
|
1482
|
+
request,
|
|
1483
|
+
routeId
|
|
1484
|
+
});
|
|
1485
|
+
await toNodeRequest(response, res);
|
|
1486
|
+
return;
|
|
1487
|
+
}
|
|
1488
|
+
const indexHTML = await server.transformIndexHtml(url, template);
|
|
1489
|
+
const transformedIndexHTML = await onBeforePageRender?.(url, indexHTML, appCtx) || indexHTML;
|
|
1490
|
+
const styleCollector = getStyleCollector ? await getStyleCollector() : null;
|
|
1491
|
+
const { appHTML, bodyAttributes, htmlAttributes, metaAttributes, styleTag, routerContext } = await render(app ?? [...routes], fromNodeRequest(req), styleCollector, base);
|
|
1492
|
+
metaAttributes.push(styleTag);
|
|
1493
|
+
const matchesEntries = routerContext?.matches.map((match) => match.route.entry).filter((entry2) => !!entry2).map((entry2) => entry2[0] === "/" ? entry2 : `/${entry2}`) ?? [];
|
|
1494
|
+
const mods = await Promise.all(
|
|
1495
|
+
[ssrEntry, entry, ...matchesEntries].map(async (entry2) => await server.moduleGraph.getModuleByUrl(entry2))
|
|
1496
|
+
);
|
|
1497
|
+
const assetsUrls = /* @__PURE__ */ new Set();
|
|
1498
|
+
const collectAssets = async (mod) => {
|
|
1499
|
+
if (!mod || !mod?.ssrTransformResult)
|
|
1500
|
+
return;
|
|
1501
|
+
const { deps = [], dynamicDeps = [] } = mod?.ssrTransformResult;
|
|
1502
|
+
const allDeps = [...deps, ...dynamicDeps];
|
|
1503
|
+
for (const dep of allDeps) {
|
|
1504
|
+
if (dep.endsWith(".css")) {
|
|
1505
|
+
assetsUrls.add(dep);
|
|
1506
|
+
} else if (dep.endsWith(".ts") || dep.endsWith(".tsx")) {
|
|
1507
|
+
const depModule = await server.moduleGraph.getModuleByUrl(dep);
|
|
1508
|
+
depModule && await collectAssets(depModule);
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
};
|
|
1512
|
+
await Promise.all(mods.map(async (mod) => collectAssets(mod)));
|
|
1513
|
+
const preloadLink = [...assetsUrls].map((item) => createLink$1(remixRouter.joinUrlSegments(server.config.base, item)));
|
|
1514
|
+
metaAttributes.push(...preloadLink);
|
|
1515
|
+
const renderedHTML = await renderHTML({
|
|
1516
|
+
rootContainerId,
|
|
1517
|
+
appHTML,
|
|
1518
|
+
indexHTML: transformedIndexHTML,
|
|
1519
|
+
metaAttributes,
|
|
1520
|
+
bodyAttributes,
|
|
1521
|
+
htmlAttributes,
|
|
1522
|
+
initialState: null
|
|
1523
|
+
});
|
|
1524
|
+
const transformed = await onPageRendered?.(url, renderedHTML, appCtx) || renderedHTML;
|
|
1525
|
+
res.statusCode = 200;
|
|
1526
|
+
res.setHeader("Content-Type", "text/html");
|
|
1527
|
+
const isDev = "pluginContainer" in server;
|
|
1528
|
+
const headers = isDev ? server.config.server.headers : server.config.preview.headers;
|
|
1529
|
+
vite.send(req, res, transformed, "html", { headers });
|
|
1530
|
+
} catch (e) {
|
|
1531
|
+
server.ssrFixStacktrace(e);
|
|
1532
|
+
console.error(`[vite-react-ssg] error: ${e.stack}`);
|
|
1533
|
+
res.statusCode = 500;
|
|
1534
|
+
res.end(e.stack);
|
|
1535
|
+
}
|
|
1536
|
+
};
|
|
1537
|
+
return () => {
|
|
1538
|
+
server.middlewares.use(renderMiddleware);
|
|
1539
|
+
};
|
|
1540
|
+
}
|
|
1541
|
+
};
|
|
1542
|
+
}
|
|
1543
|
+
async function callRouteLoader({
|
|
1544
|
+
// loadContext,
|
|
1545
|
+
loader,
|
|
1546
|
+
params,
|
|
1547
|
+
request,
|
|
1548
|
+
routeId
|
|
1549
|
+
// singleFetch,
|
|
1550
|
+
// response,
|
|
1551
|
+
}) {
|
|
1552
|
+
const result = await loader({
|
|
1553
|
+
request: stripDataParam(stripIndexParam(request)),
|
|
1554
|
+
// context: loadContext,
|
|
1555
|
+
params
|
|
1556
|
+
// Only provided when single fetch is enabled, and made available via
|
|
1557
|
+
// `defineLoader` types, not `LoaderFunctionArgs`
|
|
1558
|
+
// ...(singleFetch ? { response } : null),
|
|
1559
|
+
});
|
|
1560
|
+
if (result === void 0) {
|
|
1561
|
+
throw new Error(
|
|
1562
|
+
`You defined a loader for route "${routeId}" but didn't return anything from your \`loader\` function. Please return a value or \`null\`.`
|
|
1563
|
+
);
|
|
1564
|
+
}
|
|
1565
|
+
return isResponse(result) ? result : reactRouterDom.json(result);
|
|
1566
|
+
}
|
|
1567
|
+
function isResponse(value) {
|
|
1568
|
+
return value != null && typeof value.status === "number" && typeof value.statusText === "string" && typeof value.headers === "object" && typeof value.body !== "undefined";
|
|
1569
|
+
}
|
|
1570
|
+
function stripIndexParam(request) {
|
|
1571
|
+
const url = new URL(request.url);
|
|
1572
|
+
const indexValues = url.searchParams.getAll("index");
|
|
1573
|
+
url.searchParams.delete("index");
|
|
1574
|
+
const indexValuesToKeep = [];
|
|
1575
|
+
for (const indexValue of indexValues) {
|
|
1576
|
+
if (indexValue) {
|
|
1577
|
+
indexValuesToKeep.push(indexValue);
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
for (const toKeep of indexValuesToKeep) {
|
|
1581
|
+
url.searchParams.append("index", toKeep);
|
|
1582
|
+
}
|
|
1583
|
+
const init = {
|
|
1584
|
+
method: request.method,
|
|
1585
|
+
body: request.body,
|
|
1586
|
+
headers: request.headers,
|
|
1587
|
+
signal: request.signal
|
|
1588
|
+
};
|
|
1589
|
+
if (init.body) {
|
|
1590
|
+
init.duplex = "half";
|
|
1591
|
+
}
|
|
1592
|
+
return new Request(url.href, init);
|
|
1593
|
+
}
|
|
1594
|
+
function stripDataParam(request) {
|
|
1595
|
+
const url = new URL(request.url);
|
|
1596
|
+
url.searchParams.delete("_data");
|
|
1597
|
+
const init = {
|
|
1598
|
+
method: request.method,
|
|
1599
|
+
body: request.body,
|
|
1600
|
+
headers: request.headers,
|
|
1601
|
+
signal: request.signal
|
|
1602
|
+
};
|
|
1603
|
+
if (init.body) {
|
|
1604
|
+
init.duplex = "half";
|
|
1605
|
+
}
|
|
1606
|
+
return new Request(url.href, init);
|
|
1607
|
+
}
|
|
1400
1608
|
|
|
1401
1609
|
async function dev(ssgOptions = {}, viteConfig = {}, customOptions) {
|
|
1402
1610
|
const mode = process.env.MODE || process.env.NODE_ENV || ssgOptions.mode || "development";
|
|
@@ -1431,68 +1639,14 @@ ${err.stack}`
|
|
|
1431
1639
|
...viteConfig,
|
|
1432
1640
|
plugins: [
|
|
1433
1641
|
...viteConfig.plugins ?? [],
|
|
1434
|
-
{
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
const createRoot = await viteServer.ssrLoadModule(ssrEntry).then((m) => m.createRoot);
|
|
1443
|
-
const appCtx = await createRoot(false, url);
|
|
1444
|
-
const { routes, getStyleCollector, base, app } = appCtx;
|
|
1445
|
-
const transformedIndexHTML = await onBeforePageRender?.(url, indexHTML, appCtx) || indexHTML;
|
|
1446
|
-
const styleCollector = getStyleCollector ? await getStyleCollector() : null;
|
|
1447
|
-
const { appHTML, bodyAttributes, htmlAttributes, metaAttributes, styleTag, routerContext } = await render(app ?? [...routes], fromNodeRequest(req), styleCollector, base);
|
|
1448
|
-
metaAttributes.push(styleTag);
|
|
1449
|
-
const matchesEntries = routerContext?.matches.map((match) => match.route.entry).filter((entry2) => !!entry2).map((entry2) => entry2[0] === "/" ? entry2 : `/${entry2}`) ?? [];
|
|
1450
|
-
const mods = await Promise.all(
|
|
1451
|
-
[ssrEntry, entry, ...matchesEntries].map(async (entry2) => await viteServer.moduleGraph.getModuleByUrl(entry2))
|
|
1452
|
-
);
|
|
1453
|
-
const assetsUrls = /* @__PURE__ */ new Set();
|
|
1454
|
-
const collectAssets = async (mod) => {
|
|
1455
|
-
if (!mod || !mod?.ssrTransformResult)
|
|
1456
|
-
return;
|
|
1457
|
-
const { deps = [], dynamicDeps = [] } = mod?.ssrTransformResult;
|
|
1458
|
-
const allDeps = [...deps, ...dynamicDeps];
|
|
1459
|
-
for (const dep of allDeps) {
|
|
1460
|
-
if (dep.endsWith(".css")) {
|
|
1461
|
-
assetsUrls.add(dep);
|
|
1462
|
-
} else if (dep.endsWith(".ts") || dep.endsWith(".tsx")) {
|
|
1463
|
-
const depModule = await viteServer.moduleGraph.getModuleByUrl(dep);
|
|
1464
|
-
depModule && await collectAssets(depModule);
|
|
1465
|
-
}
|
|
1466
|
-
}
|
|
1467
|
-
};
|
|
1468
|
-
await Promise.all(mods.map(async (mod) => collectAssets(mod)));
|
|
1469
|
-
const preloadLink = [...assetsUrls].map((item) => createLink$1(joinUrlSegments(config.base, item)));
|
|
1470
|
-
metaAttributes.push(...preloadLink);
|
|
1471
|
-
const renderedHTML = await renderHTML({
|
|
1472
|
-
rootContainerId,
|
|
1473
|
-
appHTML,
|
|
1474
|
-
indexHTML: transformedIndexHTML,
|
|
1475
|
-
metaAttributes,
|
|
1476
|
-
bodyAttributes,
|
|
1477
|
-
htmlAttributes,
|
|
1478
|
-
initialState: null
|
|
1479
|
-
});
|
|
1480
|
-
const transformed = await onPageRendered?.(url, renderedHTML, appCtx) || renderedHTML;
|
|
1481
|
-
res.statusCode = 200;
|
|
1482
|
-
res.setHeader("Content-Type", "text/html");
|
|
1483
|
-
const isDev = "pluginContainer" in server;
|
|
1484
|
-
const headers = isDev ? server.config.server.headers : server.config.preview.headers;
|
|
1485
|
-
vite.send(req, res, transformed, "html", { headers });
|
|
1486
|
-
} catch (e) {
|
|
1487
|
-
viteServer.ssrFixStacktrace(e);
|
|
1488
|
-
console.error(`[vite-react-ssg] error: ${e.stack}`);
|
|
1489
|
-
res.statusCode = 500;
|
|
1490
|
-
res.end(e.stack);
|
|
1491
|
-
}
|
|
1492
|
-
});
|
|
1493
|
-
};
|
|
1494
|
-
}
|
|
1495
|
-
}
|
|
1642
|
+
ssrServerPlugin({
|
|
1643
|
+
template,
|
|
1644
|
+
ssrEntry,
|
|
1645
|
+
onBeforePageRender,
|
|
1646
|
+
onPageRendered,
|
|
1647
|
+
entry,
|
|
1648
|
+
rootContainerId
|
|
1649
|
+
})
|
|
1496
1650
|
]
|
|
1497
1651
|
});
|
|
1498
1652
|
await viteServer.listen();
|
package/dist/node.mjs
CHANGED
|
@@ -2,14 +2,17 @@ import { join, isAbsolute, parse, dirname } from 'node:path';
|
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
3
|
import { gray, yellow, blue, dim, cyan, red, green, reset, bold, bgLightCyan } from 'kolorist';
|
|
4
4
|
import fs from 'fs-extra';
|
|
5
|
-
import { resolveConfig, build as build$1, mergeConfig, version as version$1,
|
|
5
|
+
import { resolveConfig, createLogger, build as build$1, mergeConfig, version as version$1, send, createServer } from 'vite';
|
|
6
6
|
import { JSDOM } from 'jsdom';
|
|
7
7
|
import { s as serializeState } from './shared/vite-react-ssg.579feabb.mjs';
|
|
8
|
+
import { a as withTrailingSlash, r as removeLeadingSlash, c as convertRoutesToDataRoutes, j as joinUrlSegments } from './shared/vite-react-ssg.054e813a.mjs';
|
|
8
9
|
import { readFileSync } from 'node:fs';
|
|
9
10
|
import React from 'react';
|
|
10
11
|
import { HelmetProvider } from 'react-helmet-async';
|
|
11
|
-
import { Writable } from 'node:stream';
|
|
12
|
+
import { Writable, Readable } from 'node:stream';
|
|
12
13
|
import { renderToPipeableStream } from 'react-dom/server';
|
|
14
|
+
import { matchRoutes, json } from 'react-router-dom';
|
|
15
|
+
import { once } from 'node:events';
|
|
13
16
|
|
|
14
17
|
function getDefaultExportFromCjs (x) {
|
|
15
18
|
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
@@ -878,6 +881,10 @@ async function routesToPaths(routes) {
|
|
|
878
881
|
}
|
|
879
882
|
if (route.index)
|
|
880
883
|
addEntry(prefix, route.entry);
|
|
884
|
+
if (route.index && !path) {
|
|
885
|
+
addEntry("/", route.entry);
|
|
886
|
+
paths.add("/");
|
|
887
|
+
}
|
|
881
888
|
if (Array.isArray(route.children))
|
|
882
889
|
await getPaths(route.children, path);
|
|
883
890
|
}
|
|
@@ -912,23 +919,6 @@ function createRequest(path) {
|
|
|
912
919
|
url.pathname = path;
|
|
913
920
|
return new Request(url.href);
|
|
914
921
|
}
|
|
915
|
-
function joinUrlSegments(a, b) {
|
|
916
|
-
if (!a || !b)
|
|
917
|
-
return a || b || "";
|
|
918
|
-
if (a[a.length - 1] === "/")
|
|
919
|
-
a = a.substring(0, a.length - 1);
|
|
920
|
-
if (b[0] !== "/")
|
|
921
|
-
b = `/${b}`;
|
|
922
|
-
return a + b;
|
|
923
|
-
}
|
|
924
|
-
function removeLeadingSlash(str) {
|
|
925
|
-
return str[0] === "/" ? str.slice(1) : str;
|
|
926
|
-
}
|
|
927
|
-
function withTrailingSlash(path) {
|
|
928
|
-
if (path[path.length - 1] !== "/")
|
|
929
|
-
return `${path}/`;
|
|
930
|
-
return path;
|
|
931
|
-
}
|
|
932
922
|
const dynamicRE = /[:*?]/;
|
|
933
923
|
function isDynamicSegmentsRoute(route) {
|
|
934
924
|
if (!route)
|
|
@@ -1043,6 +1033,7 @@ function extractHelmet(context, styleCollector) {
|
|
|
1043
1033
|
return { htmlAttributes, bodyAttributes, metaAttributes, styleTag };
|
|
1044
1034
|
}
|
|
1045
1035
|
|
|
1036
|
+
const SCRIPT_COMMENT_PLACEHOLDER = "/* SCRIPT_COMMENT_PLACEHOLDER */";
|
|
1046
1037
|
async function renderHTML({
|
|
1047
1038
|
rootContainerId,
|
|
1048
1039
|
indexHTML,
|
|
@@ -1054,6 +1045,8 @@ async function renderHTML({
|
|
|
1054
1045
|
}) {
|
|
1055
1046
|
const stateScript = initialState ? `
|
|
1056
1047
|
<script>window.__INITIAL_STATE__=${initialState}<\/script>` : "";
|
|
1048
|
+
const scriptPlaceHolder = `
|
|
1049
|
+
<script>${SCRIPT_COMMENT_PLACEHOLDER}<\/script>`;
|
|
1057
1050
|
const headStartTag = "<head>";
|
|
1058
1051
|
const metaTags = metaAttributes.join("");
|
|
1059
1052
|
indexHTML = indexHTML.replace(headStartTag, headStartTag + metaTags);
|
|
@@ -1065,7 +1058,7 @@ async function renderHTML({
|
|
|
1065
1058
|
if (indexHTML.includes(container)) {
|
|
1066
1059
|
return indexHTML.replace(
|
|
1067
1060
|
container,
|
|
1068
|
-
`<div id="${rootContainerId}" data-server-rendered="true">${appHTML}</div>${stateScript}`
|
|
1061
|
+
`<div id="${rootContainerId}" data-server-rendered="true">${appHTML}</div>${stateScript}${scriptPlaceHolder}`
|
|
1069
1062
|
);
|
|
1070
1063
|
}
|
|
1071
1064
|
const html5Parser = await import('html5parser');
|
|
@@ -1159,7 +1152,8 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1159
1152
|
const config = await resolveConfig(viteConfig, "build", mode, mode);
|
|
1160
1153
|
const cwd = process.cwd();
|
|
1161
1154
|
const root = config.root || cwd;
|
|
1162
|
-
const
|
|
1155
|
+
const hash = Math.random().toString(36).substring(2, 12);
|
|
1156
|
+
const ssgOut = join(root, ".vite-react-ssg-temp", hash);
|
|
1163
1157
|
const outDir = config.build.outDir || "dist";
|
|
1164
1158
|
const out = isAbsolute(outDir) ? outDir : join(root, outDir);
|
|
1165
1159
|
const configBase = config.base;
|
|
@@ -1181,6 +1175,13 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1181
1175
|
} = Object.assign({}, config.ssgOptions || {}, ssgOptions);
|
|
1182
1176
|
if (fs.existsSync(ssgOut))
|
|
1183
1177
|
await fs.remove(ssgOut);
|
|
1178
|
+
const clientLogger = createLogger();
|
|
1179
|
+
const loggerWarn = clientLogger.warn;
|
|
1180
|
+
clientLogger.warn = (msg, options) => {
|
|
1181
|
+
if (msg.includes("vite:resolve") && msg.includes("externalized for browser compatibility"))
|
|
1182
|
+
return;
|
|
1183
|
+
loggerWarn(msg, options);
|
|
1184
|
+
};
|
|
1184
1185
|
buildLog("Build for client...");
|
|
1185
1186
|
await build$1(mergeConfig(viteConfig, {
|
|
1186
1187
|
build: {
|
|
@@ -1198,7 +1199,9 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1198
1199
|
}
|
|
1199
1200
|
}
|
|
1200
1201
|
},
|
|
1201
|
-
|
|
1202
|
+
customLogger: clientLogger,
|
|
1203
|
+
mode: config.mode,
|
|
1204
|
+
ssr: { noExternal: ["vite-react-ssg"] }
|
|
1202
1205
|
}));
|
|
1203
1206
|
if (mock) {
|
|
1204
1207
|
const { jsdomGlobal } = await import('./chunks/jsdomGlobal.mjs');
|
|
@@ -1223,7 +1226,8 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1223
1226
|
}
|
|
1224
1227
|
}
|
|
1225
1228
|
},
|
|
1226
|
-
mode: config.mode
|
|
1229
|
+
mode: config.mode,
|
|
1230
|
+
ssr: { noExternal: ["vite-react-ssg"] }
|
|
1227
1231
|
}));
|
|
1228
1232
|
const prefix = format === "esm" && process.platform === "win32" ? "file://" : "";
|
|
1229
1233
|
const ext = format === "esm" ? ".mjs" : ".cjs";
|
|
@@ -1247,6 +1251,7 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1247
1251
|
indexHTML = rewriteScripts(indexHTML, script);
|
|
1248
1252
|
const queue = new PQueue({ concurrency });
|
|
1249
1253
|
const crittersQueue = new PQueue({ concurrency: 1 });
|
|
1254
|
+
const staticLoaderDataManifest = {};
|
|
1250
1255
|
for (const path of routesPaths) {
|
|
1251
1256
|
queue.add(async () => {
|
|
1252
1257
|
try {
|
|
@@ -1256,7 +1261,8 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1256
1261
|
const transformedIndexHTML = await onBeforePageRender?.(path, indexHTML, appCtx) || indexHTML;
|
|
1257
1262
|
const fetchUrl = `${withTrailingSlash(base)}${removeLeadingSlash(path)}`;
|
|
1258
1263
|
const request = createRequest(fetchUrl);
|
|
1259
|
-
const { appHTML, bodyAttributes, htmlAttributes, metaAttributes, styleTag } = await render(app ?? [...routes2], request, styleCollector, base);
|
|
1264
|
+
const { appHTML, bodyAttributes, htmlAttributes, metaAttributes, styleTag, routerContext } = await render(app ?? [...routes2], request, styleCollector, base);
|
|
1265
|
+
staticLoaderDataManifest[path] = routerContext?.loaderData;
|
|
1260
1266
|
await triggerOnSSRAppRendered?.(path, appHTML, appCtx);
|
|
1261
1267
|
const renderedHTML = await renderHTML({
|
|
1262
1268
|
rootContainerId,
|
|
@@ -1272,6 +1278,7 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1272
1278
|
renderPreloadLinks(jsdom.window.document, modules, ssrManifest);
|
|
1273
1279
|
const html = jsdom.serialize();
|
|
1274
1280
|
let transformed = await onPageRendered?.(path, html, appCtx) || html;
|
|
1281
|
+
transformed = transformed.replace(SCRIPT_COMMENT_PLACEHOLDER, `window.__VITE_REACT_SSG_HASH__ = '${hash}'`);
|
|
1275
1282
|
if (critters) {
|
|
1276
1283
|
transformed = await crittersQueue.add(() => critters.process(transformed));
|
|
1277
1284
|
transformed = transformed.replace(/<link\srel="stylesheet"/g, '<link rel="stylesheet" crossorigin');
|
|
@@ -1293,6 +1300,12 @@ ${err.stack}`);
|
|
|
1293
1300
|
});
|
|
1294
1301
|
}
|
|
1295
1302
|
await queue.start().onIdle();
|
|
1303
|
+
buildLog("Generating static loader data manifest...");
|
|
1304
|
+
const staticLoaderDataManifestString = JSON.stringify(staticLoaderDataManifest, null, 0);
|
|
1305
|
+
await fs.writeFile(join(out, `static-loader-data-manifest-${hash}.json`), staticLoaderDataManifestString);
|
|
1306
|
+
config.logger.info(
|
|
1307
|
+
`${dim(`${outDir}/`)}${cyan(`static-loader-data-manifest-${hash}.json`.padEnd(15, " "))} ${dim(getSize(staticLoaderDataManifestString))}`
|
|
1308
|
+
);
|
|
1296
1309
|
await fs.remove(join(root, ".vite-react-ssg-temp"));
|
|
1297
1310
|
const pwaPlugin = config.plugins.find((i) => i.name === "vite-plugin-pwa")?.api;
|
|
1298
1311
|
if (pwaPlugin && !pwaPlugin.disabled && pwaPlugin.generateSW) {
|
|
@@ -1390,6 +1403,201 @@ function fromNodeRequest(nodeReq) {
|
|
|
1390
1403
|
};
|
|
1391
1404
|
return new Request(url.href, init);
|
|
1392
1405
|
}
|
|
1406
|
+
async function toNodeRequest(res, nodeRes) {
|
|
1407
|
+
nodeRes.statusCode = res.status;
|
|
1408
|
+
nodeRes.statusMessage = res.statusText;
|
|
1409
|
+
for (const [name, value] of res.headers) {
|
|
1410
|
+
nodeRes.setHeader(name, value);
|
|
1411
|
+
}
|
|
1412
|
+
if (res.body) {
|
|
1413
|
+
const responseBody = res.body;
|
|
1414
|
+
const readable = Readable.from(responseBody);
|
|
1415
|
+
readable.pipe(nodeRes);
|
|
1416
|
+
await once(readable, "end");
|
|
1417
|
+
} else {
|
|
1418
|
+
nodeRes.end();
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
function ssrServerPlugin({
|
|
1423
|
+
template,
|
|
1424
|
+
ssrEntry,
|
|
1425
|
+
onBeforePageRender,
|
|
1426
|
+
entry,
|
|
1427
|
+
rootContainerId,
|
|
1428
|
+
onPageRendered
|
|
1429
|
+
}) {
|
|
1430
|
+
return {
|
|
1431
|
+
name: "vite-react-ssg:dev-server-remix",
|
|
1432
|
+
configureServer(server) {
|
|
1433
|
+
const renderMiddleware = async (req, res, _next) => {
|
|
1434
|
+
try {
|
|
1435
|
+
const url = req.originalUrl;
|
|
1436
|
+
const createRoot = await server.ssrLoadModule(ssrEntry).then((m) => m.createRoot);
|
|
1437
|
+
const appCtx = await createRoot(false, url);
|
|
1438
|
+
const { routes, getStyleCollector, base, app } = appCtx;
|
|
1439
|
+
const searchParams = new URLSearchParams(url.split("?")[1]);
|
|
1440
|
+
if (!app && searchParams.has("_data")) {
|
|
1441
|
+
const request = fromNodeRequest(req);
|
|
1442
|
+
const url2 = new URL(request.url);
|
|
1443
|
+
const routeId = decodeURIComponent(searchParams.get("_data"));
|
|
1444
|
+
const matches = matchRoutes(
|
|
1445
|
+
convertRoutesToDataRoutes([...routes], (route) => route),
|
|
1446
|
+
{
|
|
1447
|
+
pathname: url2.pathname,
|
|
1448
|
+
search: url2.search,
|
|
1449
|
+
hash: url2.hash,
|
|
1450
|
+
state: null,
|
|
1451
|
+
key: "default"
|
|
1452
|
+
},
|
|
1453
|
+
base
|
|
1454
|
+
);
|
|
1455
|
+
if (!matches) {
|
|
1456
|
+
res.statusCode = 404;
|
|
1457
|
+
res.end(`Route not found: ${routeId}`);
|
|
1458
|
+
return;
|
|
1459
|
+
}
|
|
1460
|
+
const match = matches.find((m) => m.route.id === routeId);
|
|
1461
|
+
if (!match) {
|
|
1462
|
+
res.statusCode = 404;
|
|
1463
|
+
res.end(`Route not found: ${routeId}`);
|
|
1464
|
+
return;
|
|
1465
|
+
}
|
|
1466
|
+
const loader = match.route.loader ?? await match.route.lazy?.().then((m) => m.loader);
|
|
1467
|
+
if (!loader) {
|
|
1468
|
+
res.statusCode = 200;
|
|
1469
|
+
res.end(`There is no loader for the route: ${routeId}`);
|
|
1470
|
+
return;
|
|
1471
|
+
}
|
|
1472
|
+
const response = await callRouteLoader({
|
|
1473
|
+
loader,
|
|
1474
|
+
params: match.params,
|
|
1475
|
+
request,
|
|
1476
|
+
routeId
|
|
1477
|
+
});
|
|
1478
|
+
await toNodeRequest(response, res);
|
|
1479
|
+
return;
|
|
1480
|
+
}
|
|
1481
|
+
const indexHTML = await server.transformIndexHtml(url, template);
|
|
1482
|
+
const transformedIndexHTML = await onBeforePageRender?.(url, indexHTML, appCtx) || indexHTML;
|
|
1483
|
+
const styleCollector = getStyleCollector ? await getStyleCollector() : null;
|
|
1484
|
+
const { appHTML, bodyAttributes, htmlAttributes, metaAttributes, styleTag, routerContext } = await render(app ?? [...routes], fromNodeRequest(req), styleCollector, base);
|
|
1485
|
+
metaAttributes.push(styleTag);
|
|
1486
|
+
const matchesEntries = routerContext?.matches.map((match) => match.route.entry).filter((entry2) => !!entry2).map((entry2) => entry2[0] === "/" ? entry2 : `/${entry2}`) ?? [];
|
|
1487
|
+
const mods = await Promise.all(
|
|
1488
|
+
[ssrEntry, entry, ...matchesEntries].map(async (entry2) => await server.moduleGraph.getModuleByUrl(entry2))
|
|
1489
|
+
);
|
|
1490
|
+
const assetsUrls = /* @__PURE__ */ new Set();
|
|
1491
|
+
const collectAssets = async (mod) => {
|
|
1492
|
+
if (!mod || !mod?.ssrTransformResult)
|
|
1493
|
+
return;
|
|
1494
|
+
const { deps = [], dynamicDeps = [] } = mod?.ssrTransformResult;
|
|
1495
|
+
const allDeps = [...deps, ...dynamicDeps];
|
|
1496
|
+
for (const dep of allDeps) {
|
|
1497
|
+
if (dep.endsWith(".css")) {
|
|
1498
|
+
assetsUrls.add(dep);
|
|
1499
|
+
} else if (dep.endsWith(".ts") || dep.endsWith(".tsx")) {
|
|
1500
|
+
const depModule = await server.moduleGraph.getModuleByUrl(dep);
|
|
1501
|
+
depModule && await collectAssets(depModule);
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
};
|
|
1505
|
+
await Promise.all(mods.map(async (mod) => collectAssets(mod)));
|
|
1506
|
+
const preloadLink = [...assetsUrls].map((item) => createLink$1(joinUrlSegments(server.config.base, item)));
|
|
1507
|
+
metaAttributes.push(...preloadLink);
|
|
1508
|
+
const renderedHTML = await renderHTML({
|
|
1509
|
+
rootContainerId,
|
|
1510
|
+
appHTML,
|
|
1511
|
+
indexHTML: transformedIndexHTML,
|
|
1512
|
+
metaAttributes,
|
|
1513
|
+
bodyAttributes,
|
|
1514
|
+
htmlAttributes,
|
|
1515
|
+
initialState: null
|
|
1516
|
+
});
|
|
1517
|
+
const transformed = await onPageRendered?.(url, renderedHTML, appCtx) || renderedHTML;
|
|
1518
|
+
res.statusCode = 200;
|
|
1519
|
+
res.setHeader("Content-Type", "text/html");
|
|
1520
|
+
const isDev = "pluginContainer" in server;
|
|
1521
|
+
const headers = isDev ? server.config.server.headers : server.config.preview.headers;
|
|
1522
|
+
send(req, res, transformed, "html", { headers });
|
|
1523
|
+
} catch (e) {
|
|
1524
|
+
server.ssrFixStacktrace(e);
|
|
1525
|
+
console.error(`[vite-react-ssg] error: ${e.stack}`);
|
|
1526
|
+
res.statusCode = 500;
|
|
1527
|
+
res.end(e.stack);
|
|
1528
|
+
}
|
|
1529
|
+
};
|
|
1530
|
+
return () => {
|
|
1531
|
+
server.middlewares.use(renderMiddleware);
|
|
1532
|
+
};
|
|
1533
|
+
}
|
|
1534
|
+
};
|
|
1535
|
+
}
|
|
1536
|
+
async function callRouteLoader({
|
|
1537
|
+
// loadContext,
|
|
1538
|
+
loader,
|
|
1539
|
+
params,
|
|
1540
|
+
request,
|
|
1541
|
+
routeId
|
|
1542
|
+
// singleFetch,
|
|
1543
|
+
// response,
|
|
1544
|
+
}) {
|
|
1545
|
+
const result = await loader({
|
|
1546
|
+
request: stripDataParam(stripIndexParam(request)),
|
|
1547
|
+
// context: loadContext,
|
|
1548
|
+
params
|
|
1549
|
+
// Only provided when single fetch is enabled, and made available via
|
|
1550
|
+
// `defineLoader` types, not `LoaderFunctionArgs`
|
|
1551
|
+
// ...(singleFetch ? { response } : null),
|
|
1552
|
+
});
|
|
1553
|
+
if (result === void 0) {
|
|
1554
|
+
throw new Error(
|
|
1555
|
+
`You defined a loader for route "${routeId}" but didn't return anything from your \`loader\` function. Please return a value or \`null\`.`
|
|
1556
|
+
);
|
|
1557
|
+
}
|
|
1558
|
+
return isResponse(result) ? result : json(result);
|
|
1559
|
+
}
|
|
1560
|
+
function isResponse(value) {
|
|
1561
|
+
return value != null && typeof value.status === "number" && typeof value.statusText === "string" && typeof value.headers === "object" && typeof value.body !== "undefined";
|
|
1562
|
+
}
|
|
1563
|
+
function stripIndexParam(request) {
|
|
1564
|
+
const url = new URL(request.url);
|
|
1565
|
+
const indexValues = url.searchParams.getAll("index");
|
|
1566
|
+
url.searchParams.delete("index");
|
|
1567
|
+
const indexValuesToKeep = [];
|
|
1568
|
+
for (const indexValue of indexValues) {
|
|
1569
|
+
if (indexValue) {
|
|
1570
|
+
indexValuesToKeep.push(indexValue);
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
for (const toKeep of indexValuesToKeep) {
|
|
1574
|
+
url.searchParams.append("index", toKeep);
|
|
1575
|
+
}
|
|
1576
|
+
const init = {
|
|
1577
|
+
method: request.method,
|
|
1578
|
+
body: request.body,
|
|
1579
|
+
headers: request.headers,
|
|
1580
|
+
signal: request.signal
|
|
1581
|
+
};
|
|
1582
|
+
if (init.body) {
|
|
1583
|
+
init.duplex = "half";
|
|
1584
|
+
}
|
|
1585
|
+
return new Request(url.href, init);
|
|
1586
|
+
}
|
|
1587
|
+
function stripDataParam(request) {
|
|
1588
|
+
const url = new URL(request.url);
|
|
1589
|
+
url.searchParams.delete("_data");
|
|
1590
|
+
const init = {
|
|
1591
|
+
method: request.method,
|
|
1592
|
+
body: request.body,
|
|
1593
|
+
headers: request.headers,
|
|
1594
|
+
signal: request.signal
|
|
1595
|
+
};
|
|
1596
|
+
if (init.body) {
|
|
1597
|
+
init.duplex = "half";
|
|
1598
|
+
}
|
|
1599
|
+
return new Request(url.href, init);
|
|
1600
|
+
}
|
|
1393
1601
|
|
|
1394
1602
|
async function dev(ssgOptions = {}, viteConfig = {}, customOptions) {
|
|
1395
1603
|
const mode = process.env.MODE || process.env.NODE_ENV || ssgOptions.mode || "development";
|
|
@@ -1424,68 +1632,14 @@ ${err.stack}`
|
|
|
1424
1632
|
...viteConfig,
|
|
1425
1633
|
plugins: [
|
|
1426
1634
|
...viteConfig.plugins ?? [],
|
|
1427
|
-
{
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
const createRoot = await viteServer.ssrLoadModule(ssrEntry).then((m) => m.createRoot);
|
|
1436
|
-
const appCtx = await createRoot(false, url);
|
|
1437
|
-
const { routes, getStyleCollector, base, app } = appCtx;
|
|
1438
|
-
const transformedIndexHTML = await onBeforePageRender?.(url, indexHTML, appCtx) || indexHTML;
|
|
1439
|
-
const styleCollector = getStyleCollector ? await getStyleCollector() : null;
|
|
1440
|
-
const { appHTML, bodyAttributes, htmlAttributes, metaAttributes, styleTag, routerContext } = await render(app ?? [...routes], fromNodeRequest(req), styleCollector, base);
|
|
1441
|
-
metaAttributes.push(styleTag);
|
|
1442
|
-
const matchesEntries = routerContext?.matches.map((match) => match.route.entry).filter((entry2) => !!entry2).map((entry2) => entry2[0] === "/" ? entry2 : `/${entry2}`) ?? [];
|
|
1443
|
-
const mods = await Promise.all(
|
|
1444
|
-
[ssrEntry, entry, ...matchesEntries].map(async (entry2) => await viteServer.moduleGraph.getModuleByUrl(entry2))
|
|
1445
|
-
);
|
|
1446
|
-
const assetsUrls = /* @__PURE__ */ new Set();
|
|
1447
|
-
const collectAssets = async (mod) => {
|
|
1448
|
-
if (!mod || !mod?.ssrTransformResult)
|
|
1449
|
-
return;
|
|
1450
|
-
const { deps = [], dynamicDeps = [] } = mod?.ssrTransformResult;
|
|
1451
|
-
const allDeps = [...deps, ...dynamicDeps];
|
|
1452
|
-
for (const dep of allDeps) {
|
|
1453
|
-
if (dep.endsWith(".css")) {
|
|
1454
|
-
assetsUrls.add(dep);
|
|
1455
|
-
} else if (dep.endsWith(".ts") || dep.endsWith(".tsx")) {
|
|
1456
|
-
const depModule = await viteServer.moduleGraph.getModuleByUrl(dep);
|
|
1457
|
-
depModule && await collectAssets(depModule);
|
|
1458
|
-
}
|
|
1459
|
-
}
|
|
1460
|
-
};
|
|
1461
|
-
await Promise.all(mods.map(async (mod) => collectAssets(mod)));
|
|
1462
|
-
const preloadLink = [...assetsUrls].map((item) => createLink$1(joinUrlSegments(config.base, item)));
|
|
1463
|
-
metaAttributes.push(...preloadLink);
|
|
1464
|
-
const renderedHTML = await renderHTML({
|
|
1465
|
-
rootContainerId,
|
|
1466
|
-
appHTML,
|
|
1467
|
-
indexHTML: transformedIndexHTML,
|
|
1468
|
-
metaAttributes,
|
|
1469
|
-
bodyAttributes,
|
|
1470
|
-
htmlAttributes,
|
|
1471
|
-
initialState: null
|
|
1472
|
-
});
|
|
1473
|
-
const transformed = await onPageRendered?.(url, renderedHTML, appCtx) || renderedHTML;
|
|
1474
|
-
res.statusCode = 200;
|
|
1475
|
-
res.setHeader("Content-Type", "text/html");
|
|
1476
|
-
const isDev = "pluginContainer" in server;
|
|
1477
|
-
const headers = isDev ? server.config.server.headers : server.config.preview.headers;
|
|
1478
|
-
send(req, res, transformed, "html", { headers });
|
|
1479
|
-
} catch (e) {
|
|
1480
|
-
viteServer.ssrFixStacktrace(e);
|
|
1481
|
-
console.error(`[vite-react-ssg] error: ${e.stack}`);
|
|
1482
|
-
res.statusCode = 500;
|
|
1483
|
-
res.end(e.stack);
|
|
1484
|
-
}
|
|
1485
|
-
});
|
|
1486
|
-
};
|
|
1487
|
-
}
|
|
1488
|
-
}
|
|
1635
|
+
ssrServerPlugin({
|
|
1636
|
+
template,
|
|
1637
|
+
ssrEntry,
|
|
1638
|
+
onBeforePageRender,
|
|
1639
|
+
onPageRendered,
|
|
1640
|
+
entry,
|
|
1641
|
+
rootContainerId
|
|
1642
|
+
})
|
|
1489
1643
|
]
|
|
1490
1644
|
});
|
|
1491
1645
|
await viteServer.listen();
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function joinUrlSegments(a, b) {
|
|
4
|
+
if (!a || !b)
|
|
5
|
+
return a || b || "";
|
|
6
|
+
if (a[a.length - 1] === "/")
|
|
7
|
+
a = a.substring(0, a.length - 1);
|
|
8
|
+
if (b[0] !== "/")
|
|
9
|
+
b = `/${b}`;
|
|
10
|
+
return a + b;
|
|
11
|
+
}
|
|
12
|
+
function removeLeadingSlash(str) {
|
|
13
|
+
return str[0] === "/" ? str.slice(1) : str;
|
|
14
|
+
}
|
|
15
|
+
function stripBase(path, base) {
|
|
16
|
+
if (path === base)
|
|
17
|
+
return "/";
|
|
18
|
+
const devBase = withTrailingSlash(base);
|
|
19
|
+
return path.startsWith(devBase) ? path.slice(devBase.length - 1) : path;
|
|
20
|
+
}
|
|
21
|
+
function withTrailingSlash(path) {
|
|
22
|
+
if (path[path.length - 1] !== "/")
|
|
23
|
+
return `${path}/`;
|
|
24
|
+
return path;
|
|
25
|
+
}
|
|
26
|
+
function withLeadingSlash(path) {
|
|
27
|
+
if (path[0] !== "/")
|
|
28
|
+
return `/${path}`;
|
|
29
|
+
return path;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function convertRoutesToDataRoutes(routes, mapRouteProperties, parentPath = []) {
|
|
33
|
+
return routes.map((route, index) => {
|
|
34
|
+
const treePath = [...parentPath, String(index)];
|
|
35
|
+
const id = typeof route.id === "string" ? route.id : treePath.join("-");
|
|
36
|
+
route.id = id;
|
|
37
|
+
if (isIndexRoute(route)) {
|
|
38
|
+
const indexRoute = {
|
|
39
|
+
...route,
|
|
40
|
+
...mapRouteProperties(route),
|
|
41
|
+
id
|
|
42
|
+
};
|
|
43
|
+
return indexRoute;
|
|
44
|
+
} else {
|
|
45
|
+
const pathOrLayoutRoute = {
|
|
46
|
+
...route,
|
|
47
|
+
...mapRouteProperties(route),
|
|
48
|
+
id,
|
|
49
|
+
children: void 0
|
|
50
|
+
};
|
|
51
|
+
if (route.children) {
|
|
52
|
+
pathOrLayoutRoute.children = convertRoutesToDataRoutes(
|
|
53
|
+
route.children,
|
|
54
|
+
mapRouteProperties,
|
|
55
|
+
treePath
|
|
56
|
+
// manifest,
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
return pathOrLayoutRoute;
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
function isIndexRoute(route) {
|
|
64
|
+
return route.index === true;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
exports.convertRoutesToDataRoutes = convertRoutesToDataRoutes;
|
|
68
|
+
exports.joinUrlSegments = joinUrlSegments;
|
|
69
|
+
exports.removeLeadingSlash = removeLeadingSlash;
|
|
70
|
+
exports.stripBase = stripBase;
|
|
71
|
+
exports.withLeadingSlash = withLeadingSlash;
|
|
72
|
+
exports.withTrailingSlash = withTrailingSlash;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
function joinUrlSegments(a, b) {
|
|
2
|
+
if (!a || !b)
|
|
3
|
+
return a || b || "";
|
|
4
|
+
if (a[a.length - 1] === "/")
|
|
5
|
+
a = a.substring(0, a.length - 1);
|
|
6
|
+
if (b[0] !== "/")
|
|
7
|
+
b = `/${b}`;
|
|
8
|
+
return a + b;
|
|
9
|
+
}
|
|
10
|
+
function removeLeadingSlash(str) {
|
|
11
|
+
return str[0] === "/" ? str.slice(1) : str;
|
|
12
|
+
}
|
|
13
|
+
function stripBase(path, base) {
|
|
14
|
+
if (path === base)
|
|
15
|
+
return "/";
|
|
16
|
+
const devBase = withTrailingSlash(base);
|
|
17
|
+
return path.startsWith(devBase) ? path.slice(devBase.length - 1) : path;
|
|
18
|
+
}
|
|
19
|
+
function withTrailingSlash(path) {
|
|
20
|
+
if (path[path.length - 1] !== "/")
|
|
21
|
+
return `${path}/`;
|
|
22
|
+
return path;
|
|
23
|
+
}
|
|
24
|
+
function withLeadingSlash(path) {
|
|
25
|
+
if (path[0] !== "/")
|
|
26
|
+
return `/${path}`;
|
|
27
|
+
return path;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function convertRoutesToDataRoutes(routes, mapRouteProperties, parentPath = []) {
|
|
31
|
+
return routes.map((route, index) => {
|
|
32
|
+
const treePath = [...parentPath, String(index)];
|
|
33
|
+
const id = typeof route.id === "string" ? route.id : treePath.join("-");
|
|
34
|
+
route.id = id;
|
|
35
|
+
if (isIndexRoute(route)) {
|
|
36
|
+
const indexRoute = {
|
|
37
|
+
...route,
|
|
38
|
+
...mapRouteProperties(route),
|
|
39
|
+
id
|
|
40
|
+
};
|
|
41
|
+
return indexRoute;
|
|
42
|
+
} else {
|
|
43
|
+
const pathOrLayoutRoute = {
|
|
44
|
+
...route,
|
|
45
|
+
...mapRouteProperties(route),
|
|
46
|
+
id,
|
|
47
|
+
children: void 0
|
|
48
|
+
};
|
|
49
|
+
if (route.children) {
|
|
50
|
+
pathOrLayoutRoute.children = convertRoutesToDataRoutes(
|
|
51
|
+
route.children,
|
|
52
|
+
mapRouteProperties,
|
|
53
|
+
treePath
|
|
54
|
+
// manifest,
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
return pathOrLayoutRoute;
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
function isIndexRoute(route) {
|
|
62
|
+
return route.index === true;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export { withTrailingSlash as a, convertRoutesToDataRoutes as c, joinUrlSegments as j, removeLeadingSlash as r, stripBase as s, withLeadingSlash as w };
|