vite-react-ssg 0.0.3 → 0.1.1
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 +307 -238
- 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 +103 -4
- package/dist/index.d.ts +14 -5
- package/dist/index.mjs +108 -12
- package/dist/node/cli.cjs +29 -5
- package/dist/node/cli.mjs +28 -4
- package/dist/node.cjs +5 -2
- package/dist/node.d.ts +5 -2
- package/dist/node.mjs +3 -1
- package/dist/shared/{vite-react-ssg.524ba00d.mjs → vite-react-ssg.5291bf32.mjs} +289 -69
- package/dist/shared/{vite-react-ssg.a5dfecac.cjs → vite-react-ssg.8cbf43cc.cjs} +289 -67
- package/dist/style-collectors.cjs +20 -0
- package/dist/style-collectors.d.ts +10 -0
- package/dist/style-collectors.mjs +18 -0
- package/dist/{types-82f34756.d.ts → types-408e974a.d.ts} +17 -1
- package/package.json +17 -2
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
|
|
6
|
+
const dev = require('../shared/vite-react-ssg.8cbf43cc.cjs');
|
|
7
7
|
require('node:path');
|
|
8
8
|
require('node:module');
|
|
9
9
|
require('fs-extra');
|
|
@@ -12,6 +12,8 @@ require('jsdom');
|
|
|
12
12
|
require('../shared/vite-react-ssg.4ca822c0.cjs');
|
|
13
13
|
require('react');
|
|
14
14
|
require('react-helmet-async');
|
|
15
|
+
require('express');
|
|
16
|
+
require('node:fs');
|
|
15
17
|
require('react-router-dom/server.js');
|
|
16
18
|
require('node:stream');
|
|
17
19
|
require('react-dom/server');
|
|
@@ -20,7 +22,7 @@ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'defau
|
|
|
20
22
|
|
|
21
23
|
const yargs__default = /*#__PURE__*/_interopDefaultCompat(yargs);
|
|
22
24
|
|
|
23
|
-
yargs__default(helpers.hideBin(process.argv)).scriptName("vite-ssg").usage("$0 [args]").command(
|
|
25
|
+
yargs__default(helpers.hideBin(process.argv)).scriptName("vite-react-ssg").usage("$0 [args]").command(
|
|
24
26
|
"build",
|
|
25
27
|
"Build SSG",
|
|
26
28
|
(args) => args.option("script", {
|
|
@@ -40,11 +42,33 @@ yargs__default(helpers.hideBin(process.argv)).scriptName("vite-ssg").usage("$0 [
|
|
|
40
42
|
}),
|
|
41
43
|
async (args) => {
|
|
42
44
|
const { config: configFile = void 0, ...ssgOptions } = args;
|
|
43
|
-
await
|
|
45
|
+
await dev.build(ssgOptions, { configFile });
|
|
46
|
+
}
|
|
47
|
+
).command(
|
|
48
|
+
"dev",
|
|
49
|
+
"Dev SSG",
|
|
50
|
+
(args) => args.option("script", {
|
|
51
|
+
choices: ["sync", "async", "defer", "async defer"],
|
|
52
|
+
describe: "Rewrites script loading timing"
|
|
53
|
+
}).option("mock", {
|
|
54
|
+
type: "boolean",
|
|
55
|
+
describe: "Mock browser globals (window, document, etc.) for SSG"
|
|
56
|
+
}).option("config", {
|
|
57
|
+
alias: "c",
|
|
58
|
+
type: "string",
|
|
59
|
+
describe: "The vite config file to use"
|
|
60
|
+
}).option("base", {
|
|
61
|
+
alias: "b",
|
|
62
|
+
type: "string",
|
|
63
|
+
describe: "The base path to render"
|
|
64
|
+
}),
|
|
65
|
+
async (args) => {
|
|
66
|
+
const { config: configFile = void 0, ...ssgOptions } = args;
|
|
67
|
+
await dev.dev(ssgOptions, { configFile });
|
|
44
68
|
}
|
|
45
69
|
).fail((msg, err, yargs2) => {
|
|
46
70
|
console.error(`
|
|
47
|
-
${kolorist.gray("[vite-ssg]")} ${kolorist.bold(kolorist.red("An internal error occurred."))}`);
|
|
48
|
-
console.error(`${kolorist.gray("[vite-ssg]")} ${kolorist.reset(`Please report an issue, if none already exists: ${kolorist.underline("https://github.com/
|
|
71
|
+
${kolorist.gray("[vite-react-ssg]")} ${kolorist.bold(kolorist.red("An internal error occurred."))}`);
|
|
72
|
+
console.error(`${kolorist.gray("[vite-react-ssg]")} ${kolorist.reset(`Please report an issue, if none already exists: ${kolorist.underline("https://github.com/daydreamer-riri/vite-react-ssg/issues")}`)}`);
|
|
49
73
|
yargs2.exit(1, err);
|
|
50
74
|
}).showHelpOnFail(false).help().argv;
|
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, d as dev } from '../shared/vite-react-ssg.5291bf32.mjs';
|
|
5
5
|
import 'node:path';
|
|
6
6
|
import 'node:module';
|
|
7
7
|
import 'fs-extra';
|
|
@@ -10,11 +10,13 @@ import 'jsdom';
|
|
|
10
10
|
import '../shared/vite-react-ssg.9d005d5e.mjs';
|
|
11
11
|
import 'react';
|
|
12
12
|
import 'react-helmet-async';
|
|
13
|
+
import 'express';
|
|
14
|
+
import 'node:fs';
|
|
13
15
|
import 'react-router-dom/server.js';
|
|
14
16
|
import 'node:stream';
|
|
15
17
|
import 'react-dom/server';
|
|
16
18
|
|
|
17
|
-
yargs(hideBin(process.argv)).scriptName("vite-ssg").usage("$0 [args]").command(
|
|
19
|
+
yargs(hideBin(process.argv)).scriptName("vite-react-ssg").usage("$0 [args]").command(
|
|
18
20
|
"build",
|
|
19
21
|
"Build SSG",
|
|
20
22
|
(args) => args.option("script", {
|
|
@@ -36,9 +38,31 @@ yargs(hideBin(process.argv)).scriptName("vite-ssg").usage("$0 [args]").command(
|
|
|
36
38
|
const { config: configFile = void 0, ...ssgOptions } = args;
|
|
37
39
|
await build(ssgOptions, { configFile });
|
|
38
40
|
}
|
|
41
|
+
).command(
|
|
42
|
+
"dev",
|
|
43
|
+
"Dev SSG",
|
|
44
|
+
(args) => args.option("script", {
|
|
45
|
+
choices: ["sync", "async", "defer", "async defer"],
|
|
46
|
+
describe: "Rewrites script loading timing"
|
|
47
|
+
}).option("mock", {
|
|
48
|
+
type: "boolean",
|
|
49
|
+
describe: "Mock browser globals (window, document, etc.) for SSG"
|
|
50
|
+
}).option("config", {
|
|
51
|
+
alias: "c",
|
|
52
|
+
type: "string",
|
|
53
|
+
describe: "The vite config file to use"
|
|
54
|
+
}).option("base", {
|
|
55
|
+
alias: "b",
|
|
56
|
+
type: "string",
|
|
57
|
+
describe: "The base path to render"
|
|
58
|
+
}),
|
|
59
|
+
async (args) => {
|
|
60
|
+
const { config: configFile = void 0, ...ssgOptions } = args;
|
|
61
|
+
await dev(ssgOptions, { configFile });
|
|
62
|
+
}
|
|
39
63
|
).fail((msg, err, yargs2) => {
|
|
40
64
|
console.error(`
|
|
41
|
-
${gray("[vite-ssg]")} ${bold(red("An internal error occurred."))}`);
|
|
42
|
-
console.error(`${gray("[vite-ssg]")} ${reset(`Please report an issue, if none already exists: ${underline("https://github.com/
|
|
65
|
+
${gray("[vite-react-ssg]")} ${bold(red("An internal error occurred."))}`);
|
|
66
|
+
console.error(`${gray("[vite-react-ssg]")} ${reset(`Please report an issue, if none already exists: ${underline("https://github.com/daydreamer-riri/vite-react-ssg/issues")}`)}`);
|
|
43
67
|
yargs2.exit(1, err);
|
|
44
68
|
}).showHelpOnFail(false).help().argv;
|
package/dist/node.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const dev = require('./shared/vite-react-ssg.8cbf43cc.cjs');
|
|
4
4
|
require('node:path');
|
|
5
5
|
require('node:module');
|
|
6
6
|
require('kolorist');
|
|
@@ -10,10 +10,13 @@ require('jsdom');
|
|
|
10
10
|
require('./shared/vite-react-ssg.4ca822c0.cjs');
|
|
11
11
|
require('react');
|
|
12
12
|
require('react-helmet-async');
|
|
13
|
+
require('express');
|
|
14
|
+
require('node:fs');
|
|
13
15
|
require('react-router-dom/server.js');
|
|
14
16
|
require('node:stream');
|
|
15
17
|
require('react-dom/server');
|
|
16
18
|
|
|
17
19
|
|
|
18
20
|
|
|
19
|
-
exports.build =
|
|
21
|
+
exports.build = dev.build;
|
|
22
|
+
exports.dev = dev.dev;
|
package/dist/node.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { InlineConfig } from 'vite';
|
|
2
|
-
import { b as ViteReactSSGOptions } from './types-
|
|
2
|
+
import { b as ViteReactSSGOptions } from './types-408e974a.js';
|
|
3
3
|
import 'critters';
|
|
4
|
+
import 'react';
|
|
4
5
|
import 'react-router-dom';
|
|
5
6
|
|
|
6
7
|
declare function build(ssgOptions?: Partial<ViteReactSSGOptions>, viteConfig?: InlineConfig): Promise<void>;
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
declare function dev(ssgOptions?: Partial<ViteReactSSGOptions>, viteConfig?: InlineConfig): Promise<void>;
|
|
10
|
+
|
|
11
|
+
export { build, dev };
|
package/dist/node.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { b as build } from './shared/vite-react-ssg.
|
|
1
|
+
export { b as build, d as dev } from './shared/vite-react-ssg.5291bf32.mjs';
|
|
2
2
|
import 'node:path';
|
|
3
3
|
import 'node:module';
|
|
4
4
|
import 'kolorist';
|
|
@@ -8,6 +8,8 @@ import 'jsdom';
|
|
|
8
8
|
import './shared/vite-react-ssg.9d005d5e.mjs';
|
|
9
9
|
import 'react';
|
|
10
10
|
import 'react-helmet-async';
|
|
11
|
+
import 'express';
|
|
12
|
+
import 'node:fs';
|
|
11
13
|
import 'react-router-dom/server.js';
|
|
12
14
|
import 'node:stream';
|
|
13
15
|
import 'react-dom/server';
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { join, isAbsolute, parse, dirname } from 'node:path';
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { gray, yellow, blue, dim, cyan, red, green } from 'kolorist';
|
|
3
|
+
import { gray, yellow, blue, dim, cyan, red, green, bold, reset, bgLightCyan } from 'kolorist';
|
|
4
4
|
import fs from 'fs-extra';
|
|
5
|
-
import { resolveConfig, build as build$1, mergeConfig } from 'vite';
|
|
5
|
+
import { resolveConfig, build as build$1, mergeConfig, createServer, version as version$1 } from 'vite';
|
|
6
6
|
import { JSDOM } from 'jsdom';
|
|
7
7
|
import { S as SiteMetadataDefaults, s as serializeState } from './vite-react-ssg.9d005d5e.mjs';
|
|
8
|
+
import express from 'express';
|
|
9
|
+
import { readFileSync } from 'node:fs';
|
|
8
10
|
import React from 'react';
|
|
9
11
|
import { HelmetProvider } from 'react-helmet-async';
|
|
10
12
|
import { createStaticHandler, createStaticRouter, StaticRouterProvider } from 'react-router-dom/server.js';
|
|
@@ -893,6 +895,39 @@ function routesToPaths(routes) {
|
|
|
893
895
|
getPaths(routes);
|
|
894
896
|
return { paths: Array.from(paths), pathToEntry };
|
|
895
897
|
}
|
|
898
|
+
function createFetchRequest(req) {
|
|
899
|
+
const origin = `${req.protocol}://${req.get("host")}`;
|
|
900
|
+
const url = new URL(req.originalUrl || req.url, origin);
|
|
901
|
+
const controller = new AbortController();
|
|
902
|
+
req.on("close", () => controller.abort());
|
|
903
|
+
const headers = new Headers();
|
|
904
|
+
for (const [key, values] of Object.entries(req.headers)) {
|
|
905
|
+
if (values) {
|
|
906
|
+
if (Array.isArray(values)) {
|
|
907
|
+
for (const value of values)
|
|
908
|
+
headers.append(key, value);
|
|
909
|
+
} else {
|
|
910
|
+
headers.set(key, values);
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
const init = {
|
|
915
|
+
method: req.method,
|
|
916
|
+
headers,
|
|
917
|
+
signal: controller.signal
|
|
918
|
+
};
|
|
919
|
+
if (req.method !== "GET" && req.method !== "HEAD")
|
|
920
|
+
init.body = req.body;
|
|
921
|
+
return new Request(url.href, init);
|
|
922
|
+
}
|
|
923
|
+
async function resolveAlias(config, entry) {
|
|
924
|
+
const resolver = config.createResolver();
|
|
925
|
+
const result = await resolver(entry, config.root);
|
|
926
|
+
return result || join(config.root, entry);
|
|
927
|
+
}
|
|
928
|
+
const { version } = JSON.parse(
|
|
929
|
+
readFileSync(new URL("../../package.json", import.meta.url)).toString()
|
|
930
|
+
);
|
|
896
931
|
|
|
897
932
|
async function getCritters(outDir, options = {}) {
|
|
898
933
|
try {
|
|
@@ -955,14 +990,16 @@ class WritableAsPromise extends Writable {
|
|
|
955
990
|
}
|
|
956
991
|
}
|
|
957
992
|
|
|
958
|
-
async function render(routes, request) {
|
|
993
|
+
async function render(routes, request, styleCollector) {
|
|
959
994
|
const { dataRoutes, query } = createStaticHandler(routes);
|
|
960
995
|
const context = await query(request);
|
|
961
996
|
const helmetContext = {};
|
|
962
997
|
if (context instanceof Response)
|
|
963
998
|
throw context;
|
|
964
999
|
const router = createStaticRouter(dataRoutes, context);
|
|
965
|
-
|
|
1000
|
+
let app = /* @__PURE__ */ React.createElement(HelmetProvider, { context: helmetContext }, /* @__PURE__ */ React.createElement(SiteMetadataDefaults, null), /* @__PURE__ */ React.createElement(StaticRouterProvider, { router, context }));
|
|
1001
|
+
if (styleCollector)
|
|
1002
|
+
app = styleCollector.collect(app);
|
|
966
1003
|
const appHTML = await renderStaticApp(app);
|
|
967
1004
|
const { helmet } = helmetContext;
|
|
968
1005
|
const htmlAttributes = helmet.htmlAttributes.toString();
|
|
@@ -973,6 +1010,8 @@ async function render(routes, request) {
|
|
|
973
1010
|
helmet.link.toString(),
|
|
974
1011
|
helmet.script.toString()
|
|
975
1012
|
];
|
|
1013
|
+
const styleTag = styleCollector?.toString?.(appHTML) ?? "";
|
|
1014
|
+
metaStrings.push(styleTag);
|
|
976
1015
|
const metaAttributes = metaStrings.filter(Boolean);
|
|
977
1016
|
return { appHTML, htmlAttributes, bodyAttributes, metaAttributes };
|
|
978
1017
|
}
|
|
@@ -1010,7 +1049,7 @@ function renderPreloadLink(document, file) {
|
|
|
1010
1049
|
});
|
|
1011
1050
|
}
|
|
1012
1051
|
}
|
|
1013
|
-
function createLink(document) {
|
|
1052
|
+
function createLink$1(document) {
|
|
1014
1053
|
return document.createElement("link");
|
|
1015
1054
|
}
|
|
1016
1055
|
function setAttrs(el, attrs) {
|
|
@@ -1022,11 +1061,68 @@ function appendLink(document, attrs) {
|
|
|
1022
1061
|
const exits = document.head.querySelector(`link[href='${attrs.file}']`);
|
|
1023
1062
|
if (exits)
|
|
1024
1063
|
return;
|
|
1025
|
-
const link = createLink(document);
|
|
1064
|
+
const link = createLink$1(document);
|
|
1026
1065
|
setAttrs(link, attrs);
|
|
1027
1066
|
document.head.appendChild(link);
|
|
1028
1067
|
}
|
|
1029
1068
|
|
|
1069
|
+
async function renderHTML({
|
|
1070
|
+
rootContainerId,
|
|
1071
|
+
indexHTML,
|
|
1072
|
+
appHTML,
|
|
1073
|
+
metaAttributes,
|
|
1074
|
+
bodyAttributes,
|
|
1075
|
+
htmlAttributes,
|
|
1076
|
+
initialState
|
|
1077
|
+
}) {
|
|
1078
|
+
const stateScript = initialState ? `
|
|
1079
|
+
<script>window.__INITIAL_STATE__=${initialState}<\/script>` : "";
|
|
1080
|
+
const headStartTag = "<head>";
|
|
1081
|
+
const metaTags = metaAttributes.join("");
|
|
1082
|
+
indexHTML = indexHTML.replace(headStartTag, headStartTag + metaTags);
|
|
1083
|
+
const bodyStartTag = "<body";
|
|
1084
|
+
indexHTML = indexHTML.replace(bodyStartTag, `${bodyStartTag} ${bodyAttributes}`);
|
|
1085
|
+
const htmlStartTag = "<html";
|
|
1086
|
+
indexHTML = indexHTML.replace(htmlStartTag, `${htmlStartTag} ${htmlAttributes}`);
|
|
1087
|
+
const container = `<div id="${rootContainerId}"></div>`;
|
|
1088
|
+
if (indexHTML.includes(container)) {
|
|
1089
|
+
return indexHTML.replace(
|
|
1090
|
+
container,
|
|
1091
|
+
`<div id="${rootContainerId}" data-server-rendered="true">${appHTML}</div>${stateScript}`
|
|
1092
|
+
);
|
|
1093
|
+
}
|
|
1094
|
+
const html5Parser = await import('html5parser');
|
|
1095
|
+
const ast = html5Parser.parse(indexHTML);
|
|
1096
|
+
let renderedOutput;
|
|
1097
|
+
html5Parser.walk(ast, {
|
|
1098
|
+
enter: (node) => {
|
|
1099
|
+
if (!renderedOutput && node?.type === html5Parser.SyntaxKind.Tag && Array.isArray(node.attributes) && node.attributes.length > 0 && node.attributes.some((attr) => attr.name.value === "id" && attr.value?.value === rootContainerId)) {
|
|
1100
|
+
const attributesStringified = [...node.attributes.map(({ name: { value: name }, value }) => `${name}="${value.value}"`)].join(" ");
|
|
1101
|
+
const indexHTMLBefore = indexHTML.slice(0, node.start);
|
|
1102
|
+
const indexHTMLAfter = indexHTML.slice(node.end);
|
|
1103
|
+
renderedOutput = `${indexHTMLBefore}<${node.name} ${attributesStringified} data-server-rendered="true">${appHTML}</${node.name}>${stateScript}${indexHTMLAfter}`;
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
});
|
|
1107
|
+
if (!renderedOutput)
|
|
1108
|
+
throw new Error(`Could not find a tag with id="${rootContainerId}" to replace it with server-side rendered HTML`);
|
|
1109
|
+
return renderedOutput;
|
|
1110
|
+
}
|
|
1111
|
+
async function detectEntry(root) {
|
|
1112
|
+
const scriptSrcReg = /<script(?:.*?)src=["'](.+?)["'](?!<)(?:.*)\>(?:[\n\r\s]*?)(?:<\/script>)/img;
|
|
1113
|
+
const html = await fs.readFile(join(root, "index.html"), "utf-8");
|
|
1114
|
+
const scripts = [...html.matchAll(scriptSrcReg)];
|
|
1115
|
+
const [, entry] = scripts.find((matchResult) => {
|
|
1116
|
+
const [script] = matchResult;
|
|
1117
|
+
const [, scriptType] = script.match(/.*\stype=(?:'|")?([^>'"\s]+)/i) || [];
|
|
1118
|
+
return scriptType === "module";
|
|
1119
|
+
}) || [];
|
|
1120
|
+
return entry || "src/main.ts";
|
|
1121
|
+
}
|
|
1122
|
+
function createLink(href) {
|
|
1123
|
+
return `<link rel="stylesheet" href="${href}">`;
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1030
1126
|
function DefaultIncludedRoutes(paths, _routes) {
|
|
1031
1127
|
return paths.filter((i) => !i.includes(":") && !i.includes("*"));
|
|
1032
1128
|
}
|
|
@@ -1117,19 +1213,20 @@ async function build(ssgOptions = {}, viteConfig = {}) {
|
|
|
1117
1213
|
queue.add(async () => {
|
|
1118
1214
|
try {
|
|
1119
1215
|
const appCtx = await createRoot(false, route);
|
|
1120
|
-
const { routes: routes2, initialState, triggerOnSSRAppRendered, transformState = serializeState } = appCtx;
|
|
1121
|
-
const
|
|
1216
|
+
const { routes: routes2, initialState, triggerOnSSRAppRendered, transformState = serializeState, getStyleCollector } = appCtx;
|
|
1217
|
+
const styleCollector = getStyleCollector ? await getStyleCollector() : null;
|
|
1218
|
+
const transformedIndexHTML = await onBeforePageRender?.(route, indexHTML, appCtx) || indexHTML;
|
|
1122
1219
|
const url = new URL(route, "http://vite-react-ssg.com");
|
|
1123
1220
|
url.search = "";
|
|
1124
1221
|
url.hash = "";
|
|
1125
1222
|
url.pathname = route;
|
|
1126
1223
|
const request = new Request(url.href);
|
|
1127
|
-
const { appHTML, bodyAttributes, htmlAttributes, metaAttributes } = await render([...routes2], request);
|
|
1224
|
+
const { appHTML, bodyAttributes, htmlAttributes, metaAttributes } = await render([...routes2], request, styleCollector);
|
|
1128
1225
|
await triggerOnSSRAppRendered?.(route, appHTML, appCtx);
|
|
1129
1226
|
const renderedHTML = await renderHTML({
|
|
1130
1227
|
rootContainerId,
|
|
1131
1228
|
appHTML,
|
|
1132
|
-
indexHTML,
|
|
1229
|
+
indexHTML: transformedIndexHTML,
|
|
1133
1230
|
metaAttributes,
|
|
1134
1231
|
bodyAttributes,
|
|
1135
1232
|
htmlAttributes,
|
|
@@ -1173,69 +1270,11 @@ ${gray("[vite-react-ssg]")} ${green("Build finished.")}`);
|
|
|
1173
1270
|
}, waitInSeconds * 1e3);
|
|
1174
1271
|
timeout.unref();
|
|
1175
1272
|
}
|
|
1176
|
-
async function detectEntry(root) {
|
|
1177
|
-
const scriptSrcReg = /<script(?:.*?)src=["'](.+?)["'](?!<)(?:.*)\>(?:[\n\r\s]*?)(?:<\/script>)/img;
|
|
1178
|
-
const html = await fs.readFile(join(root, "index.html"), "utf-8");
|
|
1179
|
-
const scripts = [...html.matchAll(scriptSrcReg)];
|
|
1180
|
-
const [, entry] = scripts.find((matchResult) => {
|
|
1181
|
-
const [script] = matchResult;
|
|
1182
|
-
const [, scriptType] = script.match(/.*\stype=(?:'|")?([^>'"\s]+)/i) || [];
|
|
1183
|
-
return scriptType === "module";
|
|
1184
|
-
}) || [];
|
|
1185
|
-
return entry || "src/main.ts";
|
|
1186
|
-
}
|
|
1187
|
-
async function resolveAlias(config, entry) {
|
|
1188
|
-
const resolver = config.createResolver();
|
|
1189
|
-
const result = await resolver(entry, config.root);
|
|
1190
|
-
return result || join(config.root, entry);
|
|
1191
|
-
}
|
|
1192
1273
|
function rewriteScripts(indexHTML, mode) {
|
|
1193
1274
|
if (!mode || mode === "sync")
|
|
1194
1275
|
return indexHTML;
|
|
1195
1276
|
return indexHTML.replace(/<script type="module" /g, `<script type="module" ${mode} `);
|
|
1196
1277
|
}
|
|
1197
|
-
async function renderHTML({
|
|
1198
|
-
rootContainerId,
|
|
1199
|
-
indexHTML,
|
|
1200
|
-
appHTML,
|
|
1201
|
-
metaAttributes,
|
|
1202
|
-
bodyAttributes,
|
|
1203
|
-
htmlAttributes,
|
|
1204
|
-
initialState
|
|
1205
|
-
}) {
|
|
1206
|
-
const stateScript = initialState ? `
|
|
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}`);
|
|
1215
|
-
const container = `<div id="${rootContainerId}"></div>`;
|
|
1216
|
-
if (indexHTML.includes(container)) {
|
|
1217
|
-
return indexHTML.replace(
|
|
1218
|
-
container,
|
|
1219
|
-
`<div id="${rootContainerId}" data-server-rendered="true">${appHTML}</div>${stateScript}`
|
|
1220
|
-
);
|
|
1221
|
-
}
|
|
1222
|
-
const html5Parser = await import('html5parser');
|
|
1223
|
-
const ast = html5Parser.parse(indexHTML);
|
|
1224
|
-
let renderedOutput;
|
|
1225
|
-
html5Parser.walk(ast, {
|
|
1226
|
-
enter: (node) => {
|
|
1227
|
-
if (!renderedOutput && node?.type === html5Parser.SyntaxKind.Tag && Array.isArray(node.attributes) && node.attributes.length > 0 && node.attributes.some((attr) => attr.name.value === "id" && attr.value?.value === rootContainerId)) {
|
|
1228
|
-
const attributesStringified = [...node.attributes.map(({ name: { value: name }, value }) => `${name}="${value.value}"`)].join(" ");
|
|
1229
|
-
const indexHTMLBefore = indexHTML.slice(0, node.start);
|
|
1230
|
-
const indexHTMLAfter = indexHTML.slice(node.end);
|
|
1231
|
-
renderedOutput = `${indexHTMLBefore}<${node.name} ${attributesStringified} data-server-rendered="true">${appHTML}</${node.name}>${stateScript}${indexHTMLAfter}`;
|
|
1232
|
-
}
|
|
1233
|
-
}
|
|
1234
|
-
});
|
|
1235
|
-
if (!renderedOutput)
|
|
1236
|
-
throw new Error(`Could not find a tag with id="${rootContainerId}" to replace it with server-side rendered HTML`);
|
|
1237
|
-
return renderedOutput;
|
|
1238
|
-
}
|
|
1239
1278
|
async function formatHtml(html, formatting) {
|
|
1240
1279
|
if (formatting === "minify") {
|
|
1241
1280
|
const htmlMinifier = await import('html-minifier');
|
|
@@ -1271,4 +1310,185 @@ function collectModules(manifest, entry, mods = /* @__PURE__ */ new Set()) {
|
|
|
1271
1310
|
return mods;
|
|
1272
1311
|
}
|
|
1273
1312
|
|
|
1274
|
-
|
|
1313
|
+
const SHORTCUTS = [
|
|
1314
|
+
{
|
|
1315
|
+
key: "u",
|
|
1316
|
+
description: "show server url",
|
|
1317
|
+
action(vite, _) {
|
|
1318
|
+
vite.config.logger.info("");
|
|
1319
|
+
printServerInfo(vite, true);
|
|
1320
|
+
}
|
|
1321
|
+
},
|
|
1322
|
+
{
|
|
1323
|
+
key: "c",
|
|
1324
|
+
description: "clear console",
|
|
1325
|
+
action(vite, _) {
|
|
1326
|
+
vite.config.logger.clearScreen("error");
|
|
1327
|
+
}
|
|
1328
|
+
},
|
|
1329
|
+
{
|
|
1330
|
+
key: "q",
|
|
1331
|
+
description: "quit",
|
|
1332
|
+
action(_, server) {
|
|
1333
|
+
server.close(() => process.exit());
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
];
|
|
1337
|
+
function bindShortcuts(viteServer, server) {
|
|
1338
|
+
if (!process.stdin.isTTY || process.env.CI)
|
|
1339
|
+
return;
|
|
1340
|
+
viteServer.config.logger.info(
|
|
1341
|
+
dim(green(" \u279C")) + dim(" press ") + bold("h") + dim(" to show help")
|
|
1342
|
+
);
|
|
1343
|
+
const shortcuts = SHORTCUTS;
|
|
1344
|
+
let actionRunning = false;
|
|
1345
|
+
const onInput = async (input) => {
|
|
1346
|
+
if (input === "" || input === "") {
|
|
1347
|
+
try {
|
|
1348
|
+
await server.close();
|
|
1349
|
+
} finally {
|
|
1350
|
+
process.exit(1);
|
|
1351
|
+
}
|
|
1352
|
+
return;
|
|
1353
|
+
}
|
|
1354
|
+
if (actionRunning)
|
|
1355
|
+
return;
|
|
1356
|
+
if (input === "h") {
|
|
1357
|
+
viteServer.config.logger.info(
|
|
1358
|
+
[
|
|
1359
|
+
"",
|
|
1360
|
+
bold(" Shortcuts"),
|
|
1361
|
+
...shortcuts.map(
|
|
1362
|
+
(shortcut2) => dim(" press ") + bold(shortcut2.key) + dim(` to ${shortcut2.description}`)
|
|
1363
|
+
)
|
|
1364
|
+
].join("\n")
|
|
1365
|
+
);
|
|
1366
|
+
}
|
|
1367
|
+
const shortcut = shortcuts.find((shortcut2) => shortcut2.key === input);
|
|
1368
|
+
if (!shortcut)
|
|
1369
|
+
return;
|
|
1370
|
+
actionRunning = true;
|
|
1371
|
+
await shortcut.action(viteServer, server);
|
|
1372
|
+
actionRunning = false;
|
|
1373
|
+
};
|
|
1374
|
+
process.stdin.setRawMode(true);
|
|
1375
|
+
process.stdin.on("data", onInput).setEncoding("utf8").resume();
|
|
1376
|
+
server.on("close", () => {
|
|
1377
|
+
process.stdin.off("data", onInput).pause();
|
|
1378
|
+
});
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
async function dev(ssgOptions = {}, viteConfig = {}) {
|
|
1382
|
+
const mode = process.env.MODE || process.env.NODE_ENV || ssgOptions.mode || "development";
|
|
1383
|
+
const config = await resolveConfig(viteConfig, "serve", mode, mode);
|
|
1384
|
+
const cwd = process.cwd();
|
|
1385
|
+
const root = config.root || cwd;
|
|
1386
|
+
const {
|
|
1387
|
+
entry = await detectEntry(root),
|
|
1388
|
+
onBeforePageRender,
|
|
1389
|
+
onPageRendered,
|
|
1390
|
+
rootContainerId = "root"
|
|
1391
|
+
} = Object.assign({}, config.ssgOptions || {}, ssgOptions);
|
|
1392
|
+
const ssrEntry = await resolveAlias(config, entry);
|
|
1393
|
+
const template = await fs.readFile(join(root, "index.html"), "utf-8");
|
|
1394
|
+
let viteServer;
|
|
1395
|
+
globalThis.__ssr_start_time = performance.now();
|
|
1396
|
+
createServer$1().then((app) => {
|
|
1397
|
+
const port = viteServer.config.server.port || 5173;
|
|
1398
|
+
const server = app.listen(port, () => {
|
|
1399
|
+
printServerInfo(viteServer);
|
|
1400
|
+
bindShortcuts(viteServer, server);
|
|
1401
|
+
});
|
|
1402
|
+
});
|
|
1403
|
+
async function createServer$1() {
|
|
1404
|
+
process.env.__DEV_MODE_SSR = "true";
|
|
1405
|
+
const app = express();
|
|
1406
|
+
viteServer = await createServer({
|
|
1407
|
+
// ...options,
|
|
1408
|
+
server: { middlewareMode: true },
|
|
1409
|
+
appType: "custom"
|
|
1410
|
+
});
|
|
1411
|
+
app.use(viteServer.middlewares);
|
|
1412
|
+
app.use("*", async (req, res) => {
|
|
1413
|
+
try {
|
|
1414
|
+
const url = req.originalUrl;
|
|
1415
|
+
const indexHTML = await viteServer.transformIndexHtml(url, template);
|
|
1416
|
+
const createRoot = await viteServer.ssrLoadModule(ssrEntry).then((m) => m.createRoot);
|
|
1417
|
+
const appCtx = await createRoot(false, url);
|
|
1418
|
+
const { routes, getStyleCollector } = appCtx;
|
|
1419
|
+
const transformedIndexHTML = await onBeforePageRender?.(url, indexHTML, appCtx) || indexHTML;
|
|
1420
|
+
const styleCollector = getStyleCollector ? await getStyleCollector() : null;
|
|
1421
|
+
const { appHTML, bodyAttributes, htmlAttributes, metaAttributes } = await render([...routes], createFetchRequest(req), styleCollector);
|
|
1422
|
+
const mod = await viteServer.moduleGraph.getModuleByUrl(entry);
|
|
1423
|
+
const assetsUrls = /* @__PURE__ */ new Set();
|
|
1424
|
+
const collectAssets = async (mod2) => {
|
|
1425
|
+
if (!mod2?.ssrTransformResult)
|
|
1426
|
+
return;
|
|
1427
|
+
const { deps = [], dynamicDeps = [] } = mod2?.ssrTransformResult;
|
|
1428
|
+
const allDeps = [...deps, ...dynamicDeps];
|
|
1429
|
+
for (const dep of allDeps) {
|
|
1430
|
+
if (dep.endsWith(".css")) {
|
|
1431
|
+
assetsUrls.add(dep);
|
|
1432
|
+
} else if (dep.endsWith(".ts") || dep.endsWith(".tsx")) {
|
|
1433
|
+
const depModule = await viteServer.moduleGraph.getModuleByUrl(dep);
|
|
1434
|
+
depModule && await collectAssets(depModule);
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
};
|
|
1438
|
+
await collectAssets(mod);
|
|
1439
|
+
const preloadLink = [...assetsUrls].map((item) => createLink(item));
|
|
1440
|
+
metaAttributes.push(...preloadLink);
|
|
1441
|
+
const renderedHTML = await renderHTML({
|
|
1442
|
+
rootContainerId,
|
|
1443
|
+
appHTML,
|
|
1444
|
+
indexHTML: transformedIndexHTML,
|
|
1445
|
+
metaAttributes,
|
|
1446
|
+
bodyAttributes,
|
|
1447
|
+
htmlAttributes,
|
|
1448
|
+
initialState: null
|
|
1449
|
+
});
|
|
1450
|
+
const transformed = await onPageRendered?.(url, renderedHTML, appCtx) || renderedHTML;
|
|
1451
|
+
res.status(200).set({ "Content-Type": "text/html" }).end(transformed);
|
|
1452
|
+
} catch (e) {
|
|
1453
|
+
viteServer.ssrFixStacktrace(e);
|
|
1454
|
+
console.error(`[vite-react-ssg] error: ${e.stack}`);
|
|
1455
|
+
res.status(500).end(e.stack);
|
|
1456
|
+
}
|
|
1457
|
+
});
|
|
1458
|
+
return app;
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
async function printServerInfo(server, onlyUrl = false) {
|
|
1462
|
+
const info = server.config.logger.info;
|
|
1463
|
+
const port = server.config.server.port || 5173;
|
|
1464
|
+
const url = `http://localhost:${port}/`;
|
|
1465
|
+
if (!onlyUrl) {
|
|
1466
|
+
let ssrReadyMessage = " -- SSR";
|
|
1467
|
+
if (globalThis.__ssr_start_time) {
|
|
1468
|
+
ssrReadyMessage += ` ready in ${reset(bold(`${Math.round(
|
|
1469
|
+
// @ts-expect-error global var
|
|
1470
|
+
performance.now() - globalThis.__ssr_start_time
|
|
1471
|
+
)}ms`))}`;
|
|
1472
|
+
}
|
|
1473
|
+
info(
|
|
1474
|
+
`
|
|
1475
|
+
${bgLightCyan(` VITE-REACT-SSG v${version} `)}`,
|
|
1476
|
+
{ clear: !server.config.logger.hasWarned }
|
|
1477
|
+
);
|
|
1478
|
+
info(
|
|
1479
|
+
`${cyan(`
|
|
1480
|
+
VITE v${version$1}`) + dim(ssrReadyMessage)}
|
|
1481
|
+
`
|
|
1482
|
+
);
|
|
1483
|
+
}
|
|
1484
|
+
info(
|
|
1485
|
+
green(" dev server running at:")
|
|
1486
|
+
);
|
|
1487
|
+
printUrls(url, info);
|
|
1488
|
+
}
|
|
1489
|
+
function printUrls(url, info) {
|
|
1490
|
+
const colorUrl = (url2) => cyan(url2.replace(/:(\d+)\//, (_, port) => `:${bold(port)}/`));
|
|
1491
|
+
info(` ${green("\u279C")} ${bold("Local")}: ${colorUrl(url)}`);
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
export { build as b, dev as d };
|