vite-react-ssg 0.0.1 → 0.0.3
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 +238 -131
- package/bin/vite-react-ssg.js +3 -3
- package/dist/chunks/jsdomGlobal.cjs +79 -79
- package/dist/chunks/jsdomGlobal.mjs +79 -79
- package/dist/index.cjs +3 -3
- package/dist/index.d.ts +3 -2
- package/dist/index.mjs +3 -3
- package/dist/node/cli.cjs +1 -1
- package/dist/node/cli.mjs +1 -1
- package/dist/node.cjs +1 -1
- package/dist/node.d.ts +1 -2
- package/dist/node.mjs +1 -1
- package/dist/shared/{vite-react-ssg.c2c344c3.mjs → vite-react-ssg.524ba00d.mjs} +70 -15
- package/dist/shared/{vite-react-ssg.1128b41a.cjs → vite-react-ssg.a5dfecac.cjs} +71 -16
- package/dist/{types-fa5fe9c2.d.ts → types-82f34756.d.ts} +17 -5
- package/package.json +8 -7
|
@@ -1,84 +1,84 @@
|
|
|
1
1
|
import JSDOM from 'jsdom';
|
|
2
2
|
|
|
3
|
-
/*
|
|
4
|
-
MIT License
|
|
5
|
-
|
|
6
|
-
Copyright for portions of global-jsdom are held by Rico Sta. Cruz, 2016 as part of
|
|
7
|
-
jsdom-global. All other copyright for global-jsdom are held by jonathan schatz, 2017.
|
|
8
|
-
|
|
9
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
10
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
11
|
-
in the Software without restriction, including without limitation the rights
|
|
12
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
13
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
14
|
-
furnished to do so, subject to the following conditions:
|
|
15
|
-
|
|
16
|
-
The above copyright notice and this permission notice shall be included in all
|
|
17
|
-
copies or substantial portions of the Software.
|
|
18
|
-
|
|
19
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
20
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
21
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
22
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
23
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
24
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
25
|
-
SOFTWARE.
|
|
26
|
-
*/
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const defaultHtml = '<!doctype html><html><head><meta charset="utf-8"></head><body></body></html>';
|
|
30
|
-
|
|
31
|
-
// define this here so that we only ever dynamically populate KEYS once.
|
|
32
|
-
|
|
33
|
-
const KEYS = [];
|
|
34
|
-
|
|
35
|
-
function jsdomGlobal(html = defaultHtml, options = {}) {
|
|
36
|
-
// Idempotency
|
|
37
|
-
if (global.navigator
|
|
38
|
-
&& global.navigator.userAgent
|
|
39
|
-
&& global.navigator.userAgent.includes('Node.js')
|
|
40
|
-
&& global.document
|
|
41
|
-
&& typeof global.document.destroy === 'function')
|
|
42
|
-
return global.document.destroy
|
|
43
|
-
|
|
44
|
-
// set a default url if we don't get one - otherwise things explode when we copy localstorage keys
|
|
45
|
-
if (!('url' in options))
|
|
46
|
-
Object.assign(options, { url: 'http://localhost:3000' });
|
|
47
|
-
|
|
48
|
-
// enable pretendToBeVisual by default since react needs
|
|
49
|
-
// window.requestAnimationFrame, see https://github.com/jsdom/jsdom#pretending-to-be-a-visual-browser
|
|
50
|
-
if (!('pretendToBeVisual' in options))
|
|
51
|
-
Object.assign(options, { pretendToBeVisual: true });
|
|
52
|
-
|
|
53
|
-
const jsdom = new JSDOM.JSDOM(html, options);
|
|
54
|
-
const { window } = jsdom;
|
|
55
|
-
const { document } = window;
|
|
56
|
-
|
|
57
|
-
// generate our list of keys by enumerating document.window - this list may vary
|
|
58
|
-
// based on the jsdom version. filter out internal methods as well as anything
|
|
59
|
-
// that node already defines
|
|
60
|
-
|
|
61
|
-
if (KEYS.length === 0) {
|
|
62
|
-
KEYS.push(...Object.getOwnPropertyNames(window).filter(k => !k.startsWith('_')).filter(k => !(k in global)));
|
|
63
|
-
// going to add our jsdom instance, see below
|
|
64
|
-
KEYS.push('$jsdom');
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
KEYS.forEach(key => global[key] = window[key]);
|
|
68
|
-
|
|
69
|
-
// setup document / window / window.console
|
|
70
|
-
global.document = document;
|
|
71
|
-
global.window = window;
|
|
72
|
-
window.console = global.console;
|
|
73
|
-
|
|
74
|
-
// add access to our jsdom instance
|
|
75
|
-
global.$jsdom = jsdom;
|
|
76
|
-
|
|
77
|
-
const cleanup = () => KEYS.forEach(key => delete global[key]);
|
|
78
|
-
|
|
79
|
-
document.destroy = cleanup;
|
|
80
|
-
|
|
81
|
-
return cleanup
|
|
3
|
+
/*
|
|
4
|
+
MIT License
|
|
5
|
+
|
|
6
|
+
Copyright for portions of global-jsdom are held by Rico Sta. Cruz, 2016 as part of
|
|
7
|
+
jsdom-global. All other copyright for global-jsdom are held by jonathan schatz, 2017.
|
|
8
|
+
|
|
9
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
10
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
11
|
+
in the Software without restriction, including without limitation the rights
|
|
12
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
13
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
14
|
+
furnished to do so, subject to the following conditions:
|
|
15
|
+
|
|
16
|
+
The above copyright notice and this permission notice shall be included in all
|
|
17
|
+
copies or substantial portions of the Software.
|
|
18
|
+
|
|
19
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
20
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
21
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
22
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
23
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
24
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
25
|
+
SOFTWARE.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
const defaultHtml = '<!doctype html><html><head><meta charset="utf-8"></head><body></body></html>';
|
|
30
|
+
|
|
31
|
+
// define this here so that we only ever dynamically populate KEYS once.
|
|
32
|
+
|
|
33
|
+
const KEYS = [];
|
|
34
|
+
|
|
35
|
+
function jsdomGlobal(html = defaultHtml, options = {}) {
|
|
36
|
+
// Idempotency
|
|
37
|
+
if (global.navigator
|
|
38
|
+
&& global.navigator.userAgent
|
|
39
|
+
&& global.navigator.userAgent.includes('Node.js')
|
|
40
|
+
&& global.document
|
|
41
|
+
&& typeof global.document.destroy === 'function')
|
|
42
|
+
return global.document.destroy
|
|
43
|
+
|
|
44
|
+
// set a default url if we don't get one - otherwise things explode when we copy localstorage keys
|
|
45
|
+
if (!('url' in options))
|
|
46
|
+
Object.assign(options, { url: 'http://localhost:3000' });
|
|
47
|
+
|
|
48
|
+
// enable pretendToBeVisual by default since react needs
|
|
49
|
+
// window.requestAnimationFrame, see https://github.com/jsdom/jsdom#pretending-to-be-a-visual-browser
|
|
50
|
+
if (!('pretendToBeVisual' in options))
|
|
51
|
+
Object.assign(options, { pretendToBeVisual: true });
|
|
52
|
+
|
|
53
|
+
const jsdom = new JSDOM.JSDOM(html, options);
|
|
54
|
+
const { window } = jsdom;
|
|
55
|
+
const { document } = window;
|
|
56
|
+
|
|
57
|
+
// generate our list of keys by enumerating document.window - this list may vary
|
|
58
|
+
// based on the jsdom version. filter out internal methods as well as anything
|
|
59
|
+
// that node already defines
|
|
60
|
+
|
|
61
|
+
if (KEYS.length === 0) {
|
|
62
|
+
KEYS.push(...Object.getOwnPropertyNames(window).filter(k => !k.startsWith('_')).filter(k => !(k in global)));
|
|
63
|
+
// going to add our jsdom instance, see below
|
|
64
|
+
KEYS.push('$jsdom');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
KEYS.forEach(key => global[key] = window[key]);
|
|
68
|
+
|
|
69
|
+
// setup document / window / window.console
|
|
70
|
+
global.document = document;
|
|
71
|
+
global.window = window;
|
|
72
|
+
window.console = global.console;
|
|
73
|
+
|
|
74
|
+
// add access to our jsdom instance
|
|
75
|
+
global.$jsdom = jsdom;
|
|
76
|
+
|
|
77
|
+
const cleanup = () => KEYS.forEach(key => delete global[key]);
|
|
78
|
+
|
|
79
|
+
document.destroy = cleanup;
|
|
80
|
+
|
|
81
|
+
return cleanup
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
export { jsdomGlobal };
|
package/dist/index.cjs
CHANGED
|
@@ -25,7 +25,7 @@ function ViteReactSSG(routerOptions, fn, options = {}) {
|
|
|
25
25
|
rootContainer = "#root"
|
|
26
26
|
} = options;
|
|
27
27
|
const isClient = typeof window !== "undefined";
|
|
28
|
-
async function
|
|
28
|
+
async function createRoot(client = false, routePath) {
|
|
29
29
|
const browserRouter = client ? reactRouterDom.createBrowserRouter(routerOptions.routes) : void 0;
|
|
30
30
|
const appRenderCallbacks = [];
|
|
31
31
|
const onSSRAppRendered = client ? () => {
|
|
@@ -63,11 +63,11 @@ function ViteReactSSG(routerOptions, fn, options = {}) {
|
|
|
63
63
|
if (isClient) {
|
|
64
64
|
(async () => {
|
|
65
65
|
const container = typeof rootContainer === "string" ? document.querySelector(rootContainer) : rootContainer;
|
|
66
|
-
const { router } = await
|
|
66
|
+
const { router } = await createRoot(true);
|
|
67
67
|
client.hydrateRoot(container, /* @__PURE__ */ React__default.createElement(reactHelmetAsync.HelmetProvider, null, /* @__PURE__ */ React__default.createElement(SiteMetadataDefaults.SiteMetadataDefaults, null), /* @__PURE__ */ React__default.createElement(reactRouterDom.RouterProvider, { router })));
|
|
68
68
|
})();
|
|
69
69
|
}
|
|
70
|
-
return
|
|
70
|
+
return createRoot;
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
exports.Head = SiteMetadataDefaults.Head;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { R as RouterOptions, V as ViteReactSSGContext, a as ViteReactSSGClientOptions } from './types-
|
|
1
|
+
import { R as RouterOptions, V as ViteReactSSGContext, a as ViteReactSSGClientOptions } from './types-82f34756.js';
|
|
2
|
+
export { I as IndexRouteRecord, N as NonIndexRouteRecord, c as RouteRecord, b as ViteReactSSGOptions } from './types-82f34756.js';
|
|
2
3
|
import { ReactNode } from 'react';
|
|
3
4
|
import { HelmetProps } from 'react-helmet-async';
|
|
4
5
|
import 'critters';
|
|
@@ -11,4 +12,4 @@ declare function Head(props: Props): JSX.Element;
|
|
|
11
12
|
|
|
12
13
|
declare function ViteReactSSG(routerOptions: RouterOptions, fn?: (context: ViteReactSSGContext<true>) => Promise<void> | void, options?: ViteReactSSGClientOptions): (client?: boolean, routePath?: string) => Promise<ViteReactSSGContext<true>>;
|
|
13
14
|
|
|
14
|
-
export { Head, ViteReactSSG };
|
|
15
|
+
export { Head, RouterOptions, ViteReactSSG, ViteReactSSGClientOptions, ViteReactSSGContext };
|
package/dist/index.mjs
CHANGED
|
@@ -20,7 +20,7 @@ function ViteReactSSG(routerOptions, fn, options = {}) {
|
|
|
20
20
|
rootContainer = "#root"
|
|
21
21
|
} = options;
|
|
22
22
|
const isClient = typeof window !== "undefined";
|
|
23
|
-
async function
|
|
23
|
+
async function createRoot(client = false, routePath) {
|
|
24
24
|
const browserRouter = client ? createBrowserRouter(routerOptions.routes) : void 0;
|
|
25
25
|
const appRenderCallbacks = [];
|
|
26
26
|
const onSSRAppRendered = client ? () => {
|
|
@@ -58,11 +58,11 @@ function ViteReactSSG(routerOptions, fn, options = {}) {
|
|
|
58
58
|
if (isClient) {
|
|
59
59
|
(async () => {
|
|
60
60
|
const container = typeof rootContainer === "string" ? document.querySelector(rootContainer) : rootContainer;
|
|
61
|
-
const { router } = await
|
|
61
|
+
const { router } = await createRoot(true);
|
|
62
62
|
hydrateRoot(container, /* @__PURE__ */ React.createElement(HelmetProvider, null, /* @__PURE__ */ React.createElement(SiteMetadataDefaults, null), /* @__PURE__ */ React.createElement(RouterProvider, { router })));
|
|
63
63
|
})();
|
|
64
64
|
}
|
|
65
|
-
return
|
|
65
|
+
return createRoot;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
export { ViteReactSSG };
|
package/dist/node/cli.cjs
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const kolorist = require('kolorist');
|
|
4
4
|
const yargs = require('yargs');
|
|
5
5
|
const helpers = require('yargs/helpers');
|
|
6
|
-
const build = require('../shared/vite-react-ssg.
|
|
6
|
+
const build = require('../shared/vite-react-ssg.a5dfecac.cjs');
|
|
7
7
|
require('node:path');
|
|
8
8
|
require('node:module');
|
|
9
9
|
require('fs-extra');
|
package/dist/node/cli.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { gray, bold, red, reset, underline } from 'kolorist';
|
|
2
2
|
import yargs from 'yargs';
|
|
3
3
|
import { hideBin } from 'yargs/helpers';
|
|
4
|
-
import { b as build } from '../shared/vite-react-ssg.
|
|
4
|
+
import { b as build } from '../shared/vite-react-ssg.524ba00d.mjs';
|
|
5
5
|
import 'node:path';
|
|
6
6
|
import 'node:module';
|
|
7
7
|
import 'fs-extra';
|
package/dist/node.cjs
CHANGED
package/dist/node.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { InlineConfig } from 'vite';
|
|
2
|
-
import { b as ViteReactSSGOptions } from './types-
|
|
2
|
+
import { b as ViteReactSSGOptions } from './types-82f34756.js';
|
|
3
3
|
import 'critters';
|
|
4
|
-
import 'react';
|
|
5
4
|
import 'react-router-dom';
|
|
6
5
|
|
|
7
6
|
declare function build(ssgOptions?: Partial<ViteReactSSGOptions>, viteConfig?: InlineConfig): Promise<void>;
|
package/dist/node.mjs
CHANGED
|
@@ -858,23 +858,40 @@ function getSize(str) {
|
|
|
858
858
|
return `${(str.length / 1024).toFixed(2)} KiB`;
|
|
859
859
|
}
|
|
860
860
|
function routesToPaths(routes) {
|
|
861
|
+
const pathToEntry = {};
|
|
862
|
+
function addEntry(path, entry) {
|
|
863
|
+
if (!entry)
|
|
864
|
+
return;
|
|
865
|
+
if (pathToEntry[path])
|
|
866
|
+
pathToEntry[path].add(entry);
|
|
867
|
+
else
|
|
868
|
+
pathToEntry[path] = /* @__PURE__ */ new Set([entry]);
|
|
869
|
+
}
|
|
861
870
|
if (!routes)
|
|
862
|
-
return ["/"];
|
|
871
|
+
return { paths: ["/"], pathToEntry };
|
|
863
872
|
const paths = /* @__PURE__ */ new Set();
|
|
864
873
|
const getPaths = (routes2, prefix = "") => {
|
|
874
|
+
const parentPath = prefix;
|
|
865
875
|
prefix = prefix.replace(/\/$/g, "");
|
|
866
876
|
for (const route of routes2) {
|
|
867
877
|
let path = route.path;
|
|
868
878
|
if (route.path != null) {
|
|
869
879
|
path = prefix && !route.path.startsWith("/") ? `${prefix}${route.path ? `/${route.path}` : ""}` : route.path;
|
|
870
880
|
paths.add(path);
|
|
881
|
+
addEntry(path, route.entry);
|
|
882
|
+
if (pathToEntry[parentPath]) {
|
|
883
|
+
const pathCopy = path;
|
|
884
|
+
pathToEntry[parentPath].forEach((entry) => addEntry(pathCopy, entry));
|
|
885
|
+
}
|
|
871
886
|
}
|
|
887
|
+
if (route.index)
|
|
888
|
+
addEntry(prefix, route.entry);
|
|
872
889
|
if (Array.isArray(route.children))
|
|
873
890
|
getPaths(route.children, path);
|
|
874
891
|
}
|
|
875
892
|
};
|
|
876
893
|
getPaths(routes);
|
|
877
|
-
return Array.from(paths);
|
|
894
|
+
return { paths: Array.from(paths), pathToEntry };
|
|
878
895
|
}
|
|
879
896
|
|
|
880
897
|
async function getCritters(outDir, options = {}) {
|
|
@@ -946,17 +963,18 @@ async function render(routes, request) {
|
|
|
946
963
|
throw context;
|
|
947
964
|
const router = createStaticRouter(dataRoutes, context);
|
|
948
965
|
const app = /* @__PURE__ */ React.createElement(HelmetProvider, { context: helmetContext }, /* @__PURE__ */ React.createElement(SiteMetadataDefaults, null), /* @__PURE__ */ React.createElement(StaticRouterProvider, { router, context }));
|
|
949
|
-
const
|
|
966
|
+
const appHTML = await renderStaticApp(app);
|
|
950
967
|
const { helmet } = helmetContext;
|
|
951
|
-
helmet.htmlAttributes.toString();
|
|
952
|
-
helmet.bodyAttributes.toString();
|
|
953
|
-
[
|
|
968
|
+
const htmlAttributes = helmet.htmlAttributes.toString();
|
|
969
|
+
const bodyAttributes = helmet.bodyAttributes.toString();
|
|
970
|
+
const metaStrings = [
|
|
954
971
|
helmet.title.toString(),
|
|
955
972
|
helmet.meta.toString(),
|
|
956
973
|
helmet.link.toString(),
|
|
957
974
|
helmet.script.toString()
|
|
958
975
|
];
|
|
959
|
-
|
|
976
|
+
const metaAttributes = metaStrings.filter(Boolean);
|
|
977
|
+
return { appHTML, htmlAttributes, bodyAttributes, metaAttributes };
|
|
960
978
|
}
|
|
961
979
|
|
|
962
980
|
function renderPreloadLinks(document, modules, ssrManifest) {
|
|
@@ -1041,6 +1059,7 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1041
1059
|
buildLog("Build for client...");
|
|
1042
1060
|
await build$1(mergeConfig(viteConfig, {
|
|
1043
1061
|
build: {
|
|
1062
|
+
manifest: true,
|
|
1044
1063
|
ssrManifest: true,
|
|
1045
1064
|
rollupOptions: {
|
|
1046
1065
|
input: {
|
|
@@ -1079,41 +1098,46 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1079
1098
|
const ext = format === "esm" ? ".mjs" : ".cjs";
|
|
1080
1099
|
const serverEntry = join(prefix, ssgOut, parse(ssrEntry).name + ext);
|
|
1081
1100
|
const _require = createRequire(import.meta.url);
|
|
1082
|
-
const {
|
|
1101
|
+
const { createRoot, includedRoutes: serverEntryIncludedRoutes } = format === "esm" ? await import(serverEntry) : _require(serverEntry);
|
|
1083
1102
|
const includedRoutes = serverEntryIncludedRoutes || configIncludedRoutes;
|
|
1084
|
-
const { routes } = await
|
|
1085
|
-
|
|
1103
|
+
const { routes } = await createRoot(false);
|
|
1104
|
+
const { paths, pathToEntry } = routesToPaths(routes);
|
|
1105
|
+
let routesPaths = includeAllRoutes ? paths : await includedRoutes(paths, routes || []);
|
|
1086
1106
|
routesPaths = Array.from(new Set(routesPaths));
|
|
1087
1107
|
buildLog("Rendering Pages...", routesPaths.length);
|
|
1088
1108
|
const critters = crittersOptions !== false ? await getCritters(outDir, crittersOptions) : void 0;
|
|
1089
1109
|
if (critters)
|
|
1090
1110
|
console.log(`${gray("[vite-react-ssg]")} ${blue("Critical CSS generation enabled via `critters`")}`);
|
|
1091
1111
|
const ssrManifest = JSON.parse(await fs.readFile(join(out, "ssr-manifest.json"), "utf-8"));
|
|
1112
|
+
const manifest = JSON.parse(await fs.readFile(join(out, "manifest.json"), "utf-8"));
|
|
1092
1113
|
let indexHTML = await fs.readFile(join(out, "index.html"), "utf-8");
|
|
1093
1114
|
indexHTML = rewriteScripts(indexHTML, script);
|
|
1094
1115
|
const queue = new PQueue({ concurrency });
|
|
1095
1116
|
for (const route of routesPaths) {
|
|
1096
|
-
console.log("\u{1F680} ~ file: build.ts:132 ~ build ~ routesPaths:", routesPaths);
|
|
1097
1117
|
queue.add(async () => {
|
|
1098
1118
|
try {
|
|
1099
|
-
const appCtx = await
|
|
1100
|
-
const {
|
|
1119
|
+
const appCtx = await createRoot(false, route);
|
|
1120
|
+
const { routes: routes2, initialState, triggerOnSSRAppRendered, transformState = serializeState } = appCtx;
|
|
1101
1121
|
const transformedIndexHTML = await onBeforePageRender?.(route, indexHTML, appCtx);
|
|
1102
1122
|
const url = new URL(route, "http://vite-react-ssg.com");
|
|
1103
1123
|
url.search = "";
|
|
1104
1124
|
url.hash = "";
|
|
1105
1125
|
url.pathname = route;
|
|
1106
1126
|
const request = new Request(url.href);
|
|
1107
|
-
const appHTML = await render([...routes2], request);
|
|
1127
|
+
const { appHTML, bodyAttributes, htmlAttributes, metaAttributes } = await render([...routes2], request);
|
|
1108
1128
|
await triggerOnSSRAppRendered?.(route, appHTML, appCtx);
|
|
1109
1129
|
const renderedHTML = await renderHTML({
|
|
1110
1130
|
rootContainerId,
|
|
1111
1131
|
appHTML,
|
|
1112
1132
|
indexHTML,
|
|
1133
|
+
metaAttributes,
|
|
1134
|
+
bodyAttributes,
|
|
1135
|
+
htmlAttributes,
|
|
1113
1136
|
initialState: null
|
|
1114
1137
|
});
|
|
1115
1138
|
const jsdom = new JSDOM(renderedHTML);
|
|
1116
|
-
|
|
1139
|
+
const modules = collectModulesForEntrys(manifest, pathToEntry?.[route]);
|
|
1140
|
+
renderPreloadLinks(jsdom.window.document, modules, ssrManifest);
|
|
1117
1141
|
const html = jsdom.serialize();
|
|
1118
1142
|
let transformed = await onPageRendered?.(route, html, appCtx) || html;
|
|
1119
1143
|
if (critters)
|
|
@@ -1174,10 +1198,20 @@ async function renderHTML({
|
|
|
1174
1198
|
rootContainerId,
|
|
1175
1199
|
indexHTML,
|
|
1176
1200
|
appHTML,
|
|
1201
|
+
metaAttributes,
|
|
1202
|
+
bodyAttributes,
|
|
1203
|
+
htmlAttributes,
|
|
1177
1204
|
initialState
|
|
1178
1205
|
}) {
|
|
1179
1206
|
const stateScript = initialState ? `
|
|
1180
1207
|
<script>window.__INITIAL_STATE__=${initialState}<\/script>` : "";
|
|
1208
|
+
const headStartTag = "<head>";
|
|
1209
|
+
const metaTags = metaAttributes.join("");
|
|
1210
|
+
indexHTML = indexHTML.replace(headStartTag, headStartTag + metaTags);
|
|
1211
|
+
const bodyStartTag = "<body";
|
|
1212
|
+
indexHTML = indexHTML.replace(bodyStartTag, `${bodyStartTag} ${bodyAttributes}`);
|
|
1213
|
+
const htmlStartTag = "<html";
|
|
1214
|
+
indexHTML = indexHTML.replace(htmlStartTag, `${htmlStartTag} ${htmlAttributes}`);
|
|
1181
1215
|
const container = `<div id="${rootContainerId}"></div>`;
|
|
1182
1216
|
if (indexHTML.includes(container)) {
|
|
1183
1217
|
return indexHTML.replace(
|
|
@@ -1212,8 +1246,29 @@ async function formatHtml(html, formatting) {
|
|
|
1212
1246
|
minifyJS: true,
|
|
1213
1247
|
minifyCSS: true
|
|
1214
1248
|
});
|
|
1249
|
+
} else if (formatting === "prettify") {
|
|
1250
|
+
const prettier = (await import('prettier/esm/standalone.mjs')).default;
|
|
1251
|
+
const parserHTML = (await import('prettier/esm/parser-html.mjs')).default;
|
|
1252
|
+
return prettier.format(html, { semi: false, parser: "html", plugins: [parserHTML] });
|
|
1215
1253
|
}
|
|
1216
1254
|
return html;
|
|
1217
1255
|
}
|
|
1256
|
+
function collectModulesForEntrys(manifest, entrys) {
|
|
1257
|
+
const mods = /* @__PURE__ */ new Set();
|
|
1258
|
+
if (!entrys)
|
|
1259
|
+
return mods;
|
|
1260
|
+
for (const entry of entrys)
|
|
1261
|
+
collectModules(manifest, entry, mods);
|
|
1262
|
+
return mods;
|
|
1263
|
+
}
|
|
1264
|
+
function collectModules(manifest, entry, mods = /* @__PURE__ */ new Set()) {
|
|
1265
|
+
if (!entry)
|
|
1266
|
+
return mods;
|
|
1267
|
+
mods.add(entry);
|
|
1268
|
+
manifest[entry]?.dynamicImports?.forEach((item) => {
|
|
1269
|
+
collectModules(manifest, item, mods);
|
|
1270
|
+
});
|
|
1271
|
+
return mods;
|
|
1272
|
+
}
|
|
1218
1273
|
|
|
1219
1274
|
export { build as b };
|
|
@@ -865,23 +865,40 @@ function getSize(str) {
|
|
|
865
865
|
return `${(str.length / 1024).toFixed(2)} KiB`;
|
|
866
866
|
}
|
|
867
867
|
function routesToPaths(routes) {
|
|
868
|
+
const pathToEntry = {};
|
|
869
|
+
function addEntry(path, entry) {
|
|
870
|
+
if (!entry)
|
|
871
|
+
return;
|
|
872
|
+
if (pathToEntry[path])
|
|
873
|
+
pathToEntry[path].add(entry);
|
|
874
|
+
else
|
|
875
|
+
pathToEntry[path] = /* @__PURE__ */ new Set([entry]);
|
|
876
|
+
}
|
|
868
877
|
if (!routes)
|
|
869
|
-
return ["/"];
|
|
878
|
+
return { paths: ["/"], pathToEntry };
|
|
870
879
|
const paths = /* @__PURE__ */ new Set();
|
|
871
880
|
const getPaths = (routes2, prefix = "") => {
|
|
881
|
+
const parentPath = prefix;
|
|
872
882
|
prefix = prefix.replace(/\/$/g, "");
|
|
873
883
|
for (const route of routes2) {
|
|
874
884
|
let path = route.path;
|
|
875
885
|
if (route.path != null) {
|
|
876
886
|
path = prefix && !route.path.startsWith("/") ? `${prefix}${route.path ? `/${route.path}` : ""}` : route.path;
|
|
877
887
|
paths.add(path);
|
|
888
|
+
addEntry(path, route.entry);
|
|
889
|
+
if (pathToEntry[parentPath]) {
|
|
890
|
+
const pathCopy = path;
|
|
891
|
+
pathToEntry[parentPath].forEach((entry) => addEntry(pathCopy, entry));
|
|
892
|
+
}
|
|
878
893
|
}
|
|
894
|
+
if (route.index)
|
|
895
|
+
addEntry(prefix, route.entry);
|
|
879
896
|
if (Array.isArray(route.children))
|
|
880
897
|
getPaths(route.children, path);
|
|
881
898
|
}
|
|
882
899
|
};
|
|
883
900
|
getPaths(routes);
|
|
884
|
-
return Array.from(paths);
|
|
901
|
+
return { paths: Array.from(paths), pathToEntry };
|
|
885
902
|
}
|
|
886
903
|
|
|
887
904
|
async function getCritters(outDir, options = {}) {
|
|
@@ -953,17 +970,18 @@ async function render(routes, request) {
|
|
|
953
970
|
throw context;
|
|
954
971
|
const router = server_js.createStaticRouter(dataRoutes, context);
|
|
955
972
|
const app = /* @__PURE__ */ React__default.createElement(reactHelmetAsync.HelmetProvider, { context: helmetContext }, /* @__PURE__ */ React__default.createElement(SiteMetadataDefaults.SiteMetadataDefaults, null), /* @__PURE__ */ React__default.createElement(server_js.StaticRouterProvider, { router, context }));
|
|
956
|
-
const
|
|
973
|
+
const appHTML = await renderStaticApp(app);
|
|
957
974
|
const { helmet } = helmetContext;
|
|
958
|
-
helmet.htmlAttributes.toString();
|
|
959
|
-
helmet.bodyAttributes.toString();
|
|
960
|
-
[
|
|
975
|
+
const htmlAttributes = helmet.htmlAttributes.toString();
|
|
976
|
+
const bodyAttributes = helmet.bodyAttributes.toString();
|
|
977
|
+
const metaStrings = [
|
|
961
978
|
helmet.title.toString(),
|
|
962
979
|
helmet.meta.toString(),
|
|
963
980
|
helmet.link.toString(),
|
|
964
981
|
helmet.script.toString()
|
|
965
982
|
];
|
|
966
|
-
|
|
983
|
+
const metaAttributes = metaStrings.filter(Boolean);
|
|
984
|
+
return { appHTML, htmlAttributes, bodyAttributes, metaAttributes };
|
|
967
985
|
}
|
|
968
986
|
|
|
969
987
|
function renderPreloadLinks(document, modules, ssrManifest) {
|
|
@@ -1048,6 +1066,7 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1048
1066
|
buildLog("Build for client...");
|
|
1049
1067
|
await vite.build(vite.mergeConfig(viteConfig, {
|
|
1050
1068
|
build: {
|
|
1069
|
+
manifest: true,
|
|
1051
1070
|
ssrManifest: true,
|
|
1052
1071
|
rollupOptions: {
|
|
1053
1072
|
input: {
|
|
@@ -1085,42 +1104,47 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1085
1104
|
const prefix = format === "esm" && process.platform === "win32" ? "file://" : "";
|
|
1086
1105
|
const ext = format === "esm" ? ".mjs" : ".cjs";
|
|
1087
1106
|
const serverEntry = node_path.join(prefix, ssgOut, node_path.parse(ssrEntry).name + ext);
|
|
1088
|
-
const _require = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (document.currentScript && document.currentScript.src || new URL('shared/vite-react-ssg.
|
|
1089
|
-
const {
|
|
1107
|
+
const _require = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (document.currentScript && document.currentScript.src || new URL('shared/vite-react-ssg.a5dfecac.cjs', document.baseURI).href)));
|
|
1108
|
+
const { createRoot, includedRoutes: serverEntryIncludedRoutes } = format === "esm" ? await import(serverEntry) : _require(serverEntry);
|
|
1090
1109
|
const includedRoutes = serverEntryIncludedRoutes || configIncludedRoutes;
|
|
1091
|
-
const { routes } = await
|
|
1092
|
-
|
|
1110
|
+
const { routes } = await createRoot(false);
|
|
1111
|
+
const { paths, pathToEntry } = routesToPaths(routes);
|
|
1112
|
+
let routesPaths = includeAllRoutes ? paths : await includedRoutes(paths, routes || []);
|
|
1093
1113
|
routesPaths = Array.from(new Set(routesPaths));
|
|
1094
1114
|
buildLog("Rendering Pages...", routesPaths.length);
|
|
1095
1115
|
const critters = crittersOptions !== false ? await getCritters(outDir, crittersOptions) : void 0;
|
|
1096
1116
|
if (critters)
|
|
1097
1117
|
console.log(`${kolorist.gray("[vite-react-ssg]")} ${kolorist.blue("Critical CSS generation enabled via `critters`")}`);
|
|
1098
1118
|
const ssrManifest = JSON.parse(await fs__default.readFile(node_path.join(out, "ssr-manifest.json"), "utf-8"));
|
|
1119
|
+
const manifest = JSON.parse(await fs__default.readFile(node_path.join(out, "manifest.json"), "utf-8"));
|
|
1099
1120
|
let indexHTML = await fs__default.readFile(node_path.join(out, "index.html"), "utf-8");
|
|
1100
1121
|
indexHTML = rewriteScripts(indexHTML, script);
|
|
1101
1122
|
const queue = new PQueue({ concurrency });
|
|
1102
1123
|
for (const route of routesPaths) {
|
|
1103
|
-
console.log("\u{1F680} ~ file: build.ts:132 ~ build ~ routesPaths:", routesPaths);
|
|
1104
1124
|
queue.add(async () => {
|
|
1105
1125
|
try {
|
|
1106
|
-
const appCtx = await
|
|
1107
|
-
const {
|
|
1126
|
+
const appCtx = await createRoot(false, route);
|
|
1127
|
+
const { routes: routes2, initialState, triggerOnSSRAppRendered, transformState = SiteMetadataDefaults.serializeState } = appCtx;
|
|
1108
1128
|
const transformedIndexHTML = await onBeforePageRender?.(route, indexHTML, appCtx);
|
|
1109
1129
|
const url = new URL(route, "http://vite-react-ssg.com");
|
|
1110
1130
|
url.search = "";
|
|
1111
1131
|
url.hash = "";
|
|
1112
1132
|
url.pathname = route;
|
|
1113
1133
|
const request = new Request(url.href);
|
|
1114
|
-
const appHTML = await render([...routes2], request);
|
|
1134
|
+
const { appHTML, bodyAttributes, htmlAttributes, metaAttributes } = await render([...routes2], request);
|
|
1115
1135
|
await triggerOnSSRAppRendered?.(route, appHTML, appCtx);
|
|
1116
1136
|
const renderedHTML = await renderHTML({
|
|
1117
1137
|
rootContainerId,
|
|
1118
1138
|
appHTML,
|
|
1119
1139
|
indexHTML,
|
|
1140
|
+
metaAttributes,
|
|
1141
|
+
bodyAttributes,
|
|
1142
|
+
htmlAttributes,
|
|
1120
1143
|
initialState: null
|
|
1121
1144
|
});
|
|
1122
1145
|
const jsdom = new JSDOM.JSDOM(renderedHTML);
|
|
1123
|
-
|
|
1146
|
+
const modules = collectModulesForEntrys(manifest, pathToEntry?.[route]);
|
|
1147
|
+
renderPreloadLinks(jsdom.window.document, modules, ssrManifest);
|
|
1124
1148
|
const html = jsdom.serialize();
|
|
1125
1149
|
let transformed = await onPageRendered?.(route, html, appCtx) || html;
|
|
1126
1150
|
if (critters)
|
|
@@ -1181,10 +1205,20 @@ async function renderHTML({
|
|
|
1181
1205
|
rootContainerId,
|
|
1182
1206
|
indexHTML,
|
|
1183
1207
|
appHTML,
|
|
1208
|
+
metaAttributes,
|
|
1209
|
+
bodyAttributes,
|
|
1210
|
+
htmlAttributes,
|
|
1184
1211
|
initialState
|
|
1185
1212
|
}) {
|
|
1186
1213
|
const stateScript = initialState ? `
|
|
1187
1214
|
<script>window.__INITIAL_STATE__=${initialState}<\/script>` : "";
|
|
1215
|
+
const headStartTag = "<head>";
|
|
1216
|
+
const metaTags = metaAttributes.join("");
|
|
1217
|
+
indexHTML = indexHTML.replace(headStartTag, headStartTag + metaTags);
|
|
1218
|
+
const bodyStartTag = "<body";
|
|
1219
|
+
indexHTML = indexHTML.replace(bodyStartTag, `${bodyStartTag} ${bodyAttributes}`);
|
|
1220
|
+
const htmlStartTag = "<html";
|
|
1221
|
+
indexHTML = indexHTML.replace(htmlStartTag, `${htmlStartTag} ${htmlAttributes}`);
|
|
1188
1222
|
const container = `<div id="${rootContainerId}"></div>`;
|
|
1189
1223
|
if (indexHTML.includes(container)) {
|
|
1190
1224
|
return indexHTML.replace(
|
|
@@ -1219,8 +1253,29 @@ async function formatHtml(html, formatting) {
|
|
|
1219
1253
|
minifyJS: true,
|
|
1220
1254
|
minifyCSS: true
|
|
1221
1255
|
});
|
|
1256
|
+
} else if (formatting === "prettify") {
|
|
1257
|
+
const prettier = (await import('prettier/esm/standalone.mjs')).default;
|
|
1258
|
+
const parserHTML = (await import('prettier/esm/parser-html.mjs')).default;
|
|
1259
|
+
return prettier.format(html, { semi: false, parser: "html", plugins: [parserHTML] });
|
|
1222
1260
|
}
|
|
1223
1261
|
return html;
|
|
1224
1262
|
}
|
|
1263
|
+
function collectModulesForEntrys(manifest, entrys) {
|
|
1264
|
+
const mods = /* @__PURE__ */ new Set();
|
|
1265
|
+
if (!entrys)
|
|
1266
|
+
return mods;
|
|
1267
|
+
for (const entry of entrys)
|
|
1268
|
+
collectModules(manifest, entry, mods);
|
|
1269
|
+
return mods;
|
|
1270
|
+
}
|
|
1271
|
+
function collectModules(manifest, entry, mods = /* @__PURE__ */ new Set()) {
|
|
1272
|
+
if (!entry)
|
|
1273
|
+
return mods;
|
|
1274
|
+
mods.add(entry);
|
|
1275
|
+
manifest[entry]?.dynamicImports?.forEach((item) => {
|
|
1276
|
+
collectModules(manifest, item, mods);
|
|
1277
|
+
});
|
|
1278
|
+
return mods;
|
|
1279
|
+
}
|
|
1225
1280
|
|
|
1226
1281
|
exports.build = build;
|