vite-react-ssg 0.8.4 → 0.8.5

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.
Files changed (43) hide show
  1. package/README.md +10 -8
  2. package/dist/client/single-page.d.mts +4 -4
  3. package/dist/client/single-page.d.ts +4 -4
  4. package/dist/client/single-page.mjs +7 -6
  5. package/dist/index.d.mts +5 -4
  6. package/dist/index.d.ts +5 -4
  7. package/dist/index.mjs +10 -8
  8. package/dist/node/cli.mjs +9 -9
  9. package/dist/node.d.mts +2 -2
  10. package/dist/node.d.ts +2 -2
  11. package/dist/node.mjs +7 -7
  12. package/dist/shared/{vite-react-ssg.Cm9gBlfg.d.ts → vite-react-ssg.-NlgsPvg.d.mts} +8 -8
  13. package/dist/shared/{vite-react-ssg.Cm9gBlfg.d.mts → vite-react-ssg.-NlgsPvg.d.ts} +8 -8
  14. package/dist/shared/{vite-react-ssg.C0y5wbxl.mjs → vite-react-ssg.C_MPXL9p.mjs} +1 -1
  15. package/dist/shared/{vite-react-ssg.Di0pROyF.d.cts → vite-react-ssg.D2OE2Bw1.d.mts} +6 -1
  16. package/dist/shared/{vite-react-ssg.Di0pROyF.d.mts → vite-react-ssg.D2OE2Bw1.d.ts} +6 -1
  17. package/dist/shared/{vite-react-ssg.CfJcpdWF.mjs → vite-react-ssg.Dx4ca9OM.mjs} +18 -4
  18. package/dist/shared/{vite-react-ssg.CKcl-j8g.mjs → vite-react-ssg.EDckwhJo.mjs} +222 -218
  19. package/dist/tanstack.d.mts +5 -4
  20. package/dist/tanstack.d.ts +5 -4
  21. package/dist/tanstack.mjs +9 -7
  22. package/package.json +32 -33
  23. package/dist/chunks/jsdomGlobal.cjs +0 -36
  24. package/dist/client/single-page.cjs +0 -75
  25. package/dist/client/single-page.d.cts +0 -11
  26. package/dist/index.cjs +0 -196
  27. package/dist/index.d.cts +0 -26
  28. package/dist/node/cli.cjs +0 -89
  29. package/dist/node/cli.d.cts +0 -2
  30. package/dist/node.cjs +0 -24
  31. package/dist/node.d.cts +0 -11
  32. package/dist/shared/vite-react-ssg.B4jDfvXh.cjs +0 -106
  33. package/dist/shared/vite-react-ssg.C2GpVZF1.cjs +0 -38
  34. package/dist/shared/vite-react-ssg.CFQGqC60.cjs +0 -36
  35. package/dist/shared/vite-react-ssg.CjsEygxB.cjs +0 -37
  36. package/dist/shared/vite-react-ssg.Cm9gBlfg.d.cts +0 -15
  37. package/dist/shared/vite-react-ssg.DWHmkjdM.cjs +0 -35
  38. package/dist/shared/vite-react-ssg.Di0pROyF.d.ts +0 -214
  39. package/dist/shared/vite-react-ssg.Dus0yLsZ.cjs +0 -1082
  40. package/dist/style-collectors/styled-components.cjs +0 -20
  41. package/dist/style-collectors/styled-components.d.cts +0 -9
  42. package/dist/tanstack.cjs +0 -144
  43. package/dist/tanstack.d.cts +0 -30
@@ -1,1082 +0,0 @@
1
- 'use strict';
2
-
3
- const node_path = require('node:path');
4
- const node_module = require('node:module');
5
- const kolorist = require('kolorist');
6
- const PQueue = require('p-queue');
7
- const fs = require('fs-extra');
8
- const vite = require('vite');
9
- const JSDOM = require('jsdom');
10
- const state = require('./vite-react-ssg.CjsEygxB.cjs');
11
- const path = require('./vite-react-ssg.CFQGqC60.cjs');
12
- const jsxRuntime = require('react/jsx-runtime');
13
- const reactHelmetAsync = require('react-helmet-async');
14
- const node_stream = require('node:stream');
15
- const ReactDomServer = require('react-dom/server');
16
- const node_events = require('node:events');
17
- const remixRouter = require('./vite-react-ssg.C2GpVZF1.cjs');
18
- const tanstackRouter = require('./vite-react-ssg.DWHmkjdM.cjs');
19
-
20
- var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
21
- function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
22
-
23
- function _interopNamespaceCompat(e) {
24
- if (e && typeof e === 'object' && 'default' in e) return e;
25
- const n = Object.create(null);
26
- if (e) {
27
- for (const k in e) {
28
- n[k] = e[k];
29
- }
30
- }
31
- n.default = e;
32
- return n;
33
- }
34
-
35
- const PQueue__default = /*#__PURE__*/_interopDefaultCompat(PQueue);
36
- const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
37
- const ReactDomServer__namespace = /*#__PURE__*/_interopNamespaceCompat(ReactDomServer);
38
-
39
- const version = "0.8.4";
40
-
41
- function buildLog(text, count) {
42
- console.log(`
43
- ${kolorist.gray("[vite-react-ssg]")} ${kolorist.yellow(text)}${count ? kolorist.blue(` (${count})`) : ""}`);
44
- }
45
- function getSize(str) {
46
- return `${(str.length / 1024).toFixed(2)} KiB`;
47
- }
48
- async function routesToPaths(routes) {
49
- if (!routes || routes.length === 0)
50
- return { paths: ["/"] };
51
- const paths = /* @__PURE__ */ new Set();
52
- const getPaths = async (routes2, prefix = "") => {
53
- prefix = prefix.replace(/\/$/g, "");
54
- for (let route of routes2) {
55
- if (route.lazy) {
56
- const lazyData = await route.lazy();
57
- if (lazyData) {
58
- route = {
59
- ...route,
60
- ...lazyData
61
- };
62
- }
63
- }
64
- let path = route.path;
65
- path = handlePath(path, prefix);
66
- if (route.getStaticPaths && isDynamicSegmentsRoute(path)) {
67
- const staticPaths = await route.getStaticPaths();
68
- for (let staticPath of staticPaths) {
69
- staticPath = handlePath(staticPath, prefix);
70
- if (Array.isArray(route.children))
71
- await getPaths(route.children, staticPath);
72
- }
73
- }
74
- if (route.index && !path) {
75
- paths.add("/");
76
- }
77
- if (Array.isArray(route.children))
78
- await getPaths(route.children, path);
79
- }
80
- };
81
- await getPaths(routes);
82
- return { paths: Array.from(paths) };
83
- function handlePath(path, prefix) {
84
- if (path != null) {
85
- path = prefix && !path.startsWith("/") ? `${prefix}${path ? `/${path}` : ""}` : path;
86
- paths.add(path);
87
- }
88
- return path;
89
- }
90
- }
91
- async function resolveAlias(config, entry) {
92
- const resolver = config.createResolver();
93
- const result = await resolver(entry, config.root);
94
- return result || node_path.join(config.root, entry);
95
- }
96
- function createRequest(path) {
97
- const url = new URL(path, "http://vite-react-ssg.com");
98
- url.search = "";
99
- url.hash = "";
100
- url.pathname = path;
101
- return new Request(url.href);
102
- }
103
- const dynamicRE = /[:*?]/;
104
- function isDynamicSegmentsRoute(route) {
105
- if (!route)
106
- return false;
107
- return dynamicRE.test(route);
108
- }
109
-
110
- async function getBeastiesOrCritters(outDir, options = {}) {
111
- try {
112
- const BeastiesClass = (await import('beasties')).default;
113
- return new BeastiesClass({
114
- path: outDir,
115
- logLevel: "warn",
116
- external: true,
117
- inlineFonts: true,
118
- preloadFonts: true,
119
- ...options
120
- });
121
- } catch {
122
- }
123
- try {
124
- const CrittersClass = (await import('critters')).default;
125
- console.warn("`critters` is deprecated. Please use `beasties` instead.");
126
- return new CrittersClass({
127
- path: outDir,
128
- logLevel: "warn",
129
- external: true,
130
- inlineFonts: true,
131
- preloadFonts: true,
132
- ...options
133
- });
134
- } catch (e) {
135
- return void 0;
136
- }
137
- }
138
-
139
- const SCRIPT_COMMENT_PLACEHOLDER = "/* SCRIPT_COMMENT_PLACEHOLDER */";
140
- async function renderHTML({
141
- rootContainerId,
142
- indexHTML,
143
- appHTML,
144
- metaAttributes,
145
- bodyAttributes,
146
- htmlAttributes,
147
- initialState
148
- }) {
149
- const stateScript = initialState ? `
150
- <script>window.__INITIAL_STATE__=${initialState}<\/script>` : "";
151
- const scriptPlaceHolder = `
152
- <script>${SCRIPT_COMMENT_PLACEHOLDER}<\/script>`;
153
- const headStartTag = "<head>";
154
- const metaTags = metaAttributes.join("");
155
- indexHTML = indexHTML.replace(headStartTag, headStartTag + metaTags);
156
- const bodyStartTag = "<body";
157
- indexHTML = indexHTML.replace(bodyStartTag, `${bodyStartTag} ${bodyAttributes}`);
158
- const htmlStartTag = "<html";
159
- indexHTML = indexHTML.replace(htmlStartTag, `${htmlStartTag} ${htmlAttributes}`);
160
- const container = `<div id="${rootContainerId}"></div>`;
161
- if (indexHTML.includes(container)) {
162
- return indexHTML.replace(
163
- container,
164
- `<div id="${rootContainerId}" data-server-rendered="true">${appHTML}</div>${stateScript}${scriptPlaceHolder}`
165
- );
166
- }
167
- const html5Parser = await import('html5parser');
168
- const ast = html5Parser.parse(indexHTML);
169
- let renderedOutput;
170
- html5Parser.walk(ast, {
171
- enter: (node) => {
172
- 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)) {
173
- const attributesStringified = [...node.attributes.map(({ name: { value: name }, value }) => `${name}="${value.value}"`)].join(" ");
174
- const indexHTMLBefore = indexHTML.slice(0, node.start);
175
- const indexHTMLAfter = indexHTML.slice(node.end);
176
- renderedOutput = `${indexHTMLBefore}<${node.name} ${attributesStringified} data-server-rendered="true">${appHTML}</${node.name}>${stateScript}${scriptPlaceHolder}${indexHTMLAfter}`;
177
- }
178
- }
179
- });
180
- if (!renderedOutput)
181
- throw new Error(`Could not find a tag with id="${rootContainerId}" to replace it with server-side rendered HTML`);
182
- return renderedOutput;
183
- }
184
- async function detectEntry(root) {
185
- const scriptSrcReg = /<script(?:.*?)src=["'](.+?)["'](?!<)(?:.*)\>(?:[\n\r\s]*?)(?:<\/script>)/gim;
186
- const html = await fs__default.readFile(node_path.join(root, "index.html"), "utf-8");
187
- const scripts = [...html.matchAll(scriptSrcReg)];
188
- const [, entry] = scripts.find((matchResult) => {
189
- const [script] = matchResult;
190
- const [, scriptType] = script.match(/.*\stype=(?:'|")?([^>'"\s]+)/i) || [];
191
- return scriptType === "module";
192
- }) || [];
193
- return entry || "src/main.ts";
194
- }
195
- function createLink$1(href) {
196
- return `<link rel="stylesheet" href="${href}">`;
197
- }
198
-
199
- function renderPreloadLinks(document, assets) {
200
- const seen = /* @__PURE__ */ new Set();
201
- if (assets) {
202
- assets.forEach((file) => {
203
- if (!seen.has(file)) {
204
- seen.add(file);
205
- renderPreloadLink(document, file);
206
- }
207
- });
208
- }
209
- }
210
- function renderPreloadLink(document, file) {
211
- if (file.endsWith(".js")) {
212
- appendLink(document, {
213
- rel: "modulepreload",
214
- crossOrigin: "",
215
- href: file
216
- });
217
- } else if (file.endsWith(".css")) {
218
- appendLink(document, {
219
- rel: "stylesheet",
220
- href: file,
221
- crossOrigin: ""
222
- });
223
- } else if (file.endsWith(".woff") || file.endsWith(".woff2") || file.endsWith(".ttf")) {
224
- appendLink(document, {
225
- rel: "preload",
226
- as: "font",
227
- type: "font/woff2",
228
- href: file,
229
- crossOrigin: ""
230
- });
231
- } else if (file.endsWith(".png") || file.endsWith(".jpg") || file.endsWith(".jpeg") || file.endsWith(".webp") || file.endsWith(".gif") || file.endsWith(".ico") || file.endsWith(".svg")) {
232
- appendLink(document, {
233
- rel: "preload",
234
- as: "image",
235
- href: file,
236
- crossOrigin: ""
237
- });
238
- }
239
- }
240
- function createLink(document) {
241
- return document.createElement("link");
242
- }
243
- function setAttrs(el, attrs) {
244
- const keys = Object.keys(attrs);
245
- for (const key of keys)
246
- el.setAttribute(key, attrs[key]);
247
- }
248
- function appendLink(document, attrs) {
249
- const exits = document.head.querySelector(`link[href='${attrs.file}']`);
250
- if (exits)
251
- return;
252
- const link = createLink(document);
253
- setAttrs(link, attrs);
254
- document.head.appendChild(link);
255
- }
256
-
257
- const DYNAMIC_IMPORT_REGEX = /import\("([^)]+)"\)/g;
258
- async function collectAssets({
259
- routes,
260
- locationArg,
261
- base,
262
- serverManifest,
263
- manifest,
264
- ssrManifest
265
- }) {
266
- const { matchRoutes } = await import('react-router-dom');
267
- const matches = matchRoutes([...routes], locationArg, base);
268
- const routeEntries = matches?.map((item) => item.route.entry).filter(Boolean) ?? [];
269
- const dynamicImports = /* @__PURE__ */ new Set();
270
- matches?.forEach((item) => {
271
- let lazyStr = "";
272
- if (item.route.lazy) {
273
- lazyStr += item.route.lazy.toString();
274
- }
275
- if (item.route.Component?._payload?._result) {
276
- lazyStr += item.route.Component._payload._result.toString();
277
- }
278
- const match = lazyStr.matchAll(DYNAMIC_IMPORT_REGEX);
279
- for (const m of match) {
280
- dynamicImports.add(m[1].split("/").at(-1) ?? "");
281
- }
282
- });
283
- const entries = /* @__PURE__ */ new Set();
284
- routeEntries.forEach((e) => entries.add(e));
285
- const manifestEntries = [...Object.entries(serverManifest)];
286
- dynamicImports.forEach((name) => {
287
- const result = manifestEntries.find(([_, value]) => value.file.endsWith(name));
288
- if (result) {
289
- entries.add(result[0]);
290
- }
291
- });
292
- const modules = collectModulesForEntries(manifest, entries);
293
- const assets = /* @__PURE__ */ new Set();
294
- Array.from(modules).forEach((id) => {
295
- const files = ssrManifest[id] || [];
296
- files.forEach((file) => {
297
- assets.add(file);
298
- });
299
- });
300
- return assets;
301
- }
302
- function collectModulesForEntries(manifest, entries) {
303
- const mods = /* @__PURE__ */ new Set();
304
- if (!entries)
305
- return mods;
306
- for (const entry of entries)
307
- collectModules(manifest, entry, mods);
308
- return mods;
309
- }
310
- function collectModules(manifest, entry, mods = /* @__PURE__ */ new Set()) {
311
- if (!entry)
312
- return mods;
313
- mods.add(entry);
314
- manifest[entry]?.dynamicImports?.forEach((item) => {
315
- collectModules(manifest, item, mods);
316
- });
317
- return mods;
318
- }
319
-
320
- async function renderStaticApp(app) {
321
- if (!ReactDomServer__namespace.renderToPipeableStream) {
322
- return ReactDomServer__namespace.renderToString(/* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: app }));
323
- }
324
- const writableStream = new WritableAsPromise();
325
- const { pipe } = ReactDomServer__namespace.renderToPipeableStream(app, {
326
- onError(error) {
327
- writableStream.destroy(error);
328
- },
329
- onAllReady() {
330
- pipe(writableStream);
331
- }
332
- });
333
- return writableStream.getPromise();
334
- }
335
- class WritableAsPromise extends node_stream.Writable {
336
- _output;
337
- _deferred;
338
- constructor() {
339
- super();
340
- this._output = "";
341
- this._deferred = {
342
- promise: null,
343
- resolve: () => null,
344
- reject: () => null
345
- };
346
- this._deferred.promise = new Promise((resolve, reject) => {
347
- this._deferred.resolve = resolve;
348
- this._deferred.reject = reject;
349
- });
350
- }
351
- _write(chunk, _enc, next) {
352
- this._output += chunk.toString();
353
- next();
354
- }
355
- _destroy(error, next) {
356
- if (error instanceof Error)
357
- this._deferred.reject(error);
358
- else
359
- next();
360
- }
361
- end() {
362
- this._deferred.resolve(this._output);
363
- return this.destroy();
364
- }
365
- getPromise() {
366
- return this._deferred.promise;
367
- }
368
- }
369
-
370
- function extractHelmet(context, styleCollector) {
371
- const { helmet } = context;
372
- const htmlAttributes = helmet.htmlAttributes.toString();
373
- const bodyAttributes = helmet.bodyAttributes.toString();
374
- let titleString = helmet.title.toString();
375
- if (titleString.split(">")[1] === "</title") {
376
- titleString = "";
377
- }
378
- const metaStrings = [
379
- titleString,
380
- helmet.meta.toString(),
381
- helmet.link.toString(),
382
- helmet.script.toString()
383
- ];
384
- const styleTag = styleCollector?.toString?.("") ?? "";
385
- const metaAttributes = metaStrings.filter(Boolean);
386
- return { htmlAttributes, bodyAttributes, metaAttributes, styleTag };
387
- }
388
-
389
- function invariant(value, message) {
390
- if (value === false || value === null || typeof value === "undefined") {
391
- console.error(
392
- "The following error is a bug in Vite-react-ssg; please open an issue! https://github.com/Daydreamer-riri/vite-react-ssg/issues/new"
393
- );
394
- throw new Error(message);
395
- }
396
- }
397
-
398
- function fromNodeHeaders(nodeHeaders) {
399
- const headers = new Headers();
400
- for (const [key, values] of Object.entries(nodeHeaders)) {
401
- if (values) {
402
- if (Array.isArray(values)) {
403
- for (const value of values)
404
- headers.append(key, value);
405
- } else {
406
- headers.set(key, values);
407
- }
408
- }
409
- }
410
- return headers;
411
- }
412
- function fromNodeRequest(nodeReq) {
413
- const origin = nodeReq.headers.origin && nodeReq.headers.origin !== "null" ? nodeReq.headers.origin : `http://${nodeReq.headers.host}`;
414
- invariant(
415
- nodeReq.originalUrl,
416
- "Expected `nodeReq.originalUrl` to be defined"
417
- );
418
- const url = new URL(nodeReq.originalUrl, origin);
419
- const init = {
420
- method: nodeReq.method,
421
- headers: fromNodeHeaders(nodeReq.headers)
422
- };
423
- return new Request(url.href, init);
424
- }
425
- async function toNodeRequest(res, nodeRes) {
426
- nodeRes.statusCode = res.status;
427
- nodeRes.statusMessage = res.statusText;
428
- for (const [name, value] of res.headers) {
429
- nodeRes.setHeader(name, value);
430
- }
431
- if (res.body) {
432
- const responseBody = res.body;
433
- const readable = node_stream.Readable.from(responseBody);
434
- readable.pipe(nodeRes);
435
- await node_events.once(readable, "end");
436
- } else {
437
- nodeRes.end();
438
- }
439
- }
440
- function json(data, init) {
441
- if (init === void 0) {
442
- init = {};
443
- }
444
- const responseInit = typeof init === "number" ? {
445
- status: init
446
- } : init;
447
- const headers = new Headers(responseInit.headers);
448
- if (!headers.has("Content-Type")) {
449
- headers.set("Content-Type", "application/json; charset=utf-8");
450
- }
451
- return new Response(JSON.stringify(data), {
452
- ...responseInit,
453
- headers
454
- });
455
- }
456
- function stripDataParam(request) {
457
- const url = new URL(request.url);
458
- url.searchParams.delete("_data");
459
- const init = {
460
- method: request.method,
461
- body: request.body,
462
- headers: request.headers,
463
- signal: request.signal
464
- };
465
- if (init.body) {
466
- init.duplex = "half";
467
- }
468
- return new Request(url.href, init);
469
- }
470
-
471
- class RemixAdapter {
472
- context;
473
- constructor(context) {
474
- this.context = context;
475
- }
476
- async render(path$1) {
477
- const { base, routes, getStyleCollector, routerOptions } = this.context;
478
- const fetchUrl = `${path.withTrailingSlash(base)}${path.removeLeadingSlash(path$1)}`;
479
- const request = createRequest(fetchUrl);
480
- const styleCollector = getStyleCollector ? await getStyleCollector() : null;
481
- const helmetContext = {};
482
- let routerContext = null;
483
- const { StaticRouterProvider, createStaticHandler, createStaticRouter } = await import('react-router-dom/server.js');
484
- const { dataRoutes, query } = createStaticHandler([...routes], { basename: base });
485
- const _context = await query(request);
486
- if (_context instanceof Response)
487
- throw _context;
488
- routerContext = _context;
489
- const router = createStaticRouter(dataRoutes, routerContext, { future: routerOptions.future });
490
- let app = /* @__PURE__ */ jsxRuntime.jsx(reactHelmetAsync.HelmetProvider, { context: helmetContext, children: /* @__PURE__ */ jsxRuntime.jsx(StaticRouterProvider, { router, context: routerContext }) });
491
- if (styleCollector)
492
- app = styleCollector.collect(app);
493
- const appHTML = await renderStaticApp(app);
494
- const { htmlAttributes, bodyAttributes, metaAttributes, styleTag } = extractHelmet(helmetContext, styleCollector);
495
- return { appHTML, htmlAttributes, bodyAttributes, metaAttributes, styleTag, routerContext };
496
- }
497
- handleLoader = async (req, res) => {
498
- const { routes, base } = this.context;
499
- const { matchRoutes } = await import('react-router-dom');
500
- const request = fromNodeRequest(req);
501
- const url = new URL(request.url);
502
- const routeId = decodeURIComponent(url.searchParams.get("_data"));
503
- const matches = matchRoutes(
504
- remixRouter.convertRoutesToDataRoutes([...routes], (route) => route),
505
- {
506
- pathname: url.pathname,
507
- search: url.search,
508
- hash: url.hash,
509
- state: null,
510
- key: "default"
511
- },
512
- base
513
- );
514
- if (!matches) {
515
- res.statusCode = 404;
516
- res.end(`Route not found: ${routeId}`);
517
- return;
518
- }
519
- const match = matches.find((m) => m.route.id === routeId);
520
- if (!match) {
521
- res.statusCode = 404;
522
- res.end(`Route not found: ${routeId}`);
523
- return;
524
- }
525
- const loader = match.route.loader ?? await match.route.lazy?.().then((m) => m.loader);
526
- if (!loader) {
527
- res.statusCode = 200;
528
- res.end(`There is no loader for the route: ${routeId}`);
529
- return;
530
- }
531
- const response = await callRouteLoader({
532
- loader,
533
- params: match.params,
534
- request,
535
- routeId
536
- });
537
- await toNodeRequest(response, res);
538
- };
539
- }
540
- async function callRouteLoader({
541
- // loadContext,
542
- loader,
543
- params,
544
- request,
545
- routeId
546
- }) {
547
- const { json } = await import('react-router-dom');
548
- const result = await loader({
549
- request: stripDataParam(stripIndexParam(request)),
550
- params
551
- });
552
- if (result === void 0) {
553
- throw new Error(
554
- `You defined a loader for route "${routeId}" but didn't return anything from your \`loader\` function. Please return a value or \`null\`.`
555
- );
556
- }
557
- return isResponse(result) ? result : json(result);
558
- }
559
- function isResponse(value) {
560
- return value != null && typeof value.status === "number" && typeof value.statusText === "string" && typeof value.headers === "object" && typeof value.body !== "undefined";
561
- }
562
- function stripIndexParam(request) {
563
- const url = new URL(request.url);
564
- const indexValues = url.searchParams.getAll("index");
565
- url.searchParams.delete("index");
566
- const indexValuesToKeep = [];
567
- for (const indexValue of indexValues) {
568
- if (indexValue) {
569
- indexValuesToKeep.push(indexValue);
570
- }
571
- }
572
- for (const toKeep of indexValuesToKeep) {
573
- url.searchParams.append("index", toKeep);
574
- }
575
- const init = {
576
- method: request.method,
577
- body: request.body,
578
- headers: request.headers,
579
- signal: request.signal
580
- };
581
- if (init.body) {
582
- init.duplex = "half";
583
- }
584
- return new Request(url.href, init);
585
- }
586
-
587
- class SinglePageAdapter {
588
- context;
589
- constructor(context) {
590
- this.context = context;
591
- }
592
- render = async () => {
593
- const { app: inner, getStyleCollector } = this.context;
594
- const helmetContext = {};
595
- const styleCollector = getStyleCollector ? await getStyleCollector() : null;
596
- let app = /* @__PURE__ */ jsxRuntime.jsx(reactHelmetAsync.HelmetProvider, { context: helmetContext, children: inner });
597
- if (styleCollector)
598
- app = styleCollector.collect(app);
599
- const appHTML = await renderStaticApp(app);
600
- const { htmlAttributes, bodyAttributes, metaAttributes, styleTag } = extractHelmet(helmetContext, styleCollector);
601
- return { appHTML, htmlAttributes, bodyAttributes, metaAttributes, styleTag, routerContext: { loaderData: {} } };
602
- };
603
- handleLoader = () => {
604
- };
605
- }
606
-
607
- class TanstackAdapter {
608
- context;
609
- constructor(context) {
610
- this.context = context;
611
- }
612
- render = async (path$1) => {
613
- const { getStyleCollector, router: _router, base } = this.context;
614
- const styleCollector = getStyleCollector ? await getStyleCollector() : null;
615
- path$1 = `${path.withTrailingSlash(base)}${path.removeLeadingSlash(path$1)}`;
616
- const { createRouter, createMemoryHistory } = await import('@tanstack/react-router');
617
- const router = createRouter(_router.options);
618
- const { StartServer } = await import('@tanstack/start/server');
619
- const memoryHistory = createMemoryHistory({
620
- initialEntries: [path$1]
621
- });
622
- router.update({
623
- history: memoryHistory
624
- });
625
- await router.load();
626
- const helmetContext = {};
627
- let app = /* @__PURE__ */ jsxRuntime.jsx(reactHelmetAsync.HelmetProvider, { context: helmetContext, children: /* @__PURE__ */ jsxRuntime.jsx(StartServer, { router }) });
628
- const matchRoutes = router.matchRoutes(router.latestLocation);
629
- const routerContext = {
630
- loaderData: matchRoutes.map((item) => ({ id: item.routeId, loaderData: item.loaderData }))
631
- };
632
- if (styleCollector)
633
- app = styleCollector.collect(app);
634
- const appHTML = await renderStaticApp(app);
635
- const jsdom = new JSDOM.JSDOM(appHTML);
636
- const headElements = jsdom.window.document.querySelector(`#${tanstackRouter.META_CONTAINER_ID}`);
637
- const { htmlAttributes, bodyAttributes, metaAttributes, styleTag } = extractHelmet(helmetContext, styleCollector);
638
- if (headElements?.innerHTML) {
639
- metaAttributes.unshift(headElements.innerHTML);
640
- headElements.innerHTML = "";
641
- }
642
- return {
643
- appHTML: jsdom.window.document.body.innerHTML,
644
- htmlAttributes,
645
- bodyAttributes,
646
- metaAttributes,
647
- styleTag,
648
- routerContext
649
- };
650
- };
651
- handleLoader = async (req, res) => {
652
- const request = fromNodeRequest(req);
653
- const url = new URL(request.url);
654
- const routeId = decodeURIComponent(url.searchParams.get("_data"));
655
- const { router } = this.context;
656
- const matches = router.matchRoutes(url.pathname, Object.fromEntries(url.searchParams.entries()));
657
- const _match = matches.find((m) => m.routeId === routeId);
658
- const matchRoute = router.flatRoutes.find((item) => {
659
- const matchRouteId = _match?.routeId === "__root__" ? "/" : _match?.routeId;
660
- return item.id === matchRouteId;
661
- });
662
- if (!matchRoute) {
663
- res.statusCode = 404;
664
- res.end(`Route not found: ${routeId}`);
665
- return;
666
- }
667
- const getLoaderContext = () => {
668
- const {
669
- params,
670
- loaderDeps,
671
- abortController,
672
- context,
673
- cause
674
- } = _match;
675
- const search = router.options.parseSearch(url.search);
676
- const searchStr = router.options.stringifySearch(search);
677
- return {
678
- preload: false,
679
- navigate: async () => {
680
- },
681
- params,
682
- deps: loaderDeps,
683
- abortController,
684
- context,
685
- location: {
686
- ...url,
687
- search,
688
- searchStr,
689
- state: {}
690
- },
691
- cause,
692
- route: matchRoute
693
- };
694
- };
695
- const loaderData = await matchRoute.options.loader?.(getLoaderContext());
696
- if (!loaderData) {
697
- res.statusCode = 200;
698
- res.end(`There is no loader for the route: ${routeId}`);
699
- return;
700
- }
701
- await toNodeRequest(json(loaderData), res);
702
- };
703
- }
704
-
705
- function getAdapter(context) {
706
- switch (context.routerType) {
707
- case "remix":
708
- return new RemixAdapter(context);
709
- case "tanstack":
710
- return new TanstackAdapter(context);
711
- case "single-page":
712
- return new SinglePageAdapter(context);
713
- }
714
- }
715
-
716
- const dotVitedir = Number.parseInt(vite.version) >= 5 ? [".vite"] : [];
717
- function DefaultIncludedRoutes(paths, _routes) {
718
- return paths.filter((i) => !i.includes(":") && !i.includes("*"));
719
- }
720
- async function build(ssgOptions = {}, viteConfig = {}) {
721
- const mode = process.env.MODE || process.env.NODE_ENV || ssgOptions.mode || "production";
722
- const config = await vite.resolveConfig(viteConfig, "build", mode, mode);
723
- const cwd = process.cwd();
724
- const root = config.root || cwd;
725
- const hash = Math.random().toString(36).substring(2, 12);
726
- const ssgOut = node_path.join(root, ".vite-react-ssg-temp", hash);
727
- const outDir = config.build.outDir || "dist";
728
- const out = node_path.isAbsolute(outDir) ? outDir : node_path.join(root, outDir);
729
- const configBase = config.base;
730
- const mergedOptions = Object.assign({}, config.ssgOptions || {}, ssgOptions);
731
- const {
732
- script = "sync",
733
- mock = false,
734
- entry = await detectEntry(root),
735
- formatting = "none",
736
- includedRoutes: configIncludedRoutes = DefaultIncludedRoutes,
737
- onBeforePageRender,
738
- onPageRendered,
739
- onFinished,
740
- dirStyle = "flat",
741
- includeAllRoutes = false,
742
- format = "esm",
743
- concurrency = 20,
744
- rootContainerId = "root"
745
- } = mergedOptions;
746
- const beastiesOptions = mergedOptions.beastiesOptions ?? mergedOptions.crittersOptions ?? {};
747
- if (fs__default.existsSync(ssgOut))
748
- await fs__default.remove(ssgOut);
749
- const clientLogger = vite.createLogger();
750
- const loggerWarn = clientLogger.warn;
751
- clientLogger.warn = (msg, options) => {
752
- if (msg.includes("vite:resolve") && msg.includes("externalized for browser compatibility"))
753
- return;
754
- loggerWarn(msg, options);
755
- };
756
- buildLog("Build for client...");
757
- await vite.build(vite.mergeConfig(viteConfig, {
758
- build: {
759
- manifest: true,
760
- ssrManifest: true,
761
- rollupOptions: {
762
- input: {
763
- app: node_path.join(root, "./index.html")
764
- },
765
- // @ts-expect-error rollup type
766
- onLog(level, log, handler) {
767
- if (log.message.includes("react-helmet-async"))
768
- return;
769
- handler(level, log);
770
- }
771
- }
772
- },
773
- customLogger: clientLogger,
774
- mode: config.mode
775
- }));
776
- let unmock = () => {
777
- };
778
- if (mock) {
779
- const { jsdomGlobal } = await import('../chunks/jsdomGlobal.cjs');
780
- unmock = jsdomGlobal();
781
- }
782
- buildLog("Build for server...");
783
- process.env.VITE_SSG = "true";
784
- const ssrEntry = await resolveAlias(config, entry);
785
- await vite.build(vite.mergeConfig(viteConfig, {
786
- build: {
787
- ssr: ssrEntry,
788
- manifest: true,
789
- outDir: ssgOut,
790
- minify: false,
791
- cssCodeSplit: false,
792
- rollupOptions: {
793
- output: format === "esm" ? {
794
- entryFileNames: "[name].mjs",
795
- format: "esm"
796
- } : {
797
- entryFileNames: "[name].cjs",
798
- format: "cjs"
799
- },
800
- // @ts-expect-error rollup type
801
- onLog(level, log, handler) {
802
- if (log.message.includes("react-helmet-async"))
803
- return;
804
- handler(level, log);
805
- }
806
- }
807
- },
808
- mode: config.mode
809
- }));
810
- const prefix = format === "esm" && process.platform === "win32" ? "file://" : "";
811
- const ext = format === "esm" ? ".mjs" : ".cjs";
812
- const serverEntry = node_path.join(prefix, ssgOut, node_path.parse(ssrEntry).name + ext);
813
- const serverManifest = JSON.parse(await fs__default.readFile(node_path.join(ssgOut, ...dotVitedir, "manifest.json"), "utf-8"));
814
- const _require = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/vite-react-ssg.Dus0yLsZ.cjs', document.baseURI).href)));
815
- const { createRoot, includedRoutes: serverEntryIncludedRoutes } = format === "esm" ? await import(serverEntry) : _require(serverEntry);
816
- const includedRoutes = serverEntryIncludedRoutes || configIncludedRoutes;
817
- const { routes } = await createRoot(false);
818
- const { paths } = await routesToPaths(routes);
819
- let routesPaths = includeAllRoutes ? paths : await includedRoutes(paths, routes || []);
820
- routesPaths = DefaultIncludedRoutes(routesPaths);
821
- routesPaths = Array.from(new Set(routesPaths));
822
- buildLog("Rendering Pages...", routesPaths.length);
823
- const beasties = beastiesOptions !== false ? await getBeastiesOrCritters(outDir, { publicPath: configBase, ...beastiesOptions }) : void 0;
824
- if (beasties)
825
- console.log(`${kolorist.gray("[vite-react-ssg]")} ${kolorist.blue("Critical CSS generation enabled via `beasties`")}`);
826
- const ssrManifest = JSON.parse(await fs__default.readFile(node_path.join(out, ...dotVitedir, "ssr-manifest.json"), "utf-8"));
827
- const manifest = JSON.parse(await fs__default.readFile(node_path.join(out, ...dotVitedir, "manifest.json"), "utf-8"));
828
- let indexHTML = await fs__default.readFile(node_path.join(out, "index.html"), "utf-8");
829
- indexHTML = rewriteScripts(indexHTML, script);
830
- const queue = new PQueue__default({ concurrency });
831
- const crittersQueue = new PQueue__default({ concurrency: 1 });
832
- const staticLoaderDataManifest = {};
833
- for (const path$1 of routesPaths) {
834
- queue.add(async () => {
835
- try {
836
- const appCtx = await createRoot(false, path$1);
837
- const { base, routes: routes2, triggerOnSSRAppRendered, transformState = state.serializeState, app, routerType } = appCtx;
838
- const transformedIndexHTML = await onBeforePageRender?.(path$1, indexHTML, appCtx) || indexHTML;
839
- const fetchUrl = `${path.withTrailingSlash(base)}${path.removeLeadingSlash(path$1)}`;
840
- const adapter = getAdapter(appCtx);
841
- const assets = !app && routerType === "remix" ? await collectAssets({ routes: [...routes2], locationArg: fetchUrl, base, serverManifest, manifest, ssrManifest }) : /* @__PURE__ */ new Set();
842
- const { appHTML, bodyAttributes, htmlAttributes, metaAttributes, styleTag, routerContext } = await adapter.render(path$1);
843
- staticLoaderDataManifest[path.withLeadingSlash(path$1)] = routerContext?.loaderData;
844
- await triggerOnSSRAppRendered?.(path$1, appHTML, appCtx);
845
- const renderedHTML = await renderHTML({
846
- rootContainerId,
847
- appHTML,
848
- indexHTML: transformedIndexHTML,
849
- metaAttributes,
850
- bodyAttributes,
851
- htmlAttributes,
852
- initialState: null
853
- });
854
- const jsdom = new JSDOM.JSDOM(renderedHTML);
855
- renderPreloadLinks(jsdom.window.document, assets);
856
- const html = jsdom.serialize();
857
- let transformed = await onPageRendered?.(path$1, html, appCtx) || html;
858
- transformed = transformed.replace(SCRIPT_COMMENT_PLACEHOLDER, `window.__VITE_REACT_SSG_HASH__ = '${hash}'`);
859
- if (beasties) {
860
- transformed = await crittersQueue.add(() => beasties.process(transformed));
861
- transformed = transformed.replace(/<link\srel="stylesheet"/g, '<link rel="stylesheet" crossorigin');
862
- }
863
- if (styleTag)
864
- transformed = transformed.replace("<head>", `<head>${styleTag}`);
865
- const formatted = await formatHtml(transformed, formatting);
866
- const relativeRouteFile = `${(path$1.endsWith("/") ? `${path$1}index` : path$1).replace(/^\//g, "")}.html`;
867
- const filename = dirStyle === "nested" ? node_path.join(path$1.replace(/^\//g, ""), "index.html") : relativeRouteFile;
868
- await fs__default.ensureDir(node_path.join(out, node_path.dirname(filename)));
869
- await fs__default.writeFile(node_path.join(out, filename), formatted, "utf-8");
870
- config.logger.info(
871
- `${kolorist.dim(`${outDir}/`)}${kolorist.cyan(filename.padEnd(15, " "))} ${kolorist.dim(getSize(formatted))}`
872
- );
873
- } catch (err) {
874
- throw new Error(`${kolorist.gray("[vite-react-ssg]")} ${kolorist.red(`Error on page: ${kolorist.cyan(path$1)}`)}
875
- ${err.stack}`);
876
- }
877
- });
878
- }
879
- await queue.start().onIdle();
880
- buildLog("Generating static loader data manifest...");
881
- const staticLoaderDataManifestString = JSON.stringify(staticLoaderDataManifest, null, 0);
882
- await fs__default.writeFile(node_path.join(out, `static-loader-data-manifest-${hash}.json`), staticLoaderDataManifestString);
883
- config.logger.info(
884
- `${kolorist.dim(`${outDir}/`)}${kolorist.cyan(`static-loader-data-manifest-${hash}.json`.padEnd(15, " "))} ${kolorist.dim(getSize(staticLoaderDataManifestString))}`
885
- );
886
- await fs__default.remove(node_path.join(root, ".vite-react-ssg-temp"));
887
- unmock();
888
- const pwaPlugin = config.plugins.find((i) => i.name === "vite-plugin-pwa")?.api;
889
- if (pwaPlugin && !pwaPlugin.disabled && pwaPlugin.generateSW) {
890
- buildLog("Regenerate PWA...");
891
- await pwaPlugin.generateSW();
892
- }
893
- console.log(`
894
- ${kolorist.gray("[vite-react-ssg]")} ${kolorist.green("Build finished.")}`);
895
- await onFinished?.();
896
- const waitInSeconds = 15;
897
- const timeout = setTimeout(() => {
898
- console.log(`${kolorist.gray("[vite-react-ssg]")} ${kolorist.yellow(`Build process still running after ${waitInSeconds}s`)}. There might be something misconfigured in your setup. Force exit.`);
899
- process.exit(0);
900
- }, waitInSeconds * 1e3);
901
- timeout.unref();
902
- }
903
- function rewriteScripts(indexHTML, mode) {
904
- if (!mode || mode === "sync")
905
- return indexHTML;
906
- return indexHTML.replace(/<script type="module" /g, `<script type="module" ${mode} `);
907
- }
908
- async function formatHtml(html, formatting) {
909
- if (formatting === "prettify") {
910
- try {
911
- const prettier = (await import('prettier/esm/standalone.mjs')).default;
912
- const parserHTML = (await import('prettier/esm/parser-html.mjs')).default;
913
- return prettier.format(html, { semi: false, parser: "html", plugins: [parserHTML] });
914
- } catch (e) {
915
- console.error(`${kolorist.gray("[vite-react-ssg]")} ${kolorist.red(`Error formatting html: ${e?.message}`)}`);
916
- return html;
917
- }
918
- }
919
- return html;
920
- }
921
-
922
- function ssrServerPlugin({
923
- template,
924
- ssrEntry,
925
- onBeforePageRender,
926
- entry,
927
- rootContainerId,
928
- onPageRendered
929
- }) {
930
- return {
931
- name: "vite-react-ssg:dev-server",
932
- configureServer(server) {
933
- const renderMiddleware = async (req, res, next) => {
934
- try {
935
- const url = req.originalUrl;
936
- const createRoot = await server.ssrLoadModule(ssrEntry).then((m) => m.createRoot);
937
- const appCtx = await createRoot(false, url);
938
- const adapter = getAdapter(appCtx);
939
- const { app, base } = appCtx;
940
- const searchParams = new URLSearchParams(url.split("?")[1]);
941
- if (!app && searchParams.has("_data")) {
942
- return adapter.handleLoader(req, res);
943
- }
944
- const indexHTML = await server.transformIndexHtml(url, template);
945
- const transformedIndexHTML = await onBeforePageRender?.(url, indexHTML, appCtx) || indexHTML;
946
- const { appHTML, bodyAttributes, htmlAttributes, metaAttributes, styleTag } = await adapter.render(path.stripBase(url, base));
947
- metaAttributes.push(styleTag);
948
- const mods = await Promise.all(
949
- [ssrEntry, entry].map(async (entry2) => await server.moduleGraph.getModuleByUrl(entry2))
950
- );
951
- const assetsUrls = /* @__PURE__ */ new Set();
952
- const collectedMods = /* @__PURE__ */ new Set();
953
- const collectAssets = async (mod) => {
954
- if (!mod || !mod?.ssrTransformResult || collectedMods.has(mod))
955
- return;
956
- collectedMods.add(mod);
957
- const { deps = [], dynamicDeps = [] } = mod?.ssrTransformResult;
958
- const allDeps = [...deps, ...dynamicDeps];
959
- for (const dep of allDeps) {
960
- if (dep.endsWith(".css") || dep.endsWith(".scss") || dep.endsWith(".sass") || dep.endsWith(".less")) {
961
- assetsUrls.add(dep);
962
- } else if (dep.endsWith(".ts") || dep.endsWith(".tsx")) {
963
- const depModule = await server.moduleGraph.getModuleByUrl(dep);
964
- depModule && await collectAssets(depModule);
965
- }
966
- }
967
- };
968
- await Promise.all(mods.map(async (mod) => collectAssets(mod)));
969
- const preloadLink = [...assetsUrls].map((item) => createLink$1(path.joinUrlSegments(server.config.base, item)));
970
- metaAttributes.push(...preloadLink);
971
- const renderedHTML = await renderHTML({
972
- rootContainerId,
973
- appHTML,
974
- indexHTML: transformedIndexHTML,
975
- metaAttributes,
976
- bodyAttributes,
977
- htmlAttributes,
978
- initialState: null
979
- });
980
- const transformed = await onPageRendered?.(url, renderedHTML, appCtx) || renderedHTML;
981
- res.statusCode = 200;
982
- res.setHeader("Content-Type", "text/html");
983
- const isDev = "pluginContainer" in server;
984
- const headers = isDev ? server.config.server.headers : server.config.preview.headers;
985
- vite.send(req, res, transformed, "html", { headers });
986
- } catch (e) {
987
- server.ssrFixStacktrace(e);
988
- console.error(`[vite-react-ssg] error: ${e.stack}`);
989
- res.statusCode = 500;
990
- res.end(e.stack);
991
- }
992
- };
993
- return () => {
994
- server.middlewares.use(renderMiddleware);
995
- };
996
- }
997
- };
998
- }
999
-
1000
- async function dev(ssgOptions = {}, viteConfig = {}, customOptions) {
1001
- const mode = process.env.MODE || process.env.NODE_ENV || ssgOptions.mode || "development";
1002
- const config = await vite.resolveConfig(viteConfig, "serve", mode, mode);
1003
- const cwd = process.cwd();
1004
- const root = config.root || cwd;
1005
- const {
1006
- entry = await detectEntry(root),
1007
- onBeforePageRender,
1008
- onPageRendered,
1009
- rootContainerId = "root",
1010
- mock = false
1011
- } = Object.assign({}, config.ssgOptions || {}, ssgOptions);
1012
- const ssrEntry = await resolveAlias(config, entry);
1013
- const template = await fs__default.readFile(node_path.join(root, "index.html"), "utf-8");
1014
- let viteServer;
1015
- globalThis.__ssr_start_time = performance.now();
1016
- createServer().catch((err) => {
1017
- console.error(
1018
- `${kolorist.red(`failed to start server. error:`)}
1019
- ${err.stack}`
1020
- );
1021
- process.exit(1);
1022
- });
1023
- async function createServer() {
1024
- process.env.__DEV_MODE_SSR = "true";
1025
- if (mock) {
1026
- const { jsdomGlobal } = await import('../chunks/jsdomGlobal.cjs');
1027
- jsdomGlobal();
1028
- }
1029
- viteServer = await vite.createServer(
1030
- vite.mergeConfig(
1031
- {
1032
- ...viteConfig,
1033
- plugins: [
1034
- ...viteConfig.plugins ?? [],
1035
- ssrServerPlugin({
1036
- template,
1037
- ssrEntry,
1038
- onBeforePageRender,
1039
- onPageRendered,
1040
- entry,
1041
- rootContainerId
1042
- })
1043
- ]
1044
- },
1045
- {}
1046
- )
1047
- );
1048
- await viteServer.listen();
1049
- printServerInfo(viteServer, !!customOptions);
1050
- viteServer.bindCLIShortcuts({ print: true });
1051
- return viteServer;
1052
- }
1053
- }
1054
- async function printServerInfo(server, onlyUrl = false) {
1055
- if (onlyUrl)
1056
- return server.printUrls();
1057
- const info = server.config.logger.info;
1058
- let ssrReadyMessage = " -- SSR";
1059
- if (globalThis.__ssr_start_time) {
1060
- ssrReadyMessage += ` ready in ${kolorist.reset(kolorist.bold(`${Math.round(
1061
- // @ts-expect-error global var
1062
- performance.now() - globalThis.__ssr_start_time
1063
- )}ms`))}`;
1064
- }
1065
- info(
1066
- `
1067
- ${kolorist.bgLightCyan(` VITE-REACT-SSG v${version} `)}`,
1068
- { clear: !server.config.logger.hasWarned }
1069
- );
1070
- info(
1071
- `${kolorist.cyan(`
1072
- VITE v${vite.version}`) + kolorist.dim(ssrReadyMessage)}
1073
- `
1074
- );
1075
- info(
1076
- kolorist.green(" dev server running at:")
1077
- );
1078
- server.printUrls();
1079
- }
1080
-
1081
- exports.build = build;
1082
- exports.dev = dev;