@praxisjs/ssg 0.1.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.
Files changed (54) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/LICENSE +21 -0
  3. package/dist/__tests__/loader-hook.test.d.ts +2 -0
  4. package/dist/__tests__/loader-hook.test.d.ts.map +1 -0
  5. package/dist/__tests__/loader-hook.test.js +66 -0
  6. package/dist/__tests__/loader-hook.test.js.map +1 -0
  7. package/dist/__tests__/plugin.test.d.ts +2 -0
  8. package/dist/__tests__/plugin.test.d.ts.map +1 -0
  9. package/dist/__tests__/plugin.test.js +128 -0
  10. package/dist/__tests__/plugin.test.js.map +1 -0
  11. package/dist/__tests__/prerender.test.d.ts +2 -0
  12. package/dist/__tests__/prerender.test.d.ts.map +1 -0
  13. package/dist/__tests__/prerender.test.js +211 -0
  14. package/dist/__tests__/prerender.test.js.map +1 -0
  15. package/dist/__tests__/register-fallback.test.d.ts +2 -0
  16. package/dist/__tests__/register-fallback.test.d.ts.map +1 -0
  17. package/dist/__tests__/register-fallback.test.js +20 -0
  18. package/dist/__tests__/register-fallback.test.js.map +1 -0
  19. package/dist/__tests__/resolve-sync.test.d.ts +2 -0
  20. package/dist/__tests__/resolve-sync.test.d.ts.map +1 -0
  21. package/dist/__tests__/resolve-sync.test.js +67 -0
  22. package/dist/__tests__/resolve-sync.test.js.map +1 -0
  23. package/dist/__tests__/routes.test.d.ts +2 -0
  24. package/dist/__tests__/routes.test.d.ts.map +1 -0
  25. package/dist/__tests__/routes.test.js +154 -0
  26. package/dist/__tests__/routes.test.js.map +1 -0
  27. package/dist/index.d.ts +59 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +156 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/loader-hook.d.ts +5 -0
  32. package/dist/loader-hook.d.ts.map +1 -0
  33. package/dist/loader-hook.js +34 -0
  34. package/dist/loader-hook.js.map +1 -0
  35. package/dist/prerender.d.ts +38 -0
  36. package/dist/prerender.d.ts.map +1 -0
  37. package/dist/prerender.js +116 -0
  38. package/dist/prerender.js.map +1 -0
  39. package/dist/routes.d.ts +32 -0
  40. package/dist/routes.d.ts.map +1 -0
  41. package/dist/routes.js +59 -0
  42. package/dist/routes.js.map +1 -0
  43. package/package.json +38 -0
  44. package/src/__tests__/loader-hook.test.ts +76 -0
  45. package/src/__tests__/plugin.test.ts +161 -0
  46. package/src/__tests__/prerender.test.ts +181 -0
  47. package/src/__tests__/register-fallback.test.ts +23 -0
  48. package/src/__tests__/resolve-sync.test.ts +91 -0
  49. package/src/__tests__/routes.test.ts +175 -0
  50. package/src/index.ts +233 -0
  51. package/src/loader-hook.ts +43 -0
  52. package/src/prerender.ts +168 -0
  53. package/src/routes.ts +83 -0
  54. package/tsconfig.json +11 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-sync.test.js","sourceRoot":"","sources":["../../src/__tests__/resolve-sync.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=routes.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/routes.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,154 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { flattenRoutes, isStaticPath, pathToOutputFile, resolvePaths } from "../routes";
3
+ const Noop = class {
4
+ };
5
+ describe("flattenRoutes", () => {
6
+ it("flattens a flat route list unchanged", () => {
7
+ const routes = [
8
+ { path: "/", component: Noop },
9
+ { path: "/about", component: Noop },
10
+ ];
11
+ expect(flattenRoutes(routes).map((r) => r.fullPath)).toEqual(["/", "/about"]);
12
+ });
13
+ it("prefixes nested children with the parent path", () => {
14
+ const routes = [
15
+ {
16
+ path: "/blog",
17
+ component: Noop,
18
+ children: [
19
+ { path: "/", component: Noop },
20
+ { path: "/:slug", component: Noop },
21
+ ],
22
+ },
23
+ ];
24
+ expect(flattenRoutes(routes).map((r) => r.fullPath)).toEqual(["/blog", "/blog/", "/blog/:slug"]);
25
+ });
26
+ it("treats a root parent's prefix as empty, matching RouterInstance.addRoute", () => {
27
+ const routes = [
28
+ {
29
+ path: "/",
30
+ component: Noop,
31
+ children: [{ path: "/dashboard", component: Noop }],
32
+ },
33
+ ];
34
+ expect(flattenRoutes(routes).map((r) => r.fullPath)).toEqual(["/", "/dashboard"]);
35
+ });
36
+ });
37
+ describe("isStaticPath", () => {
38
+ it("treats plain paths as static", () => {
39
+ expect(isStaticPath("/about")).toBe(true);
40
+ expect(isStaticPath("/")).toBe(true);
41
+ });
42
+ it("treats :param segments as dynamic", () => {
43
+ expect(isStaticPath("/blog/:slug")).toBe(false);
44
+ });
45
+ it("treats optional :param? segments as dynamic", () => {
46
+ expect(isStaticPath("/users/:id?")).toBe(false);
47
+ });
48
+ it("treats ** catch-alls as dynamic", () => {
49
+ expect(isStaticPath("/docs/**")).toBe(false);
50
+ });
51
+ });
52
+ describe("resolvePaths", () => {
53
+ it("returns static paths as-is", async () => {
54
+ const routes = [
55
+ { path: "/", component: Noop },
56
+ { path: "/about", component: Noop },
57
+ ];
58
+ expect(await resolvePaths({ routes })).toEqual(["/", "/about"]);
59
+ });
60
+ it("expands a dynamic route via getStaticPaths", async () => {
61
+ const routes = [{ path: "/blog/:slug", component: Noop }];
62
+ const paths = await resolvePaths({
63
+ routes,
64
+ getStaticPaths: async () => ["/blog/hello", "/blog/world"],
65
+ });
66
+ expect(paths).toEqual(["/blog/hello", "/blog/world"]);
67
+ });
68
+ it("skips dynamic routes with no getStaticPaths", async () => {
69
+ const routes = [
70
+ { path: "/", component: Noop },
71
+ { path: "/blog/:slug", component: Noop },
72
+ ];
73
+ expect(await resolvePaths({ routes })).toEqual(["/"]);
74
+ });
75
+ it("passes the route and its full path pattern to getStaticPaths", async () => {
76
+ const target = { path: "/blog/:slug", component: Noop };
77
+ const routes = [target];
78
+ let seen;
79
+ await resolvePaths({
80
+ routes,
81
+ getStaticPaths: async (route, fullPath) => {
82
+ seen = [route, fullPath];
83
+ return [];
84
+ },
85
+ });
86
+ expect(seen).toEqual([target, "/blog/:slug"]);
87
+ });
88
+ it("de-duplicates paths across routes", async () => {
89
+ const routes = [
90
+ { path: "/blog/:slug", component: Noop },
91
+ { path: "/other/:slug", component: Noop },
92
+ ];
93
+ const paths = await resolvePaths({
94
+ routes,
95
+ getStaticPaths: async () => ["/shared"],
96
+ });
97
+ expect(paths).toEqual(["/shared"]);
98
+ });
99
+ it("expands a dynamic route via its own colocated getStaticPaths, with no global fallback needed", async () => {
100
+ const routes = [
101
+ { path: "/blog/:slug", component: Noop, getStaticPaths: async () => ["/blog/hello", "/blog/world"] },
102
+ ];
103
+ expect(await resolvePaths({ routes })).toEqual(["/blog/hello", "/blog/world"]);
104
+ });
105
+ it("passes the route's own full path to its colocated getStaticPaths", async () => {
106
+ let seen;
107
+ const routes = [
108
+ {
109
+ path: "/blog/:slug",
110
+ component: Noop,
111
+ getStaticPaths: async (fullPath) => {
112
+ seen = fullPath;
113
+ return [];
114
+ },
115
+ },
116
+ ];
117
+ await resolvePaths({ routes });
118
+ expect(seen).toBe("/blog/:slug");
119
+ });
120
+ it("prefers a route's own getStaticPaths over the global fallback", async () => {
121
+ const routes = [
122
+ { path: "/blog/:slug", component: Noop, getStaticPaths: async () => ["/blog/own"] },
123
+ ];
124
+ const paths = await resolvePaths({
125
+ routes,
126
+ getStaticPaths: async () => ["/blog/global"],
127
+ });
128
+ expect(paths).toEqual(["/blog/own"]);
129
+ });
130
+ it("falls back to the global getStaticPaths for routes with no colocated one, alongside routes that have their own", async () => {
131
+ const routes = [
132
+ { path: "/blog/:slug", component: Noop, getStaticPaths: async () => ["/blog/own"] },
133
+ { path: "/other/:slug", component: Noop },
134
+ ];
135
+ const paths = await resolvePaths({
136
+ routes,
137
+ getStaticPaths: async (_route, fullPath) => (fullPath === "/other/:slug" ? ["/other/global"] : []),
138
+ });
139
+ expect(paths).toEqual(["/blog/own", "/other/global"]);
140
+ });
141
+ });
142
+ describe("pathToOutputFile", () => {
143
+ it("maps the root path to index.html", () => {
144
+ expect(pathToOutputFile("/")).toBe("index.html");
145
+ });
146
+ it("maps a nested path to <path>/index.html", () => {
147
+ expect(pathToOutputFile("/about")).toBe("about/index.html");
148
+ expect(pathToOutputFile("/blog/hello-world")).toBe("blog/hello-world/index.html");
149
+ });
150
+ it("normalizes surrounding slashes", () => {
151
+ expect(pathToOutputFile("/about/")).toBe("about/index.html");
152
+ });
153
+ });
154
+ //# sourceMappingURL=routes.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.test.js","sourceRoot":"","sources":["../../src/__tests__/routes.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAI9C,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAExF,MAAM,IAAI,GAAG;CAAiB,CAAC;AAE/B,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,MAAM,GAAsB;YAChC,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE;YAC9B,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE;SACpC,CAAC;QACF,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;IAChF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,MAAM,GAAsB;YAChC;gBACE,IAAI,EAAE,OAAO;gBACb,SAAS,EAAE,IAAI;gBACf,QAAQ,EAAE;oBACR,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE;oBAC9B,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE;iBACpC;aACF;SACF,CAAC;QACF,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC;IACnG,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0EAA0E,EAAE,GAAG,EAAE;QAClF,MAAM,MAAM,GAAsB;YAChC;gBACE,IAAI,EAAE,GAAG;gBACT,SAAS,EAAE,IAAI;gBACf,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;aACpD;SACF,CAAC;QACF,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC;IACpF,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1C,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,EAAE,CAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;QAC1C,MAAM,MAAM,GAAsB;YAChC,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE;YAC9B,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE;SACpC,CAAC;QACF,MAAM,CAAC,MAAM,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC1D,MAAM,MAAM,GAAsB,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7E,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC;YAC/B,MAAM;YACN,cAAc,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,aAAa,EAAE,aAAa,CAAC;SAC3D,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC3D,MAAM,MAAM,GAAsB;YAChC,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE;YAC9B,EAAE,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,IAAI,EAAE;SACzC,CAAC;QACF,MAAM,CAAC,MAAM,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8DAA8D,EAAE,KAAK,IAAI,EAAE;QAC5E,MAAM,MAAM,GAAoB,EAAE,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;QACzE,MAAM,MAAM,GAAsB,CAAC,MAAM,CAAC,CAAC;QAC3C,IAAI,IAA2C,CAAC;QAChD,MAAM,YAAY,CAAC;YACjB,MAAM;YACN,cAAc,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE;gBACxC,IAAI,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;gBACzB,OAAO,EAAE,CAAC;YACZ,CAAC;SACF,CAAC,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;QACjD,MAAM,MAAM,GAAsB;YAChC,EAAE,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,IAAI,EAAE;YACxC,EAAE,IAAI,EAAE,cAAc,EAAE,SAAS,EAAE,IAAI,EAAE;SAC1C,CAAC;QACF,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC;YAC/B,MAAM;YACN,cAAc,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,SAAS,CAAC;SACxC,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8FAA8F,EAAE,KAAK,IAAI,EAAE;QAC5G,MAAM,MAAM,GAAsB;YAChC,EAAE,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,aAAa,EAAE,aAAa,CAAC,EAAqB;SACxH,CAAC;QACF,MAAM,CAAC,MAAM,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kEAAkE,EAAE,KAAK,IAAI,EAAE;QAChF,IAAI,IAAwB,CAAC;QAC7B,MAAM,MAAM,GAAsB;YAChC;gBACE,IAAI,EAAE,aAAa;gBACnB,SAAS,EAAE,IAAI;gBACf,cAAc,EAAE,KAAK,EAAE,QAAgB,EAAE,EAAE;oBACzC,IAAI,GAAG,QAAQ,CAAC;oBAChB,OAAO,EAAE,CAAC;gBACZ,CAAC;aACiB;SACrB,CAAC;QACF,MAAM,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QAC/B,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+DAA+D,EAAE,KAAK,IAAI,EAAE;QAC7E,MAAM,MAAM,GAAsB;YAChC,EAAE,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,WAAW,CAAC,EAAqB;SACvG,CAAC;QACF,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC;YAC/B,MAAM;YACN,cAAc,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,cAAc,CAAC;SAC7C,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gHAAgH,EAAE,KAAK,IAAI,EAAE;QAC9H,MAAM,MAAM,GAAsB;YAChC,EAAE,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,WAAW,CAAC,EAAqB;YACtG,EAAE,IAAI,EAAE,cAAc,EAAE,SAAS,EAAE,IAAI,EAAE;SAC1C,CAAC;QACF,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC;YAC/B,MAAM;YACN,cAAc,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC,QAAQ,KAAK,cAAc,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;SACnG,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,eAAe,CAAC,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAC5D,MAAM,CAAC,gBAAgB,CAAC,mBAAmB,CAAC,CAAC,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;IACpF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,59 @@
1
+ import { type Plugin } from "vite";
2
+ import type { RouterOptions } from "@praxisjs/router";
3
+ export type { GetStaticPaths, RouteEntry, RouteStaticPaths } from "./routes";
4
+ export interface SSGConfig {
5
+ /**
6
+ * Module specifier exporting the root component as its default export and
7
+ * the route table (same one passed to `@Router([...])`) as a named
8
+ * `routes` export, e.g. `"./src/app.tsx"`. Loaded through Vite's own SSR
9
+ * module graph — not imported directly by `vite.config.ts` — so the config
10
+ * file itself never needs to resolve JSX/component source.
11
+ *
12
+ * A dynamic route can expand itself into concrete paths by declaring its
13
+ * own `getStaticPaths` directly on the route object (see `RouteEntry`) —
14
+ * the recommended default, since it's colocated with the route and needs
15
+ * no path matching. `root` may *also* export a named `getStaticPaths` as a
16
+ * fallback for routes that don't declare their own; a route's own always
17
+ * takes precedence.
18
+ *
19
+ * Either way, this can only be reached through `root`, never passed as a
20
+ * plain config value here: Vite's own config loader bundles
21
+ * `vite.config.ts` with a minimal bundler that inlines relative imports
22
+ * (only bare package specifiers get externalized) but never lowers TC39
23
+ * decorators. A `getStaticPaths` written inline in `vite.config.ts` that
24
+ * reaches a decorated class through a relative import — e.g. one that
25
+ * loads a `@Collection`-decorated schema to enumerate content slugs —
26
+ * would bundle that raw decorator syntax straight into the config bundle,
27
+ * which Node cannot then execute. Exporting it from the same module as
28
+ * `root` (or from a route reachable from it) avoids this: it only ever
29
+ * loads through `ssrLoadModule`, which runs the app's real Vite pipeline
30
+ * (decorator lowering included).
31
+ */
32
+ root: string;
33
+ routerOptions?: RouterOptions;
34
+ /** CSS selector for the mount container inside `index.html`. Default: `#app`. */
35
+ containerSelector?: string;
36
+ /**
37
+ * Enables client-side hydration (reconciling the prerendered DOM instead of
38
+ * discarding it). Default: `true`. Set to `false` to fall back to a plain
39
+ * client remount over the static HTML — no reconciliation runs at all,
40
+ * client or server, and `render()` in `@praxisjs/runtime` never sees the
41
+ * hydration marker.
42
+ */
43
+ hydrate?: boolean;
44
+ }
45
+ /**
46
+ * Installs the retry hook above for the rest of this process. Idempotent.
47
+ * `ssgPlugin()` calls this itself before dynamically importing
48
+ * `@praxisjs/ssg/prerender` — only needed directly if you're calling
49
+ * `prerender()` from your own Node script instead of going through
50
+ * `ssgPlugin()`, and must run before that import.
51
+ *
52
+ * Prefers `module.registerHooks()` (in-thread, sync, Node 22.15+) and falls
53
+ * back to the older `module.register()` (off-thread, needs its own module
54
+ * file — see loader-hook.ts, the asynchronous twin of `resolveSync` above)
55
+ * on earlier Node versions.
56
+ */
57
+ export declare function registerLoaderHook(): void;
58
+ export declare function ssgPlugin(config: SSGConfig): Plugin;
59
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAgB,KAAK,MAAM,EAAuB,MAAM,MAAM,CAAC;AAEtE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAOtD,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAE7E,MAAM,WAAW,SAAS;IACxB;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,iFAAiF;IACjF,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AA6CD;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CASzC;AAoED,wBAAgB,SAAS,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CA2CnD"}
package/dist/index.js ADDED
@@ -0,0 +1,156 @@
1
+ import { readFile, writeFile, mkdir } from "node:fs/promises";
2
+ import * as nodeModule from "node:module";
3
+ import { dirname, join } from "node:path";
4
+ import { createServer } from "vite";
5
+ // ── extensionless-relative-import retry hook ────────────────────────────────
6
+ //
7
+ // Every other @praxisjs/* package is built with tsc, which emits relative
8
+ // specifiers exactly as written in source ("./router", not "./router.js") —
9
+ // harmless for every consumer so far, since they're all resolved through a
10
+ // bundler (Vite/esbuild/rollup), which resolves extensionless specifiers
11
+ // fine. Node's own ESM resolver does not: it's spec-strict and requires an
12
+ // explicit extension on relative specifiers, and @praxisjs/ssg is the first
13
+ // package here that needs to load that dependency chain (router, core, head,
14
+ // runtime) directly through Node, when `closeBundle` below dynamically
15
+ // imports ./prerender.
16
+ //
17
+ // This lives inline in the package's main entry, with zero relative imports
18
+ // of its own, rather than in a separate module: `registerLoaderHook()` must
19
+ // run *before* anything reachable from this file needs the workaround it
20
+ // installs, and a relative import here would hit the exact problem it's
21
+ // meant to fix before it ever gets the chance to run.
22
+ const RETRYABLE_CODES = new Set(["ERR_MODULE_NOT_FOUND", "ERR_UNSUPPORTED_DIR_IMPORT"]);
23
+ function resolveSync(specifier, context, nextResolve) {
24
+ try {
25
+ return nextResolve(specifier, context);
26
+ }
27
+ catch (err) {
28
+ const code = err.code;
29
+ if ((specifier.startsWith("./") || specifier.startsWith("../")) && code !== undefined && RETRYABLE_CODES.has(code)) {
30
+ for (const candidate of [`${specifier}.js`, `${specifier}/index.js`]) {
31
+ try {
32
+ return nextResolve(candidate, context);
33
+ }
34
+ catch {
35
+ // try the next candidate
36
+ }
37
+ }
38
+ }
39
+ throw err;
40
+ }
41
+ }
42
+ let hookRegistered = false;
43
+ /**
44
+ * Installs the retry hook above for the rest of this process. Idempotent.
45
+ * `ssgPlugin()` calls this itself before dynamically importing
46
+ * `@praxisjs/ssg/prerender` — only needed directly if you're calling
47
+ * `prerender()` from your own Node script instead of going through
48
+ * `ssgPlugin()`, and must run before that import.
49
+ *
50
+ * Prefers `module.registerHooks()` (in-thread, sync, Node 22.15+) and falls
51
+ * back to the older `module.register()` (off-thread, needs its own module
52
+ * file — see loader-hook.ts, the asynchronous twin of `resolveSync` above)
53
+ * on earlier Node versions.
54
+ */
55
+ export function registerLoaderHook() {
56
+ if (hookRegistered)
57
+ return;
58
+ hookRegistered = true;
59
+ if (typeof nodeModule.registerHooks === "function") {
60
+ nodeModule.registerHooks({ resolve: resolveSync });
61
+ }
62
+ else {
63
+ // eslint-disable-next-line @typescript-eslint/no-deprecated -- intentional fallback for Node < 22.15, which has no registerHooks
64
+ nodeModule.register(new URL("./loader-hook.js", import.meta.url));
65
+ }
66
+ }
67
+ async function loadEntry(resolvedConfig, root, withDomGlobals) {
68
+ const server = await createServer({
69
+ configFile: resolvedConfig.configFile,
70
+ root: resolvedConfig.root,
71
+ server: { middlewareMode: true, watch: null },
72
+ appType: "custom",
73
+ // Every @praxisjs/* package (and anything else in node_modules) must
74
+ // resolve through plain Node `import()` here — the same path `prerender()`
75
+ // itself uses to load @praxisjs/core/runtime/router/head — instead of
76
+ // being re-processed through Vite's SSR transform. Two different copies
77
+ // of @praxisjs/core would mean two separate component-instance registries:
78
+ // mountComponent() (from the plain-Node copy prerender.ts imports) would
79
+ // construct instances that @Router([...])'s decorator (baked into the
80
+ // Vite-SSR-transformed copy the root module was loaded with) doesn't
81
+ // recognize as valid components.
82
+ ssr: { external: true },
83
+ // No client ever connects to this server and nothing here benefits from
84
+ // pre-bundling npm deps for browser delivery — and a background
85
+ // (re-)optimization pass restarting mid-request looked like a plausible
86
+ // cause of "transport was disconnected" errors on lazy-loaded routes.
87
+ optimizeDeps: { noDiscovery: true, include: [] },
88
+ });
89
+ try {
90
+ // @Router([...])'s class decorator calls createRouter() at
91
+ // module-evaluation time — ssrLoadModule() below runs that as a side
92
+ // effect of importing the root module, so it needs *a* window in place
93
+ // already, even though nothing is actually being rendered yet (the real,
94
+ // per-route window gets installed later, in prerender()).
95
+ const mod = await withDomGlobals("<!doctype html><html><head></head><body></body></html>", "http://localhost/", async () => {
96
+ return (await server.ssrLoadModule(root));
97
+ });
98
+ if (!mod.default) {
99
+ throw new Error(`[@praxisjs/ssg] "${root}" has no default export — expected the root component.`);
100
+ }
101
+ if (!mod.routes) {
102
+ throw new Error(`[@praxisjs/ssg] "${root}" has no named "routes" export — expected the same route table passed to @Router([...]).`);
103
+ }
104
+ // Left open, closed by the caller after prerender() finishes: routes
105
+ // wrapped in Lazy(() => import(...)) keep their loader closures bound to
106
+ // *this* server's module runner for as long as they might still be
107
+ // invoked — closing it here would break lazy routes on every page after
108
+ // the first that needs them.
109
+ return { root: mod.default, routes: mod.routes, getStaticPaths: mod.getStaticPaths, close: () => server.close() };
110
+ }
111
+ catch (err) {
112
+ await server.close();
113
+ throw err;
114
+ }
115
+ }
116
+ export function ssgPlugin(config) {
117
+ let resolvedConfig;
118
+ // Before anything below ever dynamically imports ./prerender — see the
119
+ // retry-hook section above for why this needs to happen here.
120
+ registerLoaderHook();
121
+ return {
122
+ name: "praxisjs:ssg",
123
+ apply: "build",
124
+ configResolved(c) {
125
+ resolvedConfig = c;
126
+ },
127
+ async closeBundle() {
128
+ const { prerender, withDomGlobals } = (await import("./prerender"));
129
+ const outDir = resolvedConfig.build.outDir;
130
+ const templatePath = join(resolvedConfig.root, outDir, "index.html");
131
+ const template = await readFile(templatePath, "utf-8");
132
+ const { root, routes, getStaticPaths, close } = await loadEntry(resolvedConfig, config.root, withDomGlobals);
133
+ let pages;
134
+ try {
135
+ pages = await prerender({
136
+ root,
137
+ routes,
138
+ routerOptions: config.routerOptions,
139
+ getStaticPaths,
140
+ template,
141
+ containerSelector: config.containerSelector,
142
+ hydrate: config.hydrate,
143
+ });
144
+ }
145
+ finally {
146
+ await close();
147
+ }
148
+ for (const page of pages) {
149
+ const outFile = join(resolvedConfig.root, outDir, page.file);
150
+ await mkdir(dirname(outFile), { recursive: true });
151
+ await writeFile(outFile, page.html, "utf-8");
152
+ }
153
+ },
154
+ };
155
+ }
156
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { ResolveFnOutput, ResolveHookContext } from "node:module";
2
+ type NextResolve = (specifier: string, context?: Partial<ResolveHookContext>) => ResolveFnOutput | Promise<ResolveFnOutput>;
3
+ export declare function resolve(specifier: string, context: ResolveHookContext, nextResolve: NextResolve): Promise<ResolveFnOutput>;
4
+ export {};
5
+ //# sourceMappingURL=loader-hook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader-hook.d.ts","sourceRoot":"","sources":["../src/loader-hook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAiBvE,KAAK,WAAW,GAAG,CACjB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,KAClC,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;AAEhD,wBAAsB,OAAO,CAC3B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,kBAAkB,EAC3B,WAAW,EAAE,WAAW,GACvB,OAAO,CAAC,eAAe,CAAC,CAgB1B"}
@@ -0,0 +1,34 @@
1
+ // Loaded as a standalone hook module via module.register() (see register.ts)
2
+ // — only used as a fallback on Node versions without the newer, in-thread
3
+ // module.registerHooks() API, so it must have zero relative imports of its
4
+ // own: this file needs to work *before* the extensionless-import problem it
5
+ // exists to fix has been worked around. See register.ts for the full story.
6
+ //
7
+ // Every other @praxisjs/* package is built with tsc, which emits relative
8
+ // specifiers exactly as written in source ("./router", not "./router.js") —
9
+ // harmless for every consumer so far, since they're all resolved through a
10
+ // bundler (Vite/esbuild/rollup), which resolves extensionless specifiers
11
+ // fine. Node's own ESM resolver does not: it's spec-strict and requires an
12
+ // explicit extension on relative specifiers. This hook retries with ".js" /
13
+ // "/index.js" on the two failure modes that produces.
14
+ const RETRYABLE_CODES = new Set(["ERR_MODULE_NOT_FOUND", "ERR_UNSUPPORTED_DIR_IMPORT"]);
15
+ export async function resolve(specifier, context, nextResolve) {
16
+ try {
17
+ return await nextResolve(specifier, context);
18
+ }
19
+ catch (err) {
20
+ const code = err.code;
21
+ if ((specifier.startsWith("./") || specifier.startsWith("../")) && code !== undefined && RETRYABLE_CODES.has(code)) {
22
+ for (const candidate of [`${specifier}.js`, `${specifier}/index.js`]) {
23
+ try {
24
+ return await nextResolve(candidate, context);
25
+ }
26
+ catch {
27
+ // try the next candidate
28
+ }
29
+ }
30
+ }
31
+ throw err;
32
+ }
33
+ }
34
+ //# sourceMappingURL=loader-hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader-hook.js","sourceRoot":"","sources":["../src/loader-hook.ts"],"names":[],"mappings":"AAEA,6EAA6E;AAC7E,0EAA0E;AAC1E,2EAA2E;AAC3E,4EAA4E;AAC5E,4EAA4E;AAC5E,EAAE;AACF,0EAA0E;AAC1E,4EAA4E;AAC5E,2EAA2E;AAC3E,yEAAyE;AACzE,2EAA2E;AAC3E,4EAA4E;AAC5E,sDAAsD;AACtD,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,sBAAsB,EAAE,4BAA4B,CAAC,CAAC,CAAC;AAOxF,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,SAAiB,EACjB,OAA2B,EAC3B,WAAwB;IAExB,IAAI,CAAC;QACH,OAAO,MAAM,WAAW,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAC/C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,GAAI,GAAyB,CAAC,IAAI,CAAC;QAC7C,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,IAAI,IAAI,KAAK,SAAS,IAAI,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACnH,KAAK,MAAM,SAAS,IAAI,CAAC,GAAG,SAAS,KAAK,EAAE,GAAG,SAAS,WAAW,CAAC,EAAE,CAAC;gBACrE,IAAI,CAAC;oBACH,OAAO,MAAM,WAAW,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;gBAC/C,CAAC;gBAAC,MAAM,CAAC;oBACP,yBAAyB;gBAC3B,CAAC;YACH,CAAC;QACH,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC"}
@@ -0,0 +1,38 @@
1
+ import { JSDOM } from "jsdom";
2
+ import type { RouterOptions } from "@praxisjs/router";
3
+ import type { ComponentConstructor } from "@praxisjs/shared/internal";
4
+ import { type GetStaticPaths, type RouteEntry } from "./routes";
5
+ export { flattenRoutes, isStaticPath, normalizeRoutes, pathToOutputFile, resolvePaths, type FlattenedRoute, type ResolvePathsConfig } from "./routes";
6
+ export interface PrerenderConfig {
7
+ /** Root component class — same one passed to `@Router([...])`/mounted by `main.tsx`. */
8
+ root: ComponentConstructor;
9
+ /** Same route table passed to `@Router([...])` — a mix of RouteDefinitions and bare @Route-decorated classes is fine, same as the decorator itself accepts. */
10
+ routes: RouteEntry[];
11
+ routerOptions?: RouterOptions;
12
+ /** Global fallback for expanding a dynamic route (`:slug`, `**`) into concrete paths — a route with its own `getStaticPaths` uses that instead. Dynamic routes with neither are skipped. */
13
+ getStaticPaths?: GetStaticPaths;
14
+ /** The built `index.html` content — reused as the template for every page. */
15
+ template: string;
16
+ /** CSS selector for the mount container inside `template`. Default: `#app`. */
17
+ containerSelector?: string;
18
+ /** Whether to mark output HTML for client-side hydration. Default: `true`. When `false`, the client falls back to a full remount instead of reconciling. */
19
+ hydrate?: boolean;
20
+ }
21
+ export interface PrerenderedPage {
22
+ path: string;
23
+ /** Output file path relative to the SSG out dir, e.g. `about/index.html`. */
24
+ file: string;
25
+ html: string;
26
+ }
27
+ export declare function prerender(config: PrerenderConfig): Promise<PrerenderedPage[]>;
28
+ /**
29
+ * Runs `fn` with a fresh JSDOM's `window`/`document`/etc installed as globals
30
+ * for its duration, then restores whatever was there before. Exported so
31
+ * `index.ts`'s `loadEntry()` can use it too: `ssrLoadModule()`-ing the app's
32
+ * root module runs `@Router([...])`'s class decorator, which calls
33
+ * `createRouter()` immediately (at module-evaluation time) — that needs a
34
+ * `window` in place just as much as the real per-route render below does,
35
+ * even though it's not rendering anything itself yet.
36
+ */
37
+ export declare function withDomGlobals<T>(html: string, url: string, fn: (dom: JSDOM) => Promise<T>): Promise<T>;
38
+ //# sourceMappingURL=prerender.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prerender.d.ts","sourceRoot":"","sources":["../src/prerender.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAQ9B,OAAO,KAAK,EAAmB,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGvE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEtE,OAAO,EAAmD,KAAK,cAAc,EAAE,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAMjH,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,YAAY,EAAE,KAAK,cAAc,EAAE,KAAK,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAItJ,MAAM,WAAW,eAAe;IAC9B,wFAAwF;IACxF,IAAI,EAAE,oBAAoB,CAAC;IAC3B,+JAA+J;IAC/J,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,4LAA4L;IAC5L,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,8EAA8E;IAC9E,QAAQ,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,4JAA4J;IAC5J,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,6EAA6E;IAC7E,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,SAAS,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAgBnF;AAoDD;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAQ7G"}
@@ -0,0 +1,116 @@
1
+ import { JSDOM } from "jsdom";
2
+ import { flushPendingResources, isServerRenderPass, setServerRenderPass, } from "@praxisjs/core/internal";
3
+ import { resetHeadState } from "@praxisjs/head/internal";
4
+ import { createRouter } from "@praxisjs/router/internal";
5
+ import { getCurrentScope, mountComponent, render } from "@praxisjs/runtime";
6
+ import { normalizeRoutes, pathToOutputFile, resolvePaths } from "./routes";
7
+ // Re-exported here (this whole file, plus these, only resolves once the
8
+ // loader hook is registered — see register.ts) rather than from the main
9
+ // package entry, so importing `ssgPlugin` alone never needs router/core/head
10
+ // resolved statically. See index.ts.
11
+ export { flattenRoutes, isStaticPath, normalizeRoutes, pathToOutputFile, resolvePaths } from "./routes";
12
+ const SSG_MARKER = "data-praxis-ssg";
13
+ export async function prerender(config) {
14
+ const { getStaticPaths } = config;
15
+ const routes = normalizeRoutes(config.routes);
16
+ const paths = await resolvePaths({ routes, getStaticPaths });
17
+ const wasServerPass = isServerRenderPass();
18
+ setServerRenderPass(true);
19
+ try {
20
+ const pages = [];
21
+ for (const path of paths) {
22
+ pages.push(await renderPage(path, { ...config, routes }));
23
+ }
24
+ return pages;
25
+ }
26
+ finally {
27
+ setServerRenderPass(wasServerPass);
28
+ }
29
+ }
30
+ const PATCHED_GLOBALS = ["window", "document", "navigator", "history", "location", "Node", "Comment", "Text", "Element", "HTMLElement"];
31
+ // Modern Node already defines some of these itself (globalThis.navigator is a
32
+ // getter-only built-in since Node 21) — plain assignment throws on those, so
33
+ // every property is installed *and* restored via defineProperty, capturing
34
+ // the original descriptor (not just its value) to put back exactly what was
35
+ // there, getter and all, rather than flattening it into a plain value.
36
+ function installDomGlobals(dom) {
37
+ const g = globalThis;
38
+ const snapshot = {};
39
+ for (const key of PATCHED_GLOBALS) {
40
+ const descriptor = Object.getOwnPropertyDescriptor(globalThis, key);
41
+ if (descriptor)
42
+ snapshot[key] = descriptor;
43
+ }
44
+ const { window } = dom;
45
+ const values = {
46
+ window,
47
+ document: window.document,
48
+ navigator: window.navigator,
49
+ history: window.history,
50
+ location: window.location,
51
+ Node: window.Node,
52
+ Comment: window.Comment,
53
+ Text: window.Text,
54
+ Element: window.Element,
55
+ HTMLElement: window.HTMLElement,
56
+ };
57
+ for (const key of PATCHED_GLOBALS) {
58
+ Object.defineProperty(g, key, { value: values[key], writable: true, configurable: true, enumerable: true });
59
+ }
60
+ return snapshot;
61
+ }
62
+ function restoreGlobals(snapshot) {
63
+ const g = globalThis;
64
+ for (const key of PATCHED_GLOBALS) {
65
+ const descriptor = snapshot[key];
66
+ if (descriptor) {
67
+ Object.defineProperty(g, key, descriptor);
68
+ }
69
+ else {
70
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete -- removing a global that genuinely didn't exist before installDomGlobals() added it
71
+ delete g[key];
72
+ }
73
+ }
74
+ }
75
+ /**
76
+ * Runs `fn` with a fresh JSDOM's `window`/`document`/etc installed as globals
77
+ * for its duration, then restores whatever was there before. Exported so
78
+ * `index.ts`'s `loadEntry()` can use it too: `ssrLoadModule()`-ing the app's
79
+ * root module runs `@Router([...])`'s class decorator, which calls
80
+ * `createRouter()` immediately (at module-evaluation time) — that needs a
81
+ * `window` in place just as much as the real per-route render below does,
82
+ * even though it's not rendering anything itself yet.
83
+ */
84
+ export async function withDomGlobals(html, url, fn) {
85
+ const dom = new JSDOM(html, { url });
86
+ const snapshot = installDomGlobals(dom);
87
+ try {
88
+ return await fn(dom);
89
+ }
90
+ finally {
91
+ restoreGlobals(snapshot);
92
+ }
93
+ }
94
+ async function renderPage(path, config) {
95
+ const { root, routes, routerOptions, template, hydrate = true } = config;
96
+ const containerSelector = config.containerSelector ?? "#app";
97
+ return withDomGlobals(template, `http://localhost${path}`, async (dom) => {
98
+ resetHeadState();
99
+ const container = dom.window.document.querySelector(containerSelector);
100
+ if (!container) {
101
+ throw new Error(`[@praxisjs/ssg] No element matching "${containerSelector}" found in the HTML template.`);
102
+ }
103
+ createRouter(routes, routerOptions);
104
+ const dispose = render(() => mountComponent(root, {}, getCurrentScope()), container);
105
+ await flushPendingResources();
106
+ await Promise.resolve();
107
+ // Marked *after* rendering — the server always mounts fresh (create-mode);
108
+ // the marker only tells the client to hydrate instead of remounting.
109
+ if (hydrate)
110
+ container.setAttribute(SSG_MARKER, "1");
111
+ const html = dom.serialize();
112
+ dispose();
113
+ return { path, file: pathToOutputFile(path), html };
114
+ });
115
+ }
116
+ //# sourceMappingURL=prerender.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prerender.js","sourceRoot":"","sources":["../src/prerender.ts"],"names":[],"mappings":"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"}