vite-react-ssg 0.8.8 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,6 +4,13 @@ Static-site generation for React on Vite.
4
4
 
5
5
  See demo(also document): [docs](https://vite-react-ssg.netlify.app/)
6
6
 
7
+ > [!IMPORTANT]
8
+ > **React Router v7 Notice**
9
+ >
10
+ > React Router v7 now has built-in SSG support. If you are using React Router v7, we recommend using its official SSG capabilities for better official support and integration.
11
+ >
12
+ > `vite-react-ssg` will continue to maintain SSG functionality for React Router v6 users.
13
+
7
14
  **🎈 Support for [`@tanstack/router`](https://tanstack.com/router/latest/docs/framework/react/overview)
8
15
  and [`wouter`](https://github.com/molefrog/wouter) is in progress!**
9
16
 
@@ -229,6 +236,10 @@ export const Component = Docs
229
236
  export const entry = 'src/pages/json.tsx'
230
237
 
231
238
  export async function loader() {
239
+ // This code will avoid `shiki` and `node:fs` being mark as 'modulepreload' and sent to the client.
240
+ if (!import.meta.ssr) {
241
+ return null
242
+ }
232
243
  // The code here will not be executed on the client side, and the modules imported will not be sent to the client.
233
244
  const fs = (await import('node:fs'))
234
245
  const cwd = process.cwd()
@@ -585,7 +596,14 @@ interface ViteReactSSGOptions {
585
596
  */
586
597
  onPageRendered?: (route: string, renderedHTML: string, appCtx: ViteReactSSGContext<true>) => Promise<string | null | undefined> | string | null | undefined
587
598
 
588
- onFinished?: () => Promise<void> | void
599
+ /**
600
+ * A function that is run after generation is complete.
601
+ * It receives the build output directory as a string.
602
+ *
603
+ * You can use this to add, edit, or delete files in the output
604
+ directory that you don't want to manage in React.
605
+ */
606
+ onFinished?: (dir: string) => Promise<void> | void
589
607
  /**
590
608
  * The application's root container `id`.
591
609
  *
@@ -654,7 +672,7 @@ export default defineConfig({
654
672
 
655
673
  ## Roadmap
656
674
 
657
- - [ ] Support `react19`
675
+ - [x] Support `react19`
658
676
  - [ ] no index.html mode
659
677
 
660
678
  ## Credits
@@ -1,6 +1,6 @@
1
1
  import { ReactNode } from 'react';
2
- import { V as ViteReactSSGContext, a as ViteReactSSGClientOptions } from '../shared/vite-react-ssg.B2xAADcy.mjs';
3
- export { C as CrittersOptions, I as IndexRouteRecord, N as NonIndexRouteRecord, R as RouteRecord, c as RouterFutureConfig, d as RouterOptions, S as StyleCollector, b as ViteReactSSGOptions } from '../shared/vite-react-ssg.B2xAADcy.mjs';
2
+ import { V as ViteReactSSGContext, a as ViteReactSSGClientOptions } from '../shared/vite-react-ssg.CHKvDn8n.mjs';
3
+ export { C as CrittersOptions, I as IndexRouteRecord, N as NonIndexRouteRecord, R as RouteRecord, b as RouterFutureConfig, c as RouterOptions, S as StyleCollector, d as ViteReactSSGOptions } from '../shared/vite-react-ssg.CHKvDn8n.mjs';
4
4
  export { C as ClientOnly, H as Head } from '../shared/vite-react-ssg.-NlgsPvg.mjs';
5
5
  import 'beasties';
6
6
  import 'react-router-dom';
@@ -1,6 +1,6 @@
1
1
  import { ReactNode } from 'react';
2
- import { V as ViteReactSSGContext, a as ViteReactSSGClientOptions } from '../shared/vite-react-ssg.B2xAADcy.js';
3
- export { C as CrittersOptions, I as IndexRouteRecord, N as NonIndexRouteRecord, R as RouteRecord, c as RouterFutureConfig, d as RouterOptions, S as StyleCollector, b as ViteReactSSGOptions } from '../shared/vite-react-ssg.B2xAADcy.js';
2
+ import { V as ViteReactSSGContext, a as ViteReactSSGClientOptions } from '../shared/vite-react-ssg.CHKvDn8n.js';
3
+ export { C as CrittersOptions, I as IndexRouteRecord, N as NonIndexRouteRecord, R as RouteRecord, b as RouterFutureConfig, c as RouterOptions, S as StyleCollector, d as ViteReactSSGOptions } from '../shared/vite-react-ssg.CHKvDn8n.js';
4
4
  export { C as ClientOnly, H as Head } from '../shared/vite-react-ssg.-NlgsPvg.js';
5
5
  import 'beasties';
6
6
  import 'react-router-dom';
@@ -1,8 +1,8 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
2
  import { HelmetProvider } from 'react-helmet-async';
3
- import { r as render, h as hydrate, d as documentReady } from '../shared/vite-react-ssg.BxjO14Et.mjs';
4
- export { C as ClientOnly, H as Head } from '../shared/vite-react-ssg.BxjO14Et.mjs';
3
+ import { r as render, h as hydrate, d as documentReady } from '../shared/vite-react-ssg.DTTf7HZy.mjs';
5
4
  import { d as deserializeState } from '../shared/vite-react-ssg.C6pK7rvr.mjs';
5
+ export { C as ClientOnly, H as Head } from '../shared/vite-react-ssg.CoMLbIiW.mjs';
6
6
  import 'react';
7
7
  import 'react-dom';
8
8
 
package/dist/index.d.mts CHANGED
@@ -1,24 +1,40 @@
1
- import { V as ViteReactSSGContext, d as RouterOptions, a as ViteReactSSGClientOptions } from './shared/vite-react-ssg.B2xAADcy.mjs';
2
- export { C as CrittersOptions, I as IndexRouteRecord, N as NonIndexRouteRecord, R as RouteRecord, c as RouterFutureConfig, S as StyleCollector, b as ViteReactSSGOptions } from './shared/vite-react-ssg.B2xAADcy.mjs';
1
+ import { V as ViteReactSSGContext, c as RouterOptions, a as ViteReactSSGClientOptions } from './shared/vite-react-ssg.CHKvDn8n.mjs';
2
+ export { C as CrittersOptions, I as IndexRouteRecord, N as NonIndexRouteRecord, R as RouteRecord, b as RouterFutureConfig, S as StyleCollector, d as ViteReactSSGOptions } from './shared/vite-react-ssg.CHKvDn8n.mjs';
3
3
  export { C as ClientOnly, H as Head } from './shared/vite-react-ssg.-NlgsPvg.mjs';
4
- import { LinkProps, NavLinkProps } from 'react-router-dom';
5
- import React from 'react';
4
+ import * as react_jsx_runtime from 'react/jsx-runtime';
6
5
  import 'beasties';
6
+ import 'react';
7
+ import 'react-router-dom';
7
8
  import 'react-helmet-async';
8
9
 
9
10
  /**
10
11
  * @deprecated Please use `Link` from 'react-router-dom' instead.
11
12
  */
12
- declare const Link: React.ForwardRefExoticComponent<LinkProps & React.RefAttributes<HTMLAnchorElement>>;
13
+ declare function Link({ ref, ...props }: {
14
+ [x: string]: any;
15
+ ref: any;
16
+ }): react_jsx_runtime.JSX.Element;
17
+ declare namespace Link {
18
+ var displayName: string;
19
+ }
13
20
  /**
14
21
  * @deprecated Please use `NavLink` from 'react-router-dom' instead.
15
22
  */
16
- declare const NavLink: React.ForwardRefExoticComponent<NavLinkProps & React.RefAttributes<HTMLAnchorElement>>;
23
+ declare function NavLink({ ref, ...props }: {
24
+ [x: string]: any;
25
+ ref: any;
26
+ }): react_jsx_runtime.JSX.Element;
27
+ declare namespace NavLink {
28
+ var displayName: string;
29
+ }
17
30
 
18
31
  declare function ViteReactSSG(routerOptions: RouterOptions, fn?: (context: ViteReactSSGContext<true>) => Promise<void> | void, options?: ViteReactSSGClientOptions): (client?: boolean, routePath?: string) => Promise<ViteReactSSGContext<true>>;
19
32
  declare global {
20
33
  interface Window {
21
- __VITE_REACT_SSG_STATIC_LOADER_DATA__: any;
34
+ /** Manifest index: route path -> data file path */
35
+ __VITE_REACT_SSG_STATIC_LOADER_MANIFEST__: Record<string, string>;
36
+ /** Cached loader data: route path -> loader data */
37
+ __VITE_REACT_SSG_STATIC_LOADER_DATA__: Record<string, Record<string, unknown>>;
22
38
  __VITE_REACT_SSG_HASH__: string;
23
39
  __VITE_REACT_SSG_CONTEXT__: ViteReactSSGContext<true>;
24
40
  }
package/dist/index.d.ts CHANGED
@@ -1,24 +1,40 @@
1
- import { V as ViteReactSSGContext, d as RouterOptions, a as ViteReactSSGClientOptions } from './shared/vite-react-ssg.B2xAADcy.js';
2
- export { C as CrittersOptions, I as IndexRouteRecord, N as NonIndexRouteRecord, R as RouteRecord, c as RouterFutureConfig, S as StyleCollector, b as ViteReactSSGOptions } from './shared/vite-react-ssg.B2xAADcy.js';
1
+ import { V as ViteReactSSGContext, c as RouterOptions, a as ViteReactSSGClientOptions } from './shared/vite-react-ssg.CHKvDn8n.js';
2
+ export { C as CrittersOptions, I as IndexRouteRecord, N as NonIndexRouteRecord, R as RouteRecord, b as RouterFutureConfig, S as StyleCollector, d as ViteReactSSGOptions } from './shared/vite-react-ssg.CHKvDn8n.js';
3
3
  export { C as ClientOnly, H as Head } from './shared/vite-react-ssg.-NlgsPvg.js';
4
- import { LinkProps, NavLinkProps } from 'react-router-dom';
5
- import React from 'react';
4
+ import * as react_jsx_runtime from 'react/jsx-runtime';
6
5
  import 'beasties';
6
+ import 'react';
7
+ import 'react-router-dom';
7
8
  import 'react-helmet-async';
8
9
 
9
10
  /**
10
11
  * @deprecated Please use `Link` from 'react-router-dom' instead.
11
12
  */
12
- declare const Link: React.ForwardRefExoticComponent<LinkProps & React.RefAttributes<HTMLAnchorElement>>;
13
+ declare function Link({ ref, ...props }: {
14
+ [x: string]: any;
15
+ ref: any;
16
+ }): react_jsx_runtime.JSX.Element;
17
+ declare namespace Link {
18
+ var displayName: string;
19
+ }
13
20
  /**
14
21
  * @deprecated Please use `NavLink` from 'react-router-dom' instead.
15
22
  */
16
- declare const NavLink: React.ForwardRefExoticComponent<NavLinkProps & React.RefAttributes<HTMLAnchorElement>>;
23
+ declare function NavLink({ ref, ...props }: {
24
+ [x: string]: any;
25
+ ref: any;
26
+ }): react_jsx_runtime.JSX.Element;
27
+ declare namespace NavLink {
28
+ var displayName: string;
29
+ }
17
30
 
18
31
  declare function ViteReactSSG(routerOptions: RouterOptions, fn?: (context: ViteReactSSGContext<true>) => Promise<void> | void, options?: ViteReactSSGClientOptions): (client?: boolean, routePath?: string) => Promise<ViteReactSSGContext<true>>;
19
32
  declare global {
20
33
  interface Window {
21
- __VITE_REACT_SSG_STATIC_LOADER_DATA__: any;
34
+ /** Manifest index: route path -> data file path */
35
+ __VITE_REACT_SSG_STATIC_LOADER_MANIFEST__: Record<string, string>;
36
+ /** Cached loader data: route path -> loader data */
37
+ __VITE_REACT_SSG_STATIC_LOADER_DATA__: Record<string, Record<string, unknown>>;
22
38
  __VITE_REACT_SSG_HASH__: string;
23
39
  __VITE_REACT_SSG_CONTEXT__: ViteReactSSGContext<true>;
24
40
  }
package/dist/index.mjs CHANGED
@@ -1,15 +1,14 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
2
  import { HelmetProvider } from 'react-helmet-async';
3
3
  import { useLinkClickHandler, Link as Link$1, NavLink as NavLink$1, matchRoutes, createBrowserRouter, RouterProvider } from 'react-router-dom';
4
- import { r as render, h as hydrate, d as documentReady } from './shared/vite-react-ssg.BxjO14Et.mjs';
5
- export { C as ClientOnly, H as Head } from './shared/vite-react-ssg.BxjO14Et.mjs';
6
- import { j as joinUrlSegments, w as withLeadingSlash, s as stripBase } from './shared/vite-react-ssg.CjIppNIS.mjs';
7
- import { c as convertRoutesToDataRoutes } from './shared/vite-react-ssg.C0y5wbxl.mjs';
4
+ import { r as render, h as hydrate, d as documentReady } from './shared/vite-react-ssg.DTTf7HZy.mjs';
5
+ import { c as convertRoutesToDataRoutes, j as joinUrlSegments, w as withLeadingSlash, s as stripBase } from './shared/vite-react-ssg.BhGKpaqQ.mjs';
8
6
  import { d as deserializeState } from './shared/vite-react-ssg.C6pK7rvr.mjs';
9
- import React, { forwardRef } from 'react';
7
+ export { C as ClientOnly, H as Head } from './shared/vite-react-ssg.CoMLbIiW.mjs';
8
+ import React from 'react';
10
9
  import 'react-dom';
11
10
 
12
- const Link = forwardRef((props, ref) => {
11
+ function Link({ ref, ...props }) {
13
12
  const {
14
13
  replace,
15
14
  state,
@@ -38,9 +37,9 @@ const Link = forwardRef((props, ref) => {
38
37
  event.preventDefault();
39
38
  }
40
39
  return /* @__PURE__ */ jsx(Link$1, { ...props, ref, onClick: handleClick });
41
- });
40
+ }
42
41
  Link.displayName = "Link";
43
- const NavLink = forwardRef((props, ref) => {
42
+ function NavLink({ ref, ...props }) {
44
43
  const {
45
44
  replace,
46
45
  state,
@@ -69,7 +68,7 @@ const NavLink = forwardRef((props, ref) => {
69
68
  event.preventDefault();
70
69
  }
71
70
  return /* @__PURE__ */ jsx(NavLink$1, { ...props, ref, onClick: handleClick });
72
- });
71
+ }
73
72
  NavLink.displayName = "NavLink";
74
73
 
75
74
  function ViteReactSSG(routerOptions, fn, options = {}) {
@@ -79,14 +78,20 @@ function ViteReactSSG(routerOptions, fn, options = {}) {
79
78
  ssrWhenDev,
80
79
  getStyleCollector = null
81
80
  } = options;
82
- if (process.env.NODE_ENV === "development" && ssrWhenDev !== void 0)
83
- console.warn("[vite-react-ssg] `ssrWhenDev` option is no longer needed. If you want to use csr, just replace `vite-react-ssg dev` with `vite`.");
81
+ if (process.env.NODE_ENV === "development" && ssrWhenDev !== void 0) {
82
+ console.warn(
83
+ "[vite-react-ssg] `ssrWhenDev` option is no longer needed. If you want to use csr, just replace `vite-react-ssg dev` with `vite`."
84
+ );
85
+ }
84
86
  const isClient = typeof window !== "undefined";
85
87
  const BASE_URL = routerOptions.basename ?? "/";
86
88
  const { v7_startTransition = true, ...routerFeature } = routerOptions.future ?? {};
87
89
  async function createRoot(client = false, routePath) {
88
90
  const browserRouter = client ? createBrowserRouter(
89
- convertRoutesToDataRoutes(routerOptions.routes, transformStaticLoaderRoute),
91
+ convertRoutesToDataRoutes(
92
+ routerOptions.routes,
93
+ transformStaticLoaderRoute
94
+ ),
90
95
  { basename: BASE_URL, future: routerFeature }
91
96
  ) : void 0;
92
97
  const appRenderCallbacks = [];
@@ -128,9 +133,11 @@ function ViteReactSSG(routerOptions, fn, options = {}) {
128
133
  console.warn("[vite-react-ssg] Root container not found.");
129
134
  return;
130
135
  }
131
- const lazeMatches = matchRoutes(routerOptions.routes, window.location, BASE_URL)?.filter(
132
- (m) => m.route.lazy
133
- );
136
+ const lazeMatches = matchRoutes(
137
+ routerOptions.routes,
138
+ window.location,
139
+ BASE_URL
140
+ )?.filter((m) => m.route.lazy);
134
141
  if (lazeMatches && lazeMatches?.length > 0) {
135
142
  await Promise.all(
136
143
  lazeMatches.map(async (m) => {
@@ -164,20 +171,31 @@ function ViteReactSSG(routerOptions, fn, options = {}) {
164
171
  const url = request.url.includes("?") ? `${request.url}&${dataQuery}` : `${request.url}?${dataQuery}`;
165
172
  return fetch(url);
166
173
  } else {
167
- let staticLoadData;
168
- if (window.__VITE_REACT_SSG_STATIC_LOADER_DATA__) {
169
- staticLoadData = window.__VITE_REACT_SSG_STATIC_LOADER_DATA__;
170
- } else {
171
- const manifestUrl = joinUrlSegments(BASE_URL, `static-loader-data-manifest-${window.__VITE_REACT_SSG_HASH__}.json`);
172
- staticLoadData = await (await fetch(withLeadingSlash(manifestUrl))).json();
173
- window.__VITE_REACT_SSG_STATIC_LOADER_DATA__ = staticLoadData;
174
+ if (!window.__VITE_REACT_SSG_STATIC_LOADER_MANIFEST__) {
175
+ const manifestUrl = joinUrlSegments(
176
+ BASE_URL,
177
+ `static-loader-data-manifest-${window.__VITE_REACT_SSG_HASH__}.json`
178
+ );
179
+ window.__VITE_REACT_SSG_STATIC_LOADER_MANIFEST__ = await (await fetch(withLeadingSlash(manifestUrl))).json();
174
180
  }
175
181
  const { url } = request;
176
182
  let { pathname } = new URL(url);
177
183
  if (BASE_URL !== "/") {
178
184
  pathname = stripBase(pathname, BASE_URL);
179
185
  }
180
- const routeData = staticLoadData?.[pathname]?.[route.id];
186
+ const manifest = window.__VITE_REACT_SSG_STATIC_LOADER_MANIFEST__;
187
+ const dataFilePath = manifest?.[pathname];
188
+ if (!dataFilePath) {
189
+ return null;
190
+ }
191
+ if (!window.__VITE_REACT_SSG_STATIC_LOADER_DATA__) {
192
+ window.__VITE_REACT_SSG_STATIC_LOADER_DATA__ = {};
193
+ }
194
+ if (!window.__VITE_REACT_SSG_STATIC_LOADER_DATA__[pathname]) {
195
+ const dataUrl = joinUrlSegments(BASE_URL, dataFilePath);
196
+ window.__VITE_REACT_SSG_STATIC_LOADER_DATA__[pathname] = await (await fetch(withLeadingSlash(dataUrl))).json();
197
+ }
198
+ const routeData = window.__VITE_REACT_SSG_STATIC_LOADER_DATA__[pathname]?.[route.id];
181
199
  return routeData ?? null;
182
200
  }
183
201
  };
@@ -1,2 +1,2 @@
1
1
 
2
- export { }
2
+ export { };
@@ -1,2 +1,2 @@
1
1
 
2
- export { }
2
+ export { };
package/dist/node/cli.mjs CHANGED
@@ -1,33 +1,22 @@
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, d as dev } from '../shared/vite-react-ssg.BFwZy9nw.mjs';
5
- import { Headers, Request, Response, fetch, FormData } from '@remix-run/web-fetch';
4
+ import { b as build, d as dev } from '../shared/vite-react-ssg.DsKK_1op.mjs';
6
5
  import 'node:module';
7
6
  import 'node:path';
8
7
  import 'fs-extra';
9
8
  import 'jsdom';
10
9
  import 'p-queue';
11
10
  import 'vite';
12
- import '../shared/vite-react-ssg.CjIppNIS.mjs';
11
+ import '../shared/vite-react-ssg.BhGKpaqQ.mjs';
13
12
  import '../shared/vite-react-ssg.C6pK7rvr.mjs';
14
13
  import 'react/jsx-runtime';
15
14
  import 'react-helmet-async';
16
15
  import 'node:events';
17
16
  import 'node:stream';
18
- import '../shared/vite-react-ssg.C0y5wbxl.mjs';
19
17
  import 'react-dom/server';
20
- import '../shared/vite-react-ssg.B-j07kW6.mjs';
18
+ import '../shared/vite-react-ssg.BqDzTpJh.mjs';
21
19
 
22
- function installGlobals() {
23
- global.Headers = Headers;
24
- global.Request = Request;
25
- global.Response = Response;
26
- global.fetch = fetch;
27
- global.FormData = FormData;
28
- }
29
-
30
- installGlobals();
31
20
  yargs(hideBin(process.argv)).scriptName("vite-react-ssg").usage("$0 [args]").command(
32
21
  "build",
33
22
  "Build SSG",
package/dist/node.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { InlineConfig } from 'vite';
2
- import { b as ViteReactSSGOptions } from './shared/vite-react-ssg.B2xAADcy.mjs';
2
+ import { d as ViteReactSSGOptions } from './shared/vite-react-ssg.CHKvDn8n.mjs';
3
3
  import 'beasties';
4
4
  import 'react';
5
5
  import 'react-router-dom';
package/dist/node.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { InlineConfig } from 'vite';
2
- import { b as ViteReactSSGOptions } from './shared/vite-react-ssg.B2xAADcy.js';
2
+ import { d as ViteReactSSGOptions } from './shared/vite-react-ssg.CHKvDn8n.js';
3
3
  import 'beasties';
4
4
  import 'react';
5
5
  import 'react-router-dom';
package/dist/node.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export { b as build, d as dev } from './shared/vite-react-ssg.BFwZy9nw.mjs';
1
+ export { b as build, d as dev } from './shared/vite-react-ssg.DsKK_1op.mjs';
2
2
  import 'node:module';
3
3
  import 'node:path';
4
4
  import 'fs-extra';
@@ -6,12 +6,11 @@ import 'jsdom';
6
6
  import 'kolorist';
7
7
  import 'p-queue';
8
8
  import 'vite';
9
- import './shared/vite-react-ssg.CjIppNIS.mjs';
9
+ import './shared/vite-react-ssg.BhGKpaqQ.mjs';
10
10
  import './shared/vite-react-ssg.C6pK7rvr.mjs';
11
11
  import 'react/jsx-runtime';
12
12
  import 'react-helmet-async';
13
13
  import 'node:events';
14
14
  import 'node:stream';
15
- import './shared/vite-react-ssg.C0y5wbxl.mjs';
16
15
  import 'react-dom/server';
17
- import './shared/vite-react-ssg.B-j07kW6.mjs';
16
+ import './shared/vite-react-ssg.BqDzTpJh.mjs';
@@ -1,3 +1,32 @@
1
+ function joinUrlSegments(a, b) {
2
+ if (!a || !b)
3
+ return a || b || "";
4
+ if (a[a.length - 1] === "/")
5
+ a = a.substring(0, a.length - 1);
6
+ if (b[0] !== "/")
7
+ b = `/${b}`;
8
+ return a + b;
9
+ }
10
+ function removeLeadingSlash(str) {
11
+ return str[0] === "/" ? str.slice(1) : str;
12
+ }
13
+ function stripBase(path, base) {
14
+ if (path === base)
15
+ return "/";
16
+ const devBase = withTrailingSlash(base);
17
+ return path.startsWith(devBase) ? path.slice(devBase.length - 1) : path;
18
+ }
19
+ function withTrailingSlash(path) {
20
+ if (path[path.length - 1] !== "/")
21
+ return `${path}/`;
22
+ return path;
23
+ }
24
+ function withLeadingSlash(path) {
25
+ if (path[0] !== "/")
26
+ return `/${path}`;
27
+ return path;
28
+ }
29
+
1
30
  function convertRoutesToDataRoutes(routes, mapRouteProperties, parentPath = []) {
2
31
  return routes.map((route, index) => {
3
32
  const treePath = [...parentPath, String(index)];
@@ -33,4 +62,4 @@ function isIndexRoute(route) {
33
62
  return route.index === true;
34
63
  }
35
64
 
36
- export { convertRoutesToDataRoutes as c };
65
+ export { withTrailingSlash as a, convertRoutesToDataRoutes as c, joinUrlSegments as j, removeLeadingSlash as r, stripBase as s, withLeadingSlash as w };
@@ -0,0 +1,5 @@
1
+ function registerPaths(id, getStaticPaths) {
2
+ }
3
+ const META_CONTAINER_ID = "__SSG_TANSTACK_META_CONTAINER__";
4
+
5
+ export { META_CONTAINER_ID as M, registerPaths as r };
@@ -121,7 +121,7 @@ interface ViteReactSSGOptions<Context = ViteReactSSGContext> {
121
121
  * The returned value will be used as the HTML of the route.
122
122
  */
123
123
  onPageRendered?: (route: string, renderedHTML: string, appCtx: Context) => Promise<string | null | undefined> | string | null | undefined;
124
- onFinished?: () => Promise<void> | void;
124
+ onFinished?: (dir: string) => Promise<void> | void;
125
125
  /**
126
126
  * The application's root container `id`.
127
127
  *
@@ -216,4 +216,4 @@ declare module 'vite' {
216
216
  }
217
217
  }
218
218
 
219
- export type { CrittersOptions as C, IndexRouteRecord as I, NonIndexRouteRecord as N, RouteRecord as R, StyleCollector as S, ViteReactSSGContext as V, ViteReactSSGClientOptions as a, ViteReactSSGOptions as b, RouterFutureConfig as c, RouterOptions as d };
219
+ export type { CrittersOptions as C, IndexRouteRecord as I, NonIndexRouteRecord as N, RouteRecord as R, StyleCollector as S, ViteReactSSGContext as V, ViteReactSSGClientOptions as a, RouterFutureConfig as b, RouterOptions as c, ViteReactSSGOptions as d };
@@ -121,7 +121,7 @@ interface ViteReactSSGOptions<Context = ViteReactSSGContext> {
121
121
  * The returned value will be used as the HTML of the route.
122
122
  */
123
123
  onPageRendered?: (route: string, renderedHTML: string, appCtx: Context) => Promise<string | null | undefined> | string | null | undefined;
124
- onFinished?: () => Promise<void> | void;
124
+ onFinished?: (dir: string) => Promise<void> | void;
125
125
  /**
126
126
  * The application's root container `id`.
127
127
  *
@@ -216,4 +216,4 @@ declare module 'vite' {
216
216
  }
217
217
  }
218
218
 
219
- export type { CrittersOptions as C, IndexRouteRecord as I, NonIndexRouteRecord as N, RouteRecord as R, StyleCollector as S, ViteReactSSGContext as V, ViteReactSSGClientOptions as a, ViteReactSSGOptions as b, RouterFutureConfig as c, RouterOptions as d };
219
+ export type { CrittersOptions as C, IndexRouteRecord as I, NonIndexRouteRecord as N, RouteRecord as R, StyleCollector as S, ViteReactSSGContext as V, ViteReactSSGClientOptions as a, RouterFutureConfig as b, RouterOptions as c, ViteReactSSGOptions as d };
@@ -0,0 +1,34 @@
1
+ import { jsx, Fragment } from 'react/jsx-runtime';
2
+ import { useState, useEffect, isValidElement } from 'react';
3
+ import { Helmet } from 'react-helmet-async';
4
+
5
+ function useIsClient() {
6
+ const [isBrowser, setIsBrowser] = useState(false);
7
+ useEffect(() => {
8
+ setIsBrowser(true);
9
+ }, []);
10
+ return isBrowser;
11
+ }
12
+
13
+ function ClientOnly({
14
+ children,
15
+ fallback
16
+ }) {
17
+ const isBrowser = useIsClient();
18
+ if (isBrowser) {
19
+ if (typeof children !== "function" && process.env.NODE_ENV === "development") {
20
+ throw new Error(
21
+ `vite-react-ssg error: The children of <ClientOnly> must be a "render function", e.g. <ClientOnly>{() => <span>{window.location.href}</span>}</ClientOnly>.
22
+ Current type: ${isValidElement(children) ? "React element" : typeof children}`
23
+ );
24
+ }
25
+ return /* @__PURE__ */ jsx(Fragment, { children: children?.() });
26
+ }
27
+ return fallback ?? null;
28
+ }
29
+
30
+ function Head(props) {
31
+ return /* @__PURE__ */ jsx(Helmet, { ...props });
32
+ }
33
+
34
+ export { ClientOnly as C, Head as H };
@@ -1,7 +1,5 @@
1
- import React, { useState, useEffect, isValidElement } from 'react';
1
+ import React from 'react';
2
2
  import * as ReactDOM from 'react-dom';
3
- import { jsx, Fragment } from 'react/jsx-runtime';
4
- import { Helmet } from 'react-helmet-async';
5
3
 
6
4
  const CopyReactDOM = {
7
5
  ...ReactDOM
@@ -65,33 +63,4 @@ function documentReady(_passThrough) {
65
63
  return Promise.resolve(_passThrough);
66
64
  }
67
65
 
68
- function useIsClient() {
69
- const [isBrowser, setIsBrowser] = useState(false);
70
- useEffect(() => {
71
- setIsBrowser(true);
72
- }, []);
73
- return isBrowser;
74
- }
75
-
76
- function ClientOnly({
77
- children,
78
- fallback
79
- }) {
80
- const isBrowser = useIsClient();
81
- if (isBrowser) {
82
- if (typeof children !== "function" && process.env.NODE_ENV === "development") {
83
- throw new Error(
84
- `vite-react-ssg error: The children of <ClientOnly> must be a "render function", e.g. <ClientOnly>{() => <span>{window.location.href}</span>}</ClientOnly>.
85
- Current type: ${isValidElement(children) ? "React element" : typeof children}`
86
- );
87
- }
88
- return /* @__PURE__ */ jsx(Fragment, { children: children?.() });
89
- }
90
- return fallback ?? null;
91
- }
92
-
93
- function Head(props) {
94
- return /* @__PURE__ */ jsx(Helmet, { ...props });
95
- }
96
-
97
- export { ClientOnly as C, Head as H, documentReady as d, hydrate as h, render as r };
66
+ export { documentReady as d, hydrate as h, render as r };
@@ -1,19 +1,18 @@
1
1
  import { createRequire } from 'node:module';
2
- import { join, isAbsolute, parse, dirname } from 'node:path';
2
+ import { join, parse, isAbsolute, dirname } from 'node:path';
3
3
  import fs from 'fs-extra';
4
4
  import { JSDOM } from 'jsdom';
5
5
  import { gray, yellow, blue, dim, cyan, red, green, reset, bold, bgLightCyan } from 'kolorist';
6
6
  import PQueue from 'p-queue';
7
7
  import { resolveConfig, createLogger, build as build$1, mergeConfig, version as version$1, send, createServer } from 'vite';
8
- import { a as withTrailingSlash, r as removeLeadingSlash, w as withLeadingSlash, s as stripBase, j as joinUrlSegments } from './vite-react-ssg.CjIppNIS.mjs';
8
+ import { a as withTrailingSlash, r as removeLeadingSlash, c as convertRoutesToDataRoutes, w as withLeadingSlash, s as stripBase, j as joinUrlSegments } from './vite-react-ssg.BhGKpaqQ.mjs';
9
9
  import { s as serializeState } from './vite-react-ssg.C6pK7rvr.mjs';
10
10
  import { jsx, Fragment } from 'react/jsx-runtime';
11
11
  import { HelmetProvider } from 'react-helmet-async';
12
12
  import { once } from 'node:events';
13
13
  import { Readable, Writable } from 'node:stream';
14
- import { c as convertRoutesToDataRoutes } from './vite-react-ssg.C0y5wbxl.mjs';
15
14
  import * as ReactDomServer from 'react-dom/server';
16
- import { M as META_CONTAINER_ID } from './vite-react-ssg.B-j07kW6.mjs';
15
+ import { M as META_CONTAINER_ID } from './vite-react-ssg.BqDzTpJh.mjs';
17
16
 
18
17
  const DYNAMIC_IMPORT_REGEX = /import\("([^)]+)"\)/g;
19
18
  async function collectAssets({
@@ -356,7 +355,7 @@ class WritableAsPromise extends Writable {
356
355
  }
357
356
  }
358
357
 
359
- const version = "0.8.8";
358
+ const version = "0.9.0";
360
359
 
361
360
  function buildLog(text, count) {
362
361
  console.log(`
@@ -694,6 +693,10 @@ function getAdapter(context) {
694
693
  }
695
694
 
696
695
  const dotVitedir = Number.parseInt(version$1) >= 5 ? [".vite"] : [];
696
+ function getLoaderDataFilePath(routePath, hash) {
697
+ const normalized = routePath === "/" ? "/index" : routePath.endsWith("/") ? `${routePath}index` : routePath;
698
+ return `static-loader-data${withLeadingSlash(normalized)}.${hash}.json`;
699
+ }
697
700
  function DefaultIncludedRoutes(paths, _routes) {
698
701
  return paths.filter((i) => !i.includes(":") && !i.includes("*"));
699
702
  }
@@ -704,8 +707,7 @@ async function build(ssgOptions = {}, viteConfig = {}) {
704
707
  const root = config.root || cwd;
705
708
  const hash = Math.random().toString(36).substring(2, 12);
706
709
  const ssgOut = join(root, ".vite-react-ssg-temp", hash);
707
- const outDir = config.build.outDir || "dist";
708
- const out = isAbsolute(outDir) ? outDir : join(root, outDir);
710
+ let outDir = config.build.outDir || "dist";
709
711
  const configBase = config.base;
710
712
  const mergedOptions = Object.assign({}, config.ssgOptions || {}, ssgOptions);
711
713
  const {
@@ -730,30 +732,41 @@ async function build(ssgOptions = {}, viteConfig = {}) {
730
732
  const clientLogger = createLogger();
731
733
  const loggerWarn = clientLogger.warn;
732
734
  clientLogger.warn = (msg, options) => {
733
- if (msg.includes("vite:resolve") && msg.includes("externalized for browser compatibility"))
735
+ if (msg.includes("vite:resolve") && msg.includes("externalized for browser compatibility")) {
734
736
  return;
737
+ }
735
738
  loggerWarn(msg, options);
736
739
  };
737
740
  buildLog("Build for client...");
738
- await build$1(mergeConfig(viteConfig, {
739
- build: {
740
- manifest: true,
741
- ssrManifest: true,
742
- rollupOptions: {
743
- input: {
744
- app: join(root, htmlEntry || "./index.html")
745
- },
746
- // @ts-expect-error rollup type
747
- onLog(level, log, handler) {
748
- if (log.message.includes("react-helmet-async"))
749
- return;
750
- handler(level, log);
741
+ await build$1(
742
+ mergeConfig(viteConfig, {
743
+ build: {
744
+ manifest: true,
745
+ ssrManifest: true,
746
+ rollupOptions: {
747
+ input: {
748
+ app: join(root, htmlEntry || "./index.html")
749
+ },
750
+ // @ts-expect-error rollup type
751
+ onLog(level, log, handler) {
752
+ if (log.message.includes("react-helmet-async"))
753
+ return;
754
+ handler(level, log);
755
+ }
751
756
  }
752
- }
753
- },
754
- customLogger: clientLogger,
755
- mode: config.mode
756
- }));
757
+ },
758
+ customLogger: clientLogger,
759
+ mode: config.mode,
760
+ plugins: [
761
+ {
762
+ name: "vite-react-ssg:get-oup-dir",
763
+ configResolved(resolvedConfig) {
764
+ outDir = resolvedConfig.build.outDir || "dist";
765
+ }
766
+ }
767
+ ]
768
+ })
769
+ );
757
770
  let unmock = () => {
758
771
  };
759
772
  if (mock) {
@@ -763,37 +776,44 @@ async function build(ssgOptions = {}, viteConfig = {}) {
763
776
  buildLog("Build for server...");
764
777
  process.env.VITE_SSG = "true";
765
778
  const ssrEntry = await resolveAlias(config, entry);
766
- await build$1(mergeConfig(viteConfig, {
767
- build: {
768
- ssr: ssrEntry,
769
- manifest: true,
770
- outDir: ssgOut,
771
- minify: false,
772
- cssCodeSplit: false,
773
- rollupOptions: {
774
- output: format === "esm" ? {
775
- entryFileNames: "[name].mjs",
776
- format: "esm"
777
- } : {
778
- entryFileNames: "[name].cjs",
779
- format: "cjs"
780
- },
781
- // @ts-expect-error rollup type
782
- onLog(level, log, handler) {
783
- if (log.message.includes("react-helmet-async"))
784
- return;
785
- handler(level, log);
779
+ await build$1(
780
+ mergeConfig(viteConfig, {
781
+ build: {
782
+ ssr: ssrEntry,
783
+ manifest: true,
784
+ outDir: ssgOut,
785
+ minify: false,
786
+ cssCodeSplit: false,
787
+ rollupOptions: {
788
+ output: format === "esm" ? {
789
+ entryFileNames: "[name].mjs",
790
+ format: "esm"
791
+ } : {
792
+ entryFileNames: "[name].cjs",
793
+ format: "cjs"
794
+ },
795
+ // @ts-expect-error rollup type
796
+ onLog(level, log, handler) {
797
+ if (log.message.includes("react-helmet-async"))
798
+ return;
799
+ handler(level, log);
800
+ }
786
801
  }
787
- }
788
- },
789
- mode: config.mode
790
- }));
802
+ },
803
+ mode: config.mode
804
+ })
805
+ );
791
806
  const prefix = format === "esm" && process.platform === "win32" ? "file://" : "";
792
807
  const ext = format === "esm" ? ".mjs" : ".cjs";
793
808
  const serverEntry = prefix + join(ssgOut, parse(ssrEntry).name + ext).replace(/\\/g, "/");
794
- const serverManifest = JSON.parse(await fs.readFile(join(ssgOut, ...dotVitedir, "manifest.json"), "utf-8"));
809
+ const serverManifest = JSON.parse(
810
+ await fs.readFile(join(ssgOut, ...dotVitedir, "manifest.json"), "utf-8")
811
+ );
795
812
  const _require = createRequire(import.meta.url);
796
- const { createRoot, includedRoutes: serverEntryIncludedRoutes } = format === "esm" ? await import(serverEntry) : _require(serverEntry);
813
+ const {
814
+ createRoot,
815
+ includedRoutes: serverEntryIncludedRoutes
816
+ } = format === "esm" ? await import(serverEntry) : _require(serverEntry);
797
817
  const includedRoutes = serverEntryIncludedRoutes || configIncludedRoutes;
798
818
  const { routes } = await createRoot(false);
799
819
  const { paths } = await routesToPaths(routes);
@@ -801,28 +821,74 @@ async function build(ssgOptions = {}, viteConfig = {}) {
801
821
  routesPaths = DefaultIncludedRoutes(routesPaths);
802
822
  routesPaths = Array.from(new Set(routesPaths));
803
823
  buildLog("Rendering Pages...", routesPaths.length);
804
- const beasties = beastiesOptions !== false ? await getBeastiesOrCritters(outDir, { publicPath: configBase, ...beastiesOptions }) : void 0;
805
- if (beasties)
806
- console.log(`${gray("[vite-react-ssg]")} ${blue("Critical CSS generation enabled via `beasties`")}`);
807
- const ssrManifest = JSON.parse(await fs.readFile(join(out, ...dotVitedir, "ssr-manifest.json"), "utf-8"));
808
- const manifest = JSON.parse(await fs.readFile(join(out, ...dotVitedir, "manifest.json"), "utf-8"));
824
+ const beasties = beastiesOptions !== false ? await getBeastiesOrCritters(outDir, {
825
+ publicPath: configBase,
826
+ ...beastiesOptions
827
+ }) : void 0;
828
+ if (beasties) {
829
+ console.log(
830
+ `${gray("[vite-react-ssg]")} ${blue("Critical CSS generation enabled via `beasties`")}`
831
+ );
832
+ }
833
+ const out = isAbsolute(outDir) ? outDir : join(root, outDir);
834
+ const ssrManifest = JSON.parse(
835
+ await fs.readFile(join(out, ...dotVitedir, "ssr-manifest.json"), "utf-8")
836
+ );
837
+ const manifest = JSON.parse(
838
+ await fs.readFile(join(out, ...dotVitedir, "manifest.json"), "utf-8")
839
+ );
809
840
  let indexHTML = await fs.readFile(join(out, htmlEntry), "utf-8");
810
841
  fs.rmSync(join(out, htmlEntry));
811
842
  indexHTML = rewriteScripts(indexHTML, script);
812
843
  const queue = new PQueue({ concurrency });
813
844
  const crittersQueue = new PQueue({ concurrency: 1 });
814
845
  const staticLoaderDataManifest = {};
846
+ let loaderDataFileCount = 0;
815
847
  for (const path of routesPaths) {
816
848
  queue.add(async () => {
817
849
  try {
818
- const appCtx = await createRoot(false, path);
819
- const { base, routes: routes2, triggerOnSSRAppRendered, transformState = serializeState, app, routerType } = appCtx;
850
+ const appCtx = await createRoot(
851
+ false,
852
+ path
853
+ );
854
+ const {
855
+ base,
856
+ routes: routes2,
857
+ triggerOnSSRAppRendered,
858
+ transformState = serializeState,
859
+ app,
860
+ routerType
861
+ } = appCtx;
820
862
  const transformedIndexHTML = await onBeforePageRender?.(path, indexHTML, appCtx) || indexHTML;
821
863
  const fetchUrl = `${withTrailingSlash(base)}${removeLeadingSlash(path)}`;
822
864
  const adapter = getAdapter(appCtx);
823
- const assets = !app && routerType === "remix" ? await collectAssets({ routes: [...routes2], locationArg: fetchUrl, base, serverManifest, manifest, ssrManifest }) : /* @__PURE__ */ new Set();
824
- const { appHTML, bodyAttributes, htmlAttributes, metaAttributes, styleTag, routerContext } = await adapter.render(path);
825
- staticLoaderDataManifest[withLeadingSlash(path)] = routerContext?.loaderData;
865
+ const assets = !app && routerType === "remix" ? await collectAssets({
866
+ routes: [...routes2],
867
+ locationArg: fetchUrl,
868
+ base,
869
+ serverManifest,
870
+ manifest,
871
+ ssrManifest
872
+ }) : /* @__PURE__ */ new Set();
873
+ const {
874
+ appHTML,
875
+ bodyAttributes,
876
+ htmlAttributes,
877
+ metaAttributes,
878
+ styleTag,
879
+ routerContext
880
+ } = await adapter.render(path);
881
+ const loaderData = routerContext?.loaderData;
882
+ if (loaderData && Object.keys(loaderData).length > 0) {
883
+ const loaderDataFilePath = getLoaderDataFilePath(path, hash);
884
+ await fs.ensureDir(join(out, dirname(loaderDataFilePath)));
885
+ await fs.writeFile(
886
+ join(out, loaderDataFilePath),
887
+ JSON.stringify(loaderData)
888
+ );
889
+ staticLoaderDataManifest[withLeadingSlash(path)] = loaderDataFilePath;
890
+ loaderDataFileCount++;
891
+ }
826
892
  await triggerOnSSRAppRendered?.(path, appHTML, appCtx);
827
893
  const renderedHTML = await renderHTML({
828
894
  rootContainerId,
@@ -837,10 +903,18 @@ async function build(ssgOptions = {}, viteConfig = {}) {
837
903
  renderPreloadLinks(jsdom.window.document, assets);
838
904
  const html = jsdom.serialize();
839
905
  let transformed = await onPageRendered?.(path, html, appCtx) || html;
840
- transformed = transformed.replace(SCRIPT_COMMENT_PLACEHOLDER, `window.__VITE_REACT_SSG_HASH__ = '${hash}'`);
906
+ transformed = transformed.replace(
907
+ SCRIPT_COMMENT_PLACEHOLDER,
908
+ `window.__VITE_REACT_SSG_HASH__ = '${hash}'`
909
+ );
841
910
  if (beasties) {
842
- transformed = await crittersQueue.add(() => beasties.process(transformed));
843
- transformed = transformed.replace(/<link\srel="stylesheet"/g, '<link rel="stylesheet" crossorigin');
911
+ transformed = await crittersQueue.add(
912
+ () => beasties.process(transformed)
913
+ );
914
+ transformed = transformed.replace(
915
+ /<link\srel="stylesheet"/g,
916
+ '<link rel="stylesheet" crossorigin'
917
+ );
844
918
  }
845
919
  if (styleTag)
846
920
  transformed = transformed.replace("<head>", `<head>${styleTag}`);
@@ -853,15 +927,24 @@ async function build(ssgOptions = {}, viteConfig = {}) {
853
927
  `${dim(`${outDir}/`)}${cyan(filename.padEnd(15, " "))} ${dim(getSize(formatted))}`
854
928
  );
855
929
  } catch (err) {
856
- throw new Error(`${gray("[vite-react-ssg]")} ${red(`Error on page: ${cyan(path)}`)}
857
- ${err.stack}`);
930
+ throw new Error(
931
+ `${gray("[vite-react-ssg]")} ${red(`Error on page: ${cyan(path)}`)}
932
+ ${err.stack}`
933
+ );
858
934
  }
859
935
  });
860
936
  }
861
937
  await queue.start().onIdle();
862
- buildLog("Generating static loader data manifest...");
863
- const staticLoaderDataManifestString = JSON.stringify(staticLoaderDataManifest, null, 0);
864
- await fs.writeFile(join(out, `static-loader-data-manifest-${hash}.json`), staticLoaderDataManifestString);
938
+ buildLog("Generating static loader data...", loaderDataFileCount);
939
+ const staticLoaderDataManifestString = JSON.stringify(
940
+ staticLoaderDataManifest,
941
+ null,
942
+ 0
943
+ );
944
+ await fs.writeFile(
945
+ join(out, `static-loader-data-manifest-${hash}.json`),
946
+ staticLoaderDataManifestString
947
+ );
865
948
  config.logger.info(
866
949
  `${dim(`${outDir}/`)}${cyan(`static-loader-data-manifest-${hash}.json`.padEnd(15, " "))} ${dim(getSize(staticLoaderDataManifestString))}`
867
950
  );
@@ -874,10 +957,12 @@ ${err.stack}`);
874
957
  }
875
958
  console.log(`
876
959
  ${gray("[vite-react-ssg]")} ${green("Build finished.")}`);
877
- await onFinished?.();
960
+ await onFinished?.(outDir);
878
961
  const waitInSeconds = 15;
879
962
  const timeout = setTimeout(() => {
880
- console.log(`${gray("[vite-react-ssg]")} ${yellow(`Build process still running after ${waitInSeconds}s`)}. There might be something misconfigured in your setup. Force exit.`);
963
+ console.log(
964
+ `${gray("[vite-react-ssg]")} ${yellow(`Build process still running after ${waitInSeconds}s`)}. There might be something misconfigured in your setup. Force exit.`
965
+ );
881
966
  process.exit(0);
882
967
  }, waitInSeconds * 1e3);
883
968
  timeout.unref();
@@ -885,16 +970,25 @@ ${gray("[vite-react-ssg]")} ${green("Build finished.")}`);
885
970
  function rewriteScripts(indexHTML, mode) {
886
971
  if (!mode || mode === "sync")
887
972
  return indexHTML;
888
- return indexHTML.replace(/<script type="module" /g, `<script type="module" ${mode} `);
973
+ return indexHTML.replace(
974
+ /<script type="module" /g,
975
+ `<script type="module" ${mode} `
976
+ );
889
977
  }
890
978
  async function formatHtml(html, formatting) {
891
979
  if (formatting === "prettify") {
892
980
  try {
893
981
  const prettier = (await import('prettier/esm/standalone.mjs')).default;
894
982
  const parserHTML = (await import('prettier/esm/parser-html.mjs')).default;
895
- return prettier.format(html, { semi: false, parser: "html", plugins: [parserHTML] });
983
+ return prettier.format(html, {
984
+ semi: false,
985
+ parser: "html",
986
+ plugins: [parserHTML]
987
+ });
896
988
  } catch (e) {
897
- console.error(`${gray("[vite-react-ssg]")} ${red(`Error formatting html: ${e?.message}`)}`);
989
+ console.error(
990
+ `${gray("[vite-react-ssg]")} ${red(`Error formatting html: ${e?.message}`)}`
991
+ );
898
992
  return html;
899
993
  }
900
994
  }
@@ -1,6 +1,6 @@
1
1
  import { AnyRouter } from '@tanstack/react-router';
2
- import { V as ViteReactSSGContext$1, a as ViteReactSSGClientOptions } from './shared/vite-react-ssg.B2xAADcy.mjs';
3
- export { C as CrittersOptions, I as IndexRouteRecord, N as NonIndexRouteRecord, R as RouteRecord, c as RouterFutureConfig, S as StyleCollector, b as ViteReactSSGOptions } from './shared/vite-react-ssg.B2xAADcy.mjs';
2
+ import { V as ViteReactSSGContext$1, a as ViteReactSSGClientOptions } from './shared/vite-react-ssg.CHKvDn8n.mjs';
3
+ export { C as CrittersOptions, I as IndexRouteRecord, N as NonIndexRouteRecord, R as RouteRecord, b as RouterFutureConfig, S as StyleCollector, d as ViteReactSSGOptions } from './shared/vite-react-ssg.CHKvDn8n.mjs';
4
4
  export { C as ClientOnly, H as Head } from './shared/vite-react-ssg.-NlgsPvg.mjs';
5
5
  import 'beasties';
6
6
  import 'react';
@@ -22,10 +22,14 @@ type ViteReactSSGContext<HasRouter extends boolean = true> = Omit<ViteReactSSGCo
22
22
  declare function Experimental_ViteReactSSG(routerOptions: RouterOptions, fn?: (context: ViteReactSSGContext<true>) => Promise<void> | void, options?: ViteReactSSGClientOptions): (client?: boolean, routePath?: string) => Promise<ViteReactSSGContext<true>>;
23
23
  declare global {
24
24
  interface Window {
25
- __VITE_REACT_SSG_STATIC_LOADER_DATA__: any;
25
+ /** Manifest index: route path -> data file path */
26
+ __VITE_REACT_SSG_STATIC_LOADER_MANIFEST__: Record<string, string>;
27
+ /** Cached loader data: route path -> loader data */
28
+ __VITE_REACT_SSG_STATIC_LOADER_DATA__: Record<string, Record<string, unknown>>;
26
29
  __VITE_REACT_SSG_HASH__: string;
27
30
  __VITE_REACT_SSG_CONTEXT__: ViteReactSSGContext<true>;
28
31
  }
29
32
  }
30
33
 
31
- export { Experimental_ViteReactSSG, type RouterOptions, ViteReactSSGClientOptions, type ViteReactSSGContext, registerPaths };
34
+ export { Experimental_ViteReactSSG, ViteReactSSGClientOptions, registerPaths };
35
+ export type { RouterOptions, ViteReactSSGContext };
@@ -1,6 +1,6 @@
1
1
  import { AnyRouter } from '@tanstack/react-router';
2
- import { V as ViteReactSSGContext$1, a as ViteReactSSGClientOptions } from './shared/vite-react-ssg.B2xAADcy.js';
3
- export { C as CrittersOptions, I as IndexRouteRecord, N as NonIndexRouteRecord, R as RouteRecord, c as RouterFutureConfig, S as StyleCollector, b as ViteReactSSGOptions } from './shared/vite-react-ssg.B2xAADcy.js';
2
+ import { V as ViteReactSSGContext$1, a as ViteReactSSGClientOptions } from './shared/vite-react-ssg.CHKvDn8n.js';
3
+ export { C as CrittersOptions, I as IndexRouteRecord, N as NonIndexRouteRecord, R as RouteRecord, b as RouterFutureConfig, S as StyleCollector, d as ViteReactSSGOptions } from './shared/vite-react-ssg.CHKvDn8n.js';
4
4
  export { C as ClientOnly, H as Head } from './shared/vite-react-ssg.-NlgsPvg.js';
5
5
  import 'beasties';
6
6
  import 'react';
@@ -22,10 +22,14 @@ type ViteReactSSGContext<HasRouter extends boolean = true> = Omit<ViteReactSSGCo
22
22
  declare function Experimental_ViteReactSSG(routerOptions: RouterOptions, fn?: (context: ViteReactSSGContext<true>) => Promise<void> | void, options?: ViteReactSSGClientOptions): (client?: boolean, routePath?: string) => Promise<ViteReactSSGContext<true>>;
23
23
  declare global {
24
24
  interface Window {
25
- __VITE_REACT_SSG_STATIC_LOADER_DATA__: any;
25
+ /** Manifest index: route path -> data file path */
26
+ __VITE_REACT_SSG_STATIC_LOADER_MANIFEST__: Record<string, string>;
27
+ /** Cached loader data: route path -> loader data */
28
+ __VITE_REACT_SSG_STATIC_LOADER_DATA__: Record<string, Record<string, unknown>>;
26
29
  __VITE_REACT_SSG_HASH__: string;
27
30
  __VITE_REACT_SSG_CONTEXT__: ViteReactSSGContext<true>;
28
31
  }
29
32
  }
30
33
 
31
- export { Experimental_ViteReactSSG, type RouterOptions, ViteReactSSGClientOptions, type ViteReactSSGContext, registerPaths };
34
+ export { Experimental_ViteReactSSG, ViteReactSSGClientOptions, registerPaths };
35
+ export type { RouterOptions, ViteReactSSGContext };
package/dist/tanstack.mjs CHANGED
@@ -1,143 +1,15 @@
1
- import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
2
- import { RouterProvider } from '@tanstack/react-router';
3
- import { Meta, StartClient } from '@tanstack/start';
4
- import { HelmetProvider } from 'react-helmet-async';
5
- import { r as render, h as hydrate, d as documentReady } from './shared/vite-react-ssg.BxjO14Et.mjs';
6
- export { C as ClientOnly, H as Head } from './shared/vite-react-ssg.BxjO14Et.mjs';
7
- import { j as joinUrlSegments, w as withLeadingSlash, s as stripBase } from './shared/vite-react-ssg.CjIppNIS.mjs';
8
- import { d as deserializeState } from './shared/vite-react-ssg.C6pK7rvr.mjs';
9
- import { M as META_CONTAINER_ID, c as convertRouteTreeToRouteOption } from './shared/vite-react-ssg.B-j07kW6.mjs';
10
- export { r as registerPaths } from './shared/vite-react-ssg.B-j07kW6.mjs';
1
+ import 'react/jsx-runtime';
2
+ import '@tanstack/react-router';
3
+ import '@tanstack/start';
4
+ import 'react-helmet-async';
5
+ export { r as registerPaths } from './shared/vite-react-ssg.BqDzTpJh.mjs';
6
+ export { C as ClientOnly, H as Head } from './shared/vite-react-ssg.CoMLbIiW.mjs';
11
7
  import 'react';
12
- import 'react-dom';
13
8
 
14
- const HAS_ADD_META_FLAG_KEY = "HAS_ADD_META_FLAG_KEY";
15
9
  function Experimental_ViteReactSSG(routerOptions, fn, options = {}) {
16
- const {
17
- transformState,
18
- rootContainer = "#root",
19
- ssrWhenDev,
20
- getStyleCollector = null
21
- } = options;
22
- if (process.env.NODE_ENV === "development" && ssrWhenDev !== void 0)
23
- console.warn("[vite-react-ssg] `ssrWhenDev` option is no longer needed. If you want to use csr, just replace `vite-react-ssg dev` with `vite`.");
24
- const isClient = typeof window !== "undefined";
25
- const BASE_URL = routerOptions.basename ?? "/";
26
- const routeTree = routerOptions.routes;
27
- const OriginComponent = routeTree.options.component;
28
- if (!OriginComponent[HAS_ADD_META_FLAG_KEY]) {
29
- const component = () => /* @__PURE__ */ jsxs(Fragment, { children: [
30
- /* @__PURE__ */ jsx(OriginComponent, {}),
31
- /* @__PURE__ */ jsx("div", { id: META_CONTAINER_ID, style: { display: "none" }, children: /* @__PURE__ */ jsx(Meta, {}) })
32
- ] });
33
- component[HAS_ADD_META_FLAG_KEY] = true;
34
- routeTree.update({
35
- component
36
- });
37
- }
38
- async function createRoot(client = false, routePath) {
39
- const routes = await convertRouteTreeToRouteOption(
40
- routerOptions.routes,
41
- client,
42
- client ? (node) => {
43
- const isSSR = document.querySelector("[data-server-rendered=true]") !== null;
44
- if (!isSSR)
45
- return;
46
- node.options.loader = async (ctx) => {
47
- let pathname = ctx.location.pathname;
48
- if (process.env.NODE_ENV === "development") {
49
- const routeId = encodeURIComponent(node.id);
50
- const dataQuery = `_data=${routeId}`;
51
- const href = ctx.location.href;
52
- const url = href.includes("?") ? `${href}&${dataQuery}` : `${href}?${dataQuery}`;
53
- const res = await fetch(url);
54
- const header = res.headers;
55
- const contentType = header.get("content-type");
56
- if (contentType?.startsWith("application/json"))
57
- return res.json();
58
- return res.text();
59
- }
60
- let staticLoadData;
61
- if (window.__VITE_REACT_SSG_STATIC_LOADER_DATA__) {
62
- staticLoadData = window.__VITE_REACT_SSG_STATIC_LOADER_DATA__;
63
- } else {
64
- const manifestUrl = joinUrlSegments(BASE_URL, `static-loader-data-manifest-${window.__VITE_REACT_SSG_HASH__}.json`);
65
- staticLoadData = await (await fetch(withLeadingSlash(manifestUrl))).json();
66
- window.__VITE_REACT_SSG_STATIC_LOADER_DATA__ = staticLoadData;
67
- }
68
- if (BASE_URL !== "/") {
69
- pathname = stripBase(pathname, BASE_URL);
70
- }
71
- const routeData = staticLoadData?.[pathname]?.find((item) => item.id === node.id);
72
- return routeData?.loaderData ?? null;
73
- };
74
- } : void 0
75
- );
76
- const router = routerOptions.router;
77
- router.options.isServer = !client;
78
- const appRenderCallbacks = [];
79
- const onSSRAppRendered = client ? () => {
80
- } : (cb) => appRenderCallbacks.push(cb);
81
- const triggerOnSSRAppRendered = () => {
82
- return Promise.all(appRenderCallbacks.map((cb) => cb()));
83
- };
84
- const context = {
85
- isClient,
86
- routes,
87
- routeTree,
88
- router,
89
- routerOptions: {
90
- routes,
91
- basename: BASE_URL
92
- },
93
- onSSRAppRendered,
94
- triggerOnSSRAppRendered,
95
- initialState: {},
96
- transformState,
97
- routePath,
98
- base: BASE_URL,
99
- getStyleCollector,
100
- routerType: "tanstack"
101
- };
102
- if (client) {
103
- await documentReady();
104
- context.initialState = transformState?.(window.__INITIAL_STATE__ || {}) || deserializeState(window.__INITIAL_STATE__);
105
- }
106
- await fn?.(context);
107
- const initialState = context.initialState;
108
- return {
109
- ...context,
110
- initialState
111
- };
112
- }
113
- if (isClient) {
114
- (async () => {
115
- const container = typeof rootContainer === "string" ? document.querySelector(rootContainer) : rootContainer;
116
- if (!container) {
117
- if (typeof $jsdom === "undefined")
118
- console.warn("[vite-react-ssg] Root container not found.");
119
- return;
120
- }
121
- const context = await createRoot(true);
122
- window.__VITE_REACT_SSG_CONTEXT__ = context;
123
- const { router } = context;
124
- const isSSR = document.querySelector("[data-server-rendered=true]") !== null;
125
- if (!isSSR && process.env.NODE_ENV === "development") {
126
- render(
127
- /* @__PURE__ */ jsx(HelmetProvider, { children: /* @__PURE__ */ jsx(RouterProvider, { router }) }),
128
- container,
129
- options
130
- );
131
- } else {
132
- hydrate(
133
- /* @__PURE__ */ jsx(HelmetProvider, { children: /* @__PURE__ */ jsx(StartClient, { router }) }),
134
- container,
135
- options
136
- );
137
- }
138
- })();
139
- }
140
- return createRoot;
10
+ throw new Error(
11
+ "[vite-react-ssg] Sorry, this Version has no support for tanstack router. Please contact me via GitHub issue if you need this feature."
12
+ );
141
13
  }
142
14
 
143
15
  export { Experimental_ViteReactSSG };
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "vite-react-ssg",
3
3
  "type": "module",
4
- "version": "0.8.8",
5
- "packageManager": "pnpm@10.12.1",
4
+ "version": "0.9.0",
5
+ "packageManager": "pnpm@10.28.2",
6
6
  "description": "Static-site generation for React on Vite.",
7
7
  "author": "Riri <Daydreamerriri@outlook.com>",
8
8
  "license": "MIT",
@@ -69,7 +69,7 @@
69
69
  "build": "unbuild",
70
70
  "dev": "unbuild --stub",
71
71
  "lint": "eslint .",
72
- "test": "pnpm -r --filter=./examples/* build && vitest run",
72
+ "test": "pnpm -r build && vitest run",
73
73
  "prepublishOnly": "nr build",
74
74
  "release": "bumpp && npm publish",
75
75
  "start": "esno src/index.ts",
@@ -109,46 +109,45 @@
109
109
  }
110
110
  },
111
111
  "dependencies": {
112
- "@remix-run/web-fetch": "^4.4.2",
113
- "fs-extra": "^11.3.0",
112
+ "fs-extra": "^11.3.3",
114
113
  "html5parser": "^2.0.2",
115
114
  "jsdom": "^24.1.3",
116
115
  "kolorist": "^1.8.0",
117
- "p-queue": "^8.1.0",
116
+ "p-queue": "^9.1.0",
118
117
  "react-helmet-async": "^1.3.0",
119
118
  "yargs": "^17.7.2"
120
119
  },
121
120
  "devDependencies": {
122
- "@ririd/eslint-config": "^1.4.0",
123
- "@tanstack/react-router": "^1.121.24",
121
+ "@ririd/eslint-config": "^2.1.1",
122
+ "@tanstack/react-router": "^1.158.0",
124
123
  "@tanstack/start": "^1.120.20",
125
124
  "@types/fs-extra": "^11.0.4",
126
125
  "@types/jsdom": "^21.1.7",
127
- "@types/node": "^18.19.112",
126
+ "@types/node": "^18.19.130",
128
127
  "@types/react": "catalog:",
129
128
  "@types/react-dom": "catalog:",
130
- "@types/yargs": "^17.0.33",
131
- "@vitejs/plugin-react-swc": "^3.10.2",
132
- "beasties": "^0.3.4",
133
- "bumpp": "^10.2.0",
129
+ "@types/yargs": "^17.0.35",
130
+ "@vitejs/plugin-react-swc": "^3.11.0",
131
+ "beasties": "^0.4.1",
132
+ "bumpp": "^10.4.0",
134
133
  "critters": "^0.0.25",
135
- "eslint": "^9.29.0",
134
+ "eslint": "^9.39.2",
136
135
  "esno": "^4.8.0",
137
136
  "fast-glob": "3.3.2",
138
- "prettier": "^3.5.3",
137
+ "prettier": "^3.8.1",
139
138
  "react": "catalog:",
140
139
  "react-dom": "catalog:",
141
- "react-router-dom": "^6.30.1",
140
+ "react-router-dom": "^6.30.3",
142
141
  "rimraf": "5.0.1",
143
142
  "styled-components": "6.0.5",
144
- "typescript": "^5.8.3",
145
- "unbuild": "^3.5.0",
143
+ "typescript": "^5.9.3",
144
+ "unbuild": "^3.6.1",
146
145
  "vite": "catalog:",
147
146
  "vitest": "1.6.1"
148
147
  },
149
148
  "pnpm": {
150
149
  "overrides": {
151
- "@babel/traverse": "^7.27.4"
150
+ "@babel/traverse": "^7.29.0"
152
151
  },
153
152
  "onlyBuiltDependencies": [
154
153
  "@swc/core",
@@ -1,31 +0,0 @@
1
- const ViteReactSSGTanstackRouterStaticPathsContext = {};
2
- function registerPaths(id, getStaticPaths) {
3
- ViteReactSSGTanstackRouterStaticPathsContext[id] = getStaticPaths;
4
- }
5
- async function convertRouteTreeToRouteOption(routeTree, client, visitNode) {
6
- const routes = [];
7
- async function traverseRouteTree(node) {
8
- if (!client && node.path?.includes("$") && node.lazyFn) {
9
- await node.lazyFn();
10
- }
11
- visitNode?.(node);
12
- const routeRecord = {
13
- path: node.path,
14
- getStaticPaths: ViteReactSSGTanstackRouterStaticPathsContext[node.id]
15
- };
16
- routeRecord.path = routeRecord.path?.replaceAll("$", ":");
17
- const children = node.children;
18
- if (children) {
19
- routeRecord.children = [];
20
- for (const child of Object.values(children)) {
21
- routeRecord.children.push(await traverseRouteTree(child));
22
- }
23
- }
24
- return routeRecord;
25
- }
26
- routes.push(await traverseRouteTree(routeTree));
27
- return routes;
28
- }
29
- const META_CONTAINER_ID = "__SSG_TANSTACK_META_CONTAINER__";
30
-
31
- export { META_CONTAINER_ID as M, convertRouteTreeToRouteOption as c, registerPaths as r };
@@ -1,30 +0,0 @@
1
- function joinUrlSegments(a, b) {
2
- if (!a || !b)
3
- return a || b || "";
4
- if (a[a.length - 1] === "/")
5
- a = a.substring(0, a.length - 1);
6
- if (b[0] !== "/")
7
- b = `/${b}`;
8
- return a + b;
9
- }
10
- function removeLeadingSlash(str) {
11
- return str[0] === "/" ? str.slice(1) : str;
12
- }
13
- function stripBase(path, base) {
14
- if (path === base)
15
- return "/";
16
- const devBase = withTrailingSlash(base);
17
- return path.startsWith(devBase) ? path.slice(devBase.length - 1) : path;
18
- }
19
- function withTrailingSlash(path) {
20
- if (path[path.length - 1] !== "/")
21
- return `${path}/`;
22
- return path;
23
- }
24
- function withLeadingSlash(path) {
25
- if (path[0] !== "/")
26
- return `/${path}`;
27
- return path;
28
- }
29
-
30
- export { withTrailingSlash as a, joinUrlSegments as j, removeLeadingSlash as r, stripBase as s, withLeadingSlash as w };