vite-react-ssg 0.7.0-beta.1 → 0.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/LICENSE +21 -21
- package/README.md +591 -555
- package/bin/vite-react-ssg.js +3 -3
- package/dist/chunks/jsdomGlobal.cjs +80 -80
- package/dist/chunks/jsdomGlobal.mjs +80 -80
- package/dist/client/single-page.d.cts +2 -2
- package/dist/client/single-page.d.mts +2 -2
- package/dist/client/single-page.d.ts +2 -2
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/node.cjs +111 -60
- package/dist/node.d.cts +1 -1
- package/dist/node.d.mts +1 -1
- package/dist/node.d.ts +1 -1
- package/dist/node.mjs +112 -61
- package/dist/shared/{vite-react-ssg.870c683b.d.cts → vite-react-ssg.4d155759.d.cts} +2 -0
- package/dist/shared/{vite-react-ssg.870c683b.d.mts → vite-react-ssg.4d155759.d.mts} +2 -0
- package/dist/shared/{vite-react-ssg.870c683b.d.ts → vite-react-ssg.4d155759.d.ts} +2 -0
- package/package.json +1 -1
package/dist/node.cjs
CHANGED
|
@@ -850,19 +850,8 @@ function getSize(str) {
|
|
|
850
850
|
return `${(str.length / 1024).toFixed(2)} KiB`;
|
|
851
851
|
}
|
|
852
852
|
async function routesToPaths(routes) {
|
|
853
|
-
const pathToEntry = {};
|
|
854
|
-
function addEntry(path, entry) {
|
|
855
|
-
if (!entry)
|
|
856
|
-
return;
|
|
857
|
-
if (entry[0] === "/")
|
|
858
|
-
entry = entry.slice(1);
|
|
859
|
-
if (pathToEntry[path])
|
|
860
|
-
pathToEntry[path].add(entry);
|
|
861
|
-
else
|
|
862
|
-
pathToEntry[path] = /* @__PURE__ */ new Set([entry]);
|
|
863
|
-
}
|
|
864
853
|
if (!routes || routes.length === 0)
|
|
865
|
-
return { paths: ["/"]
|
|
854
|
+
return { paths: ["/"] };
|
|
866
855
|
const paths = /* @__PURE__ */ new Set();
|
|
867
856
|
const getPaths = async (routes2, prefix = "") => {
|
|
868
857
|
prefix = prefix.replace(/\/$/g, "");
|
|
@@ -877,32 +866,28 @@ async function routesToPaths(routes) {
|
|
|
877
866
|
}
|
|
878
867
|
}
|
|
879
868
|
let path = route.path;
|
|
880
|
-
path = handlePath(path, prefix
|
|
869
|
+
path = handlePath(path, prefix);
|
|
881
870
|
if (route.getStaticPaths && isDynamicSegmentsRoute(path)) {
|
|
882
871
|
const staticPaths = await route.getStaticPaths();
|
|
883
872
|
for (let staticPath of staticPaths) {
|
|
884
|
-
staticPath = handlePath(staticPath, prefix
|
|
873
|
+
staticPath = handlePath(staticPath, prefix);
|
|
885
874
|
if (Array.isArray(route.children))
|
|
886
875
|
await getPaths(route.children, staticPath);
|
|
887
876
|
}
|
|
888
877
|
}
|
|
889
|
-
if (route.index)
|
|
890
|
-
|
|
878
|
+
if (route.index && !path) {
|
|
879
|
+
paths.add("/");
|
|
880
|
+
}
|
|
891
881
|
if (Array.isArray(route.children))
|
|
892
882
|
await getPaths(route.children, path);
|
|
893
883
|
}
|
|
894
884
|
};
|
|
895
885
|
await getPaths(routes);
|
|
896
|
-
return { paths: Array.from(paths)
|
|
897
|
-
function handlePath(path, prefix
|
|
886
|
+
return { paths: Array.from(paths) };
|
|
887
|
+
function handlePath(path, prefix) {
|
|
898
888
|
if (path != null) {
|
|
899
889
|
path = prefix && !path.startsWith("/") ? `${prefix}${path ? `/${path}` : ""}` : path;
|
|
900
890
|
paths.add(path);
|
|
901
|
-
addEntry(path, entry);
|
|
902
|
-
if (pathToEntry[prefix]) {
|
|
903
|
-
const pathCopy = path;
|
|
904
|
-
pathToEntry[prefix].forEach((entry2) => addEntry(pathCopy, entry2));
|
|
905
|
-
}
|
|
906
891
|
}
|
|
907
892
|
return path;
|
|
908
893
|
}
|
|
@@ -1096,18 +1081,10 @@ function createLink$1(href) {
|
|
|
1096
1081
|
return `<link rel="stylesheet" href="${href}">`;
|
|
1097
1082
|
}
|
|
1098
1083
|
|
|
1099
|
-
function renderPreloadLinks(document,
|
|
1084
|
+
function renderPreloadLinks(document, assets) {
|
|
1100
1085
|
const seen = /* @__PURE__ */ new Set();
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
const files = ssrManifest[id] || [];
|
|
1104
|
-
files.forEach((file) => {
|
|
1105
|
-
if (!preloadLinks.includes(file))
|
|
1106
|
-
preloadLinks.push(file);
|
|
1107
|
-
});
|
|
1108
|
-
});
|
|
1109
|
-
if (preloadLinks) {
|
|
1110
|
-
preloadLinks.forEach((file) => {
|
|
1086
|
+
if (assets) {
|
|
1087
|
+
assets.forEach((file) => {
|
|
1111
1088
|
if (!seen.has(file)) {
|
|
1112
1089
|
seen.add(file);
|
|
1113
1090
|
renderPreloadLink(document, file);
|
|
@@ -1128,6 +1105,21 @@ function renderPreloadLink(document, file) {
|
|
|
1128
1105
|
href: file,
|
|
1129
1106
|
crossOrigin: ""
|
|
1130
1107
|
});
|
|
1108
|
+
} else if (file.endsWith(".woff") || file.endsWith(".woff2") || file.endsWith(".ttf")) {
|
|
1109
|
+
appendLink(document, {
|
|
1110
|
+
rel: "preload",
|
|
1111
|
+
as: "font",
|
|
1112
|
+
type: "font/woff2",
|
|
1113
|
+
href: file,
|
|
1114
|
+
crossOrigin: ""
|
|
1115
|
+
});
|
|
1116
|
+
} else if (file.endsWith(".png") || file.endsWith(".jpg") || file.endsWith(".jpeg") || file.endsWith(".webp") || file.endsWith(".gif") || file.endsWith(".ico") || file.endsWith(".svg")) {
|
|
1117
|
+
appendLink(document, {
|
|
1118
|
+
rel: "preload",
|
|
1119
|
+
as: "image",
|
|
1120
|
+
href: file,
|
|
1121
|
+
crossOrigin: ""
|
|
1122
|
+
});
|
|
1131
1123
|
}
|
|
1132
1124
|
}
|
|
1133
1125
|
function createLink(document) {
|
|
@@ -1147,6 +1139,69 @@ function appendLink(document, attrs) {
|
|
|
1147
1139
|
document.head.appendChild(link);
|
|
1148
1140
|
}
|
|
1149
1141
|
|
|
1142
|
+
const DYNAMIC_IMPORT_REGEX = /import\("([^)]+)"\)/g;
|
|
1143
|
+
function collectAssets({
|
|
1144
|
+
routes,
|
|
1145
|
+
locationArg,
|
|
1146
|
+
base,
|
|
1147
|
+
serverManifest,
|
|
1148
|
+
manifest,
|
|
1149
|
+
ssrManifest
|
|
1150
|
+
}) {
|
|
1151
|
+
const matches = reactRouterDom.matchRoutes([...routes], locationArg, base);
|
|
1152
|
+
const routeEntries = matches?.map((item) => item.route.entry).filter(Boolean) ?? [];
|
|
1153
|
+
const dynamicImports = /* @__PURE__ */ new Set();
|
|
1154
|
+
matches?.forEach((item) => {
|
|
1155
|
+
let lazyStr = "";
|
|
1156
|
+
if (item.route.lazy) {
|
|
1157
|
+
lazyStr += item.route.lazy.toString();
|
|
1158
|
+
}
|
|
1159
|
+
if (item.route.Component?._payload?._result) {
|
|
1160
|
+
lazyStr += item.route.Component._payload._result.toString();
|
|
1161
|
+
}
|
|
1162
|
+
const match = lazyStr.matchAll(DYNAMIC_IMPORT_REGEX);
|
|
1163
|
+
for (const m of match) {
|
|
1164
|
+
dynamicImports.add(m[1].split("/").at(-1) ?? "");
|
|
1165
|
+
}
|
|
1166
|
+
});
|
|
1167
|
+
const entries = /* @__PURE__ */ new Set();
|
|
1168
|
+
routeEntries.forEach((e) => entries.add(e));
|
|
1169
|
+
const manifestEntries = [...Object.entries(serverManifest)];
|
|
1170
|
+
dynamicImports.forEach((name) => {
|
|
1171
|
+
const result = manifestEntries.find(([_, value]) => value.file.endsWith(name));
|
|
1172
|
+
if (result) {
|
|
1173
|
+
entries.add(result[0]);
|
|
1174
|
+
}
|
|
1175
|
+
});
|
|
1176
|
+
const modules = collectModulesForEntries(manifest, entries);
|
|
1177
|
+
const assets = /* @__PURE__ */ new Set();
|
|
1178
|
+
Array.from(modules).forEach((id) => {
|
|
1179
|
+
const files = ssrManifest[id] || [];
|
|
1180
|
+
files.forEach((file) => {
|
|
1181
|
+
assets.add(file);
|
|
1182
|
+
});
|
|
1183
|
+
});
|
|
1184
|
+
return assets;
|
|
1185
|
+
}
|
|
1186
|
+
function collectModulesForEntries(manifest, entries) {
|
|
1187
|
+
const mods = /* @__PURE__ */ new Set();
|
|
1188
|
+
if (!entries)
|
|
1189
|
+
return mods;
|
|
1190
|
+
for (const entry of entries)
|
|
1191
|
+
collectModules(manifest, entry, mods);
|
|
1192
|
+
return mods;
|
|
1193
|
+
}
|
|
1194
|
+
function collectModules(manifest, entry, mods = /* @__PURE__ */ new Set()) {
|
|
1195
|
+
if (!entry)
|
|
1196
|
+
return mods;
|
|
1197
|
+
mods.add(entry);
|
|
1198
|
+
manifest[entry]?.dynamicImports?.forEach((item) => {
|
|
1199
|
+
collectModules(manifest, item, mods);
|
|
1200
|
+
});
|
|
1201
|
+
return mods;
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
const dotVitedir = Number.parseInt(vite.version) >= 5 ? [".vite"] : [];
|
|
1150
1205
|
function DefaultIncludedRoutes(paths, _routes) {
|
|
1151
1206
|
return paths.filter((i) => !i.includes(":") && !i.includes("*"));
|
|
1152
1207
|
}
|
|
@@ -1178,6 +1233,13 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1178
1233
|
} = Object.assign({}, config.ssgOptions || {}, ssgOptions);
|
|
1179
1234
|
if (fs__default.existsSync(ssgOut))
|
|
1180
1235
|
await fs__default.remove(ssgOut);
|
|
1236
|
+
const clientLogger = vite.createLogger();
|
|
1237
|
+
const loggerWarn = clientLogger.warn;
|
|
1238
|
+
clientLogger.warn = (msg, options) => {
|
|
1239
|
+
if (msg.includes("vite:resolve") && msg.includes("externalized for browser compatibility"))
|
|
1240
|
+
return;
|
|
1241
|
+
loggerWarn(msg, options);
|
|
1242
|
+
};
|
|
1181
1243
|
buildLog("Build for client...");
|
|
1182
1244
|
await vite.build(vite.mergeConfig(viteConfig, {
|
|
1183
1245
|
build: {
|
|
@@ -1195,6 +1257,7 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1195
1257
|
}
|
|
1196
1258
|
}
|
|
1197
1259
|
},
|
|
1260
|
+
customLogger: clientLogger,
|
|
1198
1261
|
mode: config.mode,
|
|
1199
1262
|
ssr: { noExternal: ["vite-react-ssg"] }
|
|
1200
1263
|
}));
|
|
@@ -1208,6 +1271,7 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1208
1271
|
await vite.build(vite.mergeConfig(viteConfig, {
|
|
1209
1272
|
build: {
|
|
1210
1273
|
ssr: ssrEntry,
|
|
1274
|
+
manifest: true,
|
|
1211
1275
|
outDir: ssgOut,
|
|
1212
1276
|
minify: false,
|
|
1213
1277
|
cssCodeSplit: false,
|
|
@@ -1227,11 +1291,12 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1227
1291
|
const prefix = format === "esm" && process.platform === "win32" ? "file://" : "";
|
|
1228
1292
|
const ext = format === "esm" ? ".mjs" : ".cjs";
|
|
1229
1293
|
const serverEntry = node_path.join(prefix, ssgOut, node_path.parse(ssrEntry).name + ext);
|
|
1294
|
+
const serverManifest = JSON.parse(await fs__default.readFile(node_path.join(ssgOut, ...dotVitedir, "manifest.json"), "utf-8"));
|
|
1230
1295
|
const _require = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (document.currentScript && document.currentScript.src || new URL('node.cjs', document.baseURI).href)));
|
|
1231
1296
|
const { createRoot, includedRoutes: serverEntryIncludedRoutes } = format === "esm" ? await import(serverEntry) : _require(serverEntry);
|
|
1232
1297
|
const includedRoutes = serverEntryIncludedRoutes || configIncludedRoutes;
|
|
1233
1298
|
const { routes } = await createRoot(false);
|
|
1234
|
-
const { paths
|
|
1299
|
+
const { paths } = await routesToPaths(routes);
|
|
1235
1300
|
let routesPaths = includeAllRoutes ? paths : await includedRoutes(paths, routes || []);
|
|
1236
1301
|
routesPaths = DefaultIncludedRoutes(routesPaths);
|
|
1237
1302
|
routesPaths = Array.from(new Set(routesPaths));
|
|
@@ -1239,7 +1304,6 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1239
1304
|
const critters = crittersOptions !== false ? await getCritters(outDir, { publicPath: configBase, ...crittersOptions }) : void 0;
|
|
1240
1305
|
if (critters)
|
|
1241
1306
|
console.log(`${kolorist.gray("[vite-react-ssg]")} ${kolorist.blue("Critical CSS generation enabled via `critters`")}`);
|
|
1242
|
-
const dotVitedir = Number.parseInt(vite.version) >= 5 ? [".vite"] : [];
|
|
1243
1307
|
const ssrManifest = JSON.parse(await fs__default.readFile(node_path.join(out, ...dotVitedir, "ssr-manifest.json"), "utf-8"));
|
|
1244
1308
|
const manifest = JSON.parse(await fs__default.readFile(node_path.join(out, ...dotVitedir, "manifest.json"), "utf-8"));
|
|
1245
1309
|
let indexHTML = await fs__default.readFile(node_path.join(out, "index.html"), "utf-8");
|
|
@@ -1256,6 +1320,7 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1256
1320
|
const transformedIndexHTML = await onBeforePageRender?.(path, indexHTML, appCtx) || indexHTML;
|
|
1257
1321
|
const fetchUrl = `${remixRouter.withTrailingSlash(base)}${remixRouter.removeLeadingSlash(path)}`;
|
|
1258
1322
|
const request = createRequest(fetchUrl);
|
|
1323
|
+
const assets = !app ? collectAssets({ routes: [...routes2], locationArg: fetchUrl, base, serverManifest, manifest, ssrManifest }) : /* @__PURE__ */ new Set();
|
|
1259
1324
|
const { appHTML, bodyAttributes, htmlAttributes, metaAttributes, styleTag, routerContext } = await render(app ?? [...routes2], request, styleCollector, base);
|
|
1260
1325
|
staticLoaderDataManifest[path] = routerContext?.loaderData;
|
|
1261
1326
|
await triggerOnSSRAppRendered?.(path, appHTML, appCtx);
|
|
@@ -1269,8 +1334,7 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1269
1334
|
initialState: null
|
|
1270
1335
|
});
|
|
1271
1336
|
const jsdom = new JSDOM.JSDOM(renderedHTML);
|
|
1272
|
-
|
|
1273
|
-
renderPreloadLinks(jsdom.window.document, modules, ssrManifest);
|
|
1337
|
+
renderPreloadLinks(jsdom.window.document, assets);
|
|
1274
1338
|
const html = jsdom.serialize();
|
|
1275
1339
|
let transformed = await onPageRendered?.(path, html, appCtx) || html;
|
|
1276
1340
|
transformed = transformed.replace(SCRIPT_COMMENT_PLACEHOLDER, `window.__VITE_REACT_SSG_HASH__ = '${hash}'`);
|
|
@@ -1295,7 +1359,12 @@ ${err.stack}`);
|
|
|
1295
1359
|
});
|
|
1296
1360
|
}
|
|
1297
1361
|
await queue.start().onIdle();
|
|
1298
|
-
|
|
1362
|
+
buildLog("Generating static loader data manifest...");
|
|
1363
|
+
const staticLoaderDataManifestString = JSON.stringify(staticLoaderDataManifest, null, 0);
|
|
1364
|
+
await fs__default.writeFile(node_path.join(out, `static-loader-data-manifest-${hash}.json`), staticLoaderDataManifestString);
|
|
1365
|
+
config.logger.info(
|
|
1366
|
+
`${kolorist.dim(`${outDir}/`)}${kolorist.cyan(`static-loader-data-manifest-${hash}.json`.padEnd(15, " "))} ${kolorist.dim(getSize(staticLoaderDataManifestString))}`
|
|
1367
|
+
);
|
|
1299
1368
|
await fs__default.remove(node_path.join(root, ".vite-react-ssg-temp"));
|
|
1300
1369
|
const pwaPlugin = config.plugins.find((i) => i.name === "vite-plugin-pwa")?.api;
|
|
1301
1370
|
if (pwaPlugin && !pwaPlugin.disabled && pwaPlugin.generateSW) {
|
|
@@ -1339,23 +1408,6 @@ async function formatHtml(html, formatting) {
|
|
|
1339
1408
|
}
|
|
1340
1409
|
return html;
|
|
1341
1410
|
}
|
|
1342
|
-
function collectModulesForEntrys(manifest, entrys) {
|
|
1343
|
-
const mods = /* @__PURE__ */ new Set();
|
|
1344
|
-
if (!entrys)
|
|
1345
|
-
return mods;
|
|
1346
|
-
for (const entry of entrys)
|
|
1347
|
-
collectModules(manifest, entry, mods);
|
|
1348
|
-
return mods;
|
|
1349
|
-
}
|
|
1350
|
-
function collectModules(manifest, entry, mods = /* @__PURE__ */ new Set()) {
|
|
1351
|
-
if (!entry)
|
|
1352
|
-
return mods;
|
|
1353
|
-
mods.add(entry);
|
|
1354
|
-
manifest[entry]?.dynamicImports?.forEach((item) => {
|
|
1355
|
-
collectModules(manifest, item, mods);
|
|
1356
|
-
});
|
|
1357
|
-
return mods;
|
|
1358
|
-
}
|
|
1359
1411
|
|
|
1360
1412
|
function invariant(value, message) {
|
|
1361
1413
|
if (value === false || value === null || typeof value === "undefined") {
|
|
@@ -1471,11 +1523,10 @@ function ssrServerPlugin({
|
|
|
1471
1523
|
const indexHTML = await server.transformIndexHtml(url, template);
|
|
1472
1524
|
const transformedIndexHTML = await onBeforePageRender?.(url, indexHTML, appCtx) || indexHTML;
|
|
1473
1525
|
const styleCollector = getStyleCollector ? await getStyleCollector() : null;
|
|
1474
|
-
const { appHTML, bodyAttributes, htmlAttributes, metaAttributes, styleTag
|
|
1526
|
+
const { appHTML, bodyAttributes, htmlAttributes, metaAttributes, styleTag } = await render(app ?? [...routes], fromNodeRequest(req), styleCollector, base);
|
|
1475
1527
|
metaAttributes.push(styleTag);
|
|
1476
|
-
const matchesEntries = routerContext?.matches.map((match) => match.route.entry).filter((entry2) => !!entry2).map((entry2) => entry2[0] === "/" ? entry2 : `/${entry2}`) ?? [];
|
|
1477
1528
|
const mods = await Promise.all(
|
|
1478
|
-
[ssrEntry, entry
|
|
1529
|
+
[ssrEntry, entry].map(async (entry2) => await server.moduleGraph.getModuleByUrl(entry2))
|
|
1479
1530
|
);
|
|
1480
1531
|
const assetsUrls = /* @__PURE__ */ new Set();
|
|
1481
1532
|
const collectAssets = async (mod) => {
|
|
@@ -1484,7 +1535,7 @@ function ssrServerPlugin({
|
|
|
1484
1535
|
const { deps = [], dynamicDeps = [] } = mod?.ssrTransformResult;
|
|
1485
1536
|
const allDeps = [...deps, ...dynamicDeps];
|
|
1486
1537
|
for (const dep of allDeps) {
|
|
1487
|
-
if (dep.endsWith(".css")) {
|
|
1538
|
+
if (dep.endsWith(".css") || dep.endsWith(".scss") || dep.endsWith(".sass") || dep.endsWith(".less")) {
|
|
1488
1539
|
assetsUrls.add(dep);
|
|
1489
1540
|
} else if (dep.endsWith(".ts") || dep.endsWith(".tsx")) {
|
|
1490
1541
|
const depModule = await server.moduleGraph.getModuleByUrl(dep);
|
package/dist/node.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { InlineConfig } from 'vite';
|
|
2
|
-
import { b as ViteReactSSGOptions } from './shared/vite-react-ssg.
|
|
2
|
+
import { b as ViteReactSSGOptions } from './shared/vite-react-ssg.4d155759.cjs';
|
|
3
3
|
import 'critters';
|
|
4
4
|
import 'react';
|
|
5
5
|
import 'react-router-dom';
|
package/dist/node.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { InlineConfig } from 'vite';
|
|
2
|
-
import { b as ViteReactSSGOptions } from './shared/vite-react-ssg.
|
|
2
|
+
import { b as ViteReactSSGOptions } from './shared/vite-react-ssg.4d155759.mjs';
|
|
3
3
|
import 'critters';
|
|
4
4
|
import 'react';
|
|
5
5
|
import 'react-router-dom';
|
package/dist/node.d.ts
CHANGED
package/dist/node.mjs
CHANGED
|
@@ -2,7 +2,7 @@ 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, send, createServer } from 'vite';
|
|
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
8
|
import { a as withTrailingSlash, r as removeLeadingSlash, c as convertRoutesToDataRoutes, j as joinUrlSegments } from './shared/vite-react-ssg.054e813a.mjs';
|
|
@@ -843,19 +843,8 @@ function getSize(str) {
|
|
|
843
843
|
return `${(str.length / 1024).toFixed(2)} KiB`;
|
|
844
844
|
}
|
|
845
845
|
async function routesToPaths(routes) {
|
|
846
|
-
const pathToEntry = {};
|
|
847
|
-
function addEntry(path, entry) {
|
|
848
|
-
if (!entry)
|
|
849
|
-
return;
|
|
850
|
-
if (entry[0] === "/")
|
|
851
|
-
entry = entry.slice(1);
|
|
852
|
-
if (pathToEntry[path])
|
|
853
|
-
pathToEntry[path].add(entry);
|
|
854
|
-
else
|
|
855
|
-
pathToEntry[path] = /* @__PURE__ */ new Set([entry]);
|
|
856
|
-
}
|
|
857
846
|
if (!routes || routes.length === 0)
|
|
858
|
-
return { paths: ["/"]
|
|
847
|
+
return { paths: ["/"] };
|
|
859
848
|
const paths = /* @__PURE__ */ new Set();
|
|
860
849
|
const getPaths = async (routes2, prefix = "") => {
|
|
861
850
|
prefix = prefix.replace(/\/$/g, "");
|
|
@@ -870,32 +859,28 @@ async function routesToPaths(routes) {
|
|
|
870
859
|
}
|
|
871
860
|
}
|
|
872
861
|
let path = route.path;
|
|
873
|
-
path = handlePath(path, prefix
|
|
862
|
+
path = handlePath(path, prefix);
|
|
874
863
|
if (route.getStaticPaths && isDynamicSegmentsRoute(path)) {
|
|
875
864
|
const staticPaths = await route.getStaticPaths();
|
|
876
865
|
for (let staticPath of staticPaths) {
|
|
877
|
-
staticPath = handlePath(staticPath, prefix
|
|
866
|
+
staticPath = handlePath(staticPath, prefix);
|
|
878
867
|
if (Array.isArray(route.children))
|
|
879
868
|
await getPaths(route.children, staticPath);
|
|
880
869
|
}
|
|
881
870
|
}
|
|
882
|
-
if (route.index)
|
|
883
|
-
|
|
871
|
+
if (route.index && !path) {
|
|
872
|
+
paths.add("/");
|
|
873
|
+
}
|
|
884
874
|
if (Array.isArray(route.children))
|
|
885
875
|
await getPaths(route.children, path);
|
|
886
876
|
}
|
|
887
877
|
};
|
|
888
878
|
await getPaths(routes);
|
|
889
|
-
return { paths: Array.from(paths)
|
|
890
|
-
function handlePath(path, prefix
|
|
879
|
+
return { paths: Array.from(paths) };
|
|
880
|
+
function handlePath(path, prefix) {
|
|
891
881
|
if (path != null) {
|
|
892
882
|
path = prefix && !path.startsWith("/") ? `${prefix}${path ? `/${path}` : ""}` : path;
|
|
893
883
|
paths.add(path);
|
|
894
|
-
addEntry(path, entry);
|
|
895
|
-
if (pathToEntry[prefix]) {
|
|
896
|
-
const pathCopy = path;
|
|
897
|
-
pathToEntry[prefix].forEach((entry2) => addEntry(pathCopy, entry2));
|
|
898
|
-
}
|
|
899
884
|
}
|
|
900
885
|
return path;
|
|
901
886
|
}
|
|
@@ -1089,18 +1074,10 @@ function createLink$1(href) {
|
|
|
1089
1074
|
return `<link rel="stylesheet" href="${href}">`;
|
|
1090
1075
|
}
|
|
1091
1076
|
|
|
1092
|
-
function renderPreloadLinks(document,
|
|
1077
|
+
function renderPreloadLinks(document, assets) {
|
|
1093
1078
|
const seen = /* @__PURE__ */ new Set();
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
const files = ssrManifest[id] || [];
|
|
1097
|
-
files.forEach((file) => {
|
|
1098
|
-
if (!preloadLinks.includes(file))
|
|
1099
|
-
preloadLinks.push(file);
|
|
1100
|
-
});
|
|
1101
|
-
});
|
|
1102
|
-
if (preloadLinks) {
|
|
1103
|
-
preloadLinks.forEach((file) => {
|
|
1079
|
+
if (assets) {
|
|
1080
|
+
assets.forEach((file) => {
|
|
1104
1081
|
if (!seen.has(file)) {
|
|
1105
1082
|
seen.add(file);
|
|
1106
1083
|
renderPreloadLink(document, file);
|
|
@@ -1121,6 +1098,21 @@ function renderPreloadLink(document, file) {
|
|
|
1121
1098
|
href: file,
|
|
1122
1099
|
crossOrigin: ""
|
|
1123
1100
|
});
|
|
1101
|
+
} else if (file.endsWith(".woff") || file.endsWith(".woff2") || file.endsWith(".ttf")) {
|
|
1102
|
+
appendLink(document, {
|
|
1103
|
+
rel: "preload",
|
|
1104
|
+
as: "font",
|
|
1105
|
+
type: "font/woff2",
|
|
1106
|
+
href: file,
|
|
1107
|
+
crossOrigin: ""
|
|
1108
|
+
});
|
|
1109
|
+
} else if (file.endsWith(".png") || file.endsWith(".jpg") || file.endsWith(".jpeg") || file.endsWith(".webp") || file.endsWith(".gif") || file.endsWith(".ico") || file.endsWith(".svg")) {
|
|
1110
|
+
appendLink(document, {
|
|
1111
|
+
rel: "preload",
|
|
1112
|
+
as: "image",
|
|
1113
|
+
href: file,
|
|
1114
|
+
crossOrigin: ""
|
|
1115
|
+
});
|
|
1124
1116
|
}
|
|
1125
1117
|
}
|
|
1126
1118
|
function createLink(document) {
|
|
@@ -1140,6 +1132,69 @@ function appendLink(document, attrs) {
|
|
|
1140
1132
|
document.head.appendChild(link);
|
|
1141
1133
|
}
|
|
1142
1134
|
|
|
1135
|
+
const DYNAMIC_IMPORT_REGEX = /import\("([^)]+)"\)/g;
|
|
1136
|
+
function collectAssets({
|
|
1137
|
+
routes,
|
|
1138
|
+
locationArg,
|
|
1139
|
+
base,
|
|
1140
|
+
serverManifest,
|
|
1141
|
+
manifest,
|
|
1142
|
+
ssrManifest
|
|
1143
|
+
}) {
|
|
1144
|
+
const matches = matchRoutes([...routes], locationArg, base);
|
|
1145
|
+
const routeEntries = matches?.map((item) => item.route.entry).filter(Boolean) ?? [];
|
|
1146
|
+
const dynamicImports = /* @__PURE__ */ new Set();
|
|
1147
|
+
matches?.forEach((item) => {
|
|
1148
|
+
let lazyStr = "";
|
|
1149
|
+
if (item.route.lazy) {
|
|
1150
|
+
lazyStr += item.route.lazy.toString();
|
|
1151
|
+
}
|
|
1152
|
+
if (item.route.Component?._payload?._result) {
|
|
1153
|
+
lazyStr += item.route.Component._payload._result.toString();
|
|
1154
|
+
}
|
|
1155
|
+
const match = lazyStr.matchAll(DYNAMIC_IMPORT_REGEX);
|
|
1156
|
+
for (const m of match) {
|
|
1157
|
+
dynamicImports.add(m[1].split("/").at(-1) ?? "");
|
|
1158
|
+
}
|
|
1159
|
+
});
|
|
1160
|
+
const entries = /* @__PURE__ */ new Set();
|
|
1161
|
+
routeEntries.forEach((e) => entries.add(e));
|
|
1162
|
+
const manifestEntries = [...Object.entries(serverManifest)];
|
|
1163
|
+
dynamicImports.forEach((name) => {
|
|
1164
|
+
const result = manifestEntries.find(([_, value]) => value.file.endsWith(name));
|
|
1165
|
+
if (result) {
|
|
1166
|
+
entries.add(result[0]);
|
|
1167
|
+
}
|
|
1168
|
+
});
|
|
1169
|
+
const modules = collectModulesForEntries(manifest, entries);
|
|
1170
|
+
const assets = /* @__PURE__ */ new Set();
|
|
1171
|
+
Array.from(modules).forEach((id) => {
|
|
1172
|
+
const files = ssrManifest[id] || [];
|
|
1173
|
+
files.forEach((file) => {
|
|
1174
|
+
assets.add(file);
|
|
1175
|
+
});
|
|
1176
|
+
});
|
|
1177
|
+
return assets;
|
|
1178
|
+
}
|
|
1179
|
+
function collectModulesForEntries(manifest, entries) {
|
|
1180
|
+
const mods = /* @__PURE__ */ new Set();
|
|
1181
|
+
if (!entries)
|
|
1182
|
+
return mods;
|
|
1183
|
+
for (const entry of entries)
|
|
1184
|
+
collectModules(manifest, entry, mods);
|
|
1185
|
+
return mods;
|
|
1186
|
+
}
|
|
1187
|
+
function collectModules(manifest, entry, mods = /* @__PURE__ */ new Set()) {
|
|
1188
|
+
if (!entry)
|
|
1189
|
+
return mods;
|
|
1190
|
+
mods.add(entry);
|
|
1191
|
+
manifest[entry]?.dynamicImports?.forEach((item) => {
|
|
1192
|
+
collectModules(manifest, item, mods);
|
|
1193
|
+
});
|
|
1194
|
+
return mods;
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
const dotVitedir = Number.parseInt(version$1) >= 5 ? [".vite"] : [];
|
|
1143
1198
|
function DefaultIncludedRoutes(paths, _routes) {
|
|
1144
1199
|
return paths.filter((i) => !i.includes(":") && !i.includes("*"));
|
|
1145
1200
|
}
|
|
@@ -1171,6 +1226,13 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1171
1226
|
} = Object.assign({}, config.ssgOptions || {}, ssgOptions);
|
|
1172
1227
|
if (fs.existsSync(ssgOut))
|
|
1173
1228
|
await fs.remove(ssgOut);
|
|
1229
|
+
const clientLogger = createLogger();
|
|
1230
|
+
const loggerWarn = clientLogger.warn;
|
|
1231
|
+
clientLogger.warn = (msg, options) => {
|
|
1232
|
+
if (msg.includes("vite:resolve") && msg.includes("externalized for browser compatibility"))
|
|
1233
|
+
return;
|
|
1234
|
+
loggerWarn(msg, options);
|
|
1235
|
+
};
|
|
1174
1236
|
buildLog("Build for client...");
|
|
1175
1237
|
await build$1(mergeConfig(viteConfig, {
|
|
1176
1238
|
build: {
|
|
@@ -1188,6 +1250,7 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1188
1250
|
}
|
|
1189
1251
|
}
|
|
1190
1252
|
},
|
|
1253
|
+
customLogger: clientLogger,
|
|
1191
1254
|
mode: config.mode,
|
|
1192
1255
|
ssr: { noExternal: ["vite-react-ssg"] }
|
|
1193
1256
|
}));
|
|
@@ -1201,6 +1264,7 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1201
1264
|
await build$1(mergeConfig(viteConfig, {
|
|
1202
1265
|
build: {
|
|
1203
1266
|
ssr: ssrEntry,
|
|
1267
|
+
manifest: true,
|
|
1204
1268
|
outDir: ssgOut,
|
|
1205
1269
|
minify: false,
|
|
1206
1270
|
cssCodeSplit: false,
|
|
@@ -1220,11 +1284,12 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1220
1284
|
const prefix = format === "esm" && process.platform === "win32" ? "file://" : "";
|
|
1221
1285
|
const ext = format === "esm" ? ".mjs" : ".cjs";
|
|
1222
1286
|
const serverEntry = join(prefix, ssgOut, parse(ssrEntry).name + ext);
|
|
1287
|
+
const serverManifest = JSON.parse(await fs.readFile(join(ssgOut, ...dotVitedir, "manifest.json"), "utf-8"));
|
|
1223
1288
|
const _require = createRequire(import.meta.url);
|
|
1224
1289
|
const { createRoot, includedRoutes: serverEntryIncludedRoutes } = format === "esm" ? await import(serverEntry) : _require(serverEntry);
|
|
1225
1290
|
const includedRoutes = serverEntryIncludedRoutes || configIncludedRoutes;
|
|
1226
1291
|
const { routes } = await createRoot(false);
|
|
1227
|
-
const { paths
|
|
1292
|
+
const { paths } = await routesToPaths(routes);
|
|
1228
1293
|
let routesPaths = includeAllRoutes ? paths : await includedRoutes(paths, routes || []);
|
|
1229
1294
|
routesPaths = DefaultIncludedRoutes(routesPaths);
|
|
1230
1295
|
routesPaths = Array.from(new Set(routesPaths));
|
|
@@ -1232,7 +1297,6 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1232
1297
|
const critters = crittersOptions !== false ? await getCritters(outDir, { publicPath: configBase, ...crittersOptions }) : void 0;
|
|
1233
1298
|
if (critters)
|
|
1234
1299
|
console.log(`${gray("[vite-react-ssg]")} ${blue("Critical CSS generation enabled via `critters`")}`);
|
|
1235
|
-
const dotVitedir = Number.parseInt(version$1) >= 5 ? [".vite"] : [];
|
|
1236
1300
|
const ssrManifest = JSON.parse(await fs.readFile(join(out, ...dotVitedir, "ssr-manifest.json"), "utf-8"));
|
|
1237
1301
|
const manifest = JSON.parse(await fs.readFile(join(out, ...dotVitedir, "manifest.json"), "utf-8"));
|
|
1238
1302
|
let indexHTML = await fs.readFile(join(out, "index.html"), "utf-8");
|
|
@@ -1249,6 +1313,7 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1249
1313
|
const transformedIndexHTML = await onBeforePageRender?.(path, indexHTML, appCtx) || indexHTML;
|
|
1250
1314
|
const fetchUrl = `${withTrailingSlash(base)}${removeLeadingSlash(path)}`;
|
|
1251
1315
|
const request = createRequest(fetchUrl);
|
|
1316
|
+
const assets = !app ? collectAssets({ routes: [...routes2], locationArg: fetchUrl, base, serverManifest, manifest, ssrManifest }) : /* @__PURE__ */ new Set();
|
|
1252
1317
|
const { appHTML, bodyAttributes, htmlAttributes, metaAttributes, styleTag, routerContext } = await render(app ?? [...routes2], request, styleCollector, base);
|
|
1253
1318
|
staticLoaderDataManifest[path] = routerContext?.loaderData;
|
|
1254
1319
|
await triggerOnSSRAppRendered?.(path, appHTML, appCtx);
|
|
@@ -1262,8 +1327,7 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1262
1327
|
initialState: null
|
|
1263
1328
|
});
|
|
1264
1329
|
const jsdom = new JSDOM(renderedHTML);
|
|
1265
|
-
|
|
1266
|
-
renderPreloadLinks(jsdom.window.document, modules, ssrManifest);
|
|
1330
|
+
renderPreloadLinks(jsdom.window.document, assets);
|
|
1267
1331
|
const html = jsdom.serialize();
|
|
1268
1332
|
let transformed = await onPageRendered?.(path, html, appCtx) || html;
|
|
1269
1333
|
transformed = transformed.replace(SCRIPT_COMMENT_PLACEHOLDER, `window.__VITE_REACT_SSG_HASH__ = '${hash}'`);
|
|
@@ -1288,7 +1352,12 @@ ${err.stack}`);
|
|
|
1288
1352
|
});
|
|
1289
1353
|
}
|
|
1290
1354
|
await queue.start().onIdle();
|
|
1291
|
-
|
|
1355
|
+
buildLog("Generating static loader data manifest...");
|
|
1356
|
+
const staticLoaderDataManifestString = JSON.stringify(staticLoaderDataManifest, null, 0);
|
|
1357
|
+
await fs.writeFile(join(out, `static-loader-data-manifest-${hash}.json`), staticLoaderDataManifestString);
|
|
1358
|
+
config.logger.info(
|
|
1359
|
+
`${dim(`${outDir}/`)}${cyan(`static-loader-data-manifest-${hash}.json`.padEnd(15, " "))} ${dim(getSize(staticLoaderDataManifestString))}`
|
|
1360
|
+
);
|
|
1292
1361
|
await fs.remove(join(root, ".vite-react-ssg-temp"));
|
|
1293
1362
|
const pwaPlugin = config.plugins.find((i) => i.name === "vite-plugin-pwa")?.api;
|
|
1294
1363
|
if (pwaPlugin && !pwaPlugin.disabled && pwaPlugin.generateSW) {
|
|
@@ -1332,23 +1401,6 @@ async function formatHtml(html, formatting) {
|
|
|
1332
1401
|
}
|
|
1333
1402
|
return html;
|
|
1334
1403
|
}
|
|
1335
|
-
function collectModulesForEntrys(manifest, entrys) {
|
|
1336
|
-
const mods = /* @__PURE__ */ new Set();
|
|
1337
|
-
if (!entrys)
|
|
1338
|
-
return mods;
|
|
1339
|
-
for (const entry of entrys)
|
|
1340
|
-
collectModules(manifest, entry, mods);
|
|
1341
|
-
return mods;
|
|
1342
|
-
}
|
|
1343
|
-
function collectModules(manifest, entry, mods = /* @__PURE__ */ new Set()) {
|
|
1344
|
-
if (!entry)
|
|
1345
|
-
return mods;
|
|
1346
|
-
mods.add(entry);
|
|
1347
|
-
manifest[entry]?.dynamicImports?.forEach((item) => {
|
|
1348
|
-
collectModules(manifest, item, mods);
|
|
1349
|
-
});
|
|
1350
|
-
return mods;
|
|
1351
|
-
}
|
|
1352
1404
|
|
|
1353
1405
|
function invariant(value, message) {
|
|
1354
1406
|
if (value === false || value === null || typeof value === "undefined") {
|
|
@@ -1464,11 +1516,10 @@ function ssrServerPlugin({
|
|
|
1464
1516
|
const indexHTML = await server.transformIndexHtml(url, template);
|
|
1465
1517
|
const transformedIndexHTML = await onBeforePageRender?.(url, indexHTML, appCtx) || indexHTML;
|
|
1466
1518
|
const styleCollector = getStyleCollector ? await getStyleCollector() : null;
|
|
1467
|
-
const { appHTML, bodyAttributes, htmlAttributes, metaAttributes, styleTag
|
|
1519
|
+
const { appHTML, bodyAttributes, htmlAttributes, metaAttributes, styleTag } = await render(app ?? [...routes], fromNodeRequest(req), styleCollector, base);
|
|
1468
1520
|
metaAttributes.push(styleTag);
|
|
1469
|
-
const matchesEntries = routerContext?.matches.map((match) => match.route.entry).filter((entry2) => !!entry2).map((entry2) => entry2[0] === "/" ? entry2 : `/${entry2}`) ?? [];
|
|
1470
1521
|
const mods = await Promise.all(
|
|
1471
|
-
[ssrEntry, entry
|
|
1522
|
+
[ssrEntry, entry].map(async (entry2) => await server.moduleGraph.getModuleByUrl(entry2))
|
|
1472
1523
|
);
|
|
1473
1524
|
const assetsUrls = /* @__PURE__ */ new Set();
|
|
1474
1525
|
const collectAssets = async (mod) => {
|
|
@@ -1477,7 +1528,7 @@ function ssrServerPlugin({
|
|
|
1477
1528
|
const { deps = [], dynamicDeps = [] } = mod?.ssrTransformResult;
|
|
1478
1529
|
const allDeps = [...deps, ...dynamicDeps];
|
|
1479
1530
|
for (const dep of allDeps) {
|
|
1480
|
-
if (dep.endsWith(".css")) {
|
|
1531
|
+
if (dep.endsWith(".css") || dep.endsWith(".scss") || dep.endsWith(".sass") || dep.endsWith(".less")) {
|
|
1481
1532
|
assetsUrls.add(dep);
|
|
1482
1533
|
} else if (dep.endsWith(".ts") || dep.endsWith(".tsx")) {
|
|
1483
1534
|
const depModule = await server.moduleGraph.getModuleByUrl(dep);
|
|
@@ -140,6 +140,8 @@ interface CommonRouteOptions {
|
|
|
140
140
|
/**
|
|
141
141
|
* Used to obtain static resources through manifest
|
|
142
142
|
*
|
|
143
|
+
* **You are not required to use this field. It is only necessary when "prehydration style loss" occurs.**
|
|
144
|
+
*
|
|
143
145
|
* @example `src/pages/home.tsx`
|
|
144
146
|
*/
|
|
145
147
|
entry?: string;
|
|
@@ -140,6 +140,8 @@ interface CommonRouteOptions {
|
|
|
140
140
|
/**
|
|
141
141
|
* Used to obtain static resources through manifest
|
|
142
142
|
*
|
|
143
|
+
* **You are not required to use this field. It is only necessary when "prehydration style loss" occurs.**
|
|
144
|
+
*
|
|
143
145
|
* @example `src/pages/home.tsx`
|
|
144
146
|
*/
|
|
145
147
|
entry?: string;
|
|
@@ -140,6 +140,8 @@ interface CommonRouteOptions {
|
|
|
140
140
|
/**
|
|
141
141
|
* Used to obtain static resources through manifest
|
|
142
142
|
*
|
|
143
|
+
* **You are not required to use this field. It is only necessary when "prehydration style loss" occurs.**
|
|
144
|
+
*
|
|
143
145
|
* @example `src/pages/home.tsx`
|
|
144
146
|
*/
|
|
145
147
|
entry?: string;
|