@praxisjs/ssg 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +39 -15
- package/dist/index.js.map +1 -1
- package/dist/loader-hook.d.ts.map +1 -1
- package/dist/loader-hook.js +3 -13
- package/dist/loader-hook.js.map +1 -1
- package/dist/prerender.d.ts +10 -7
- package/dist/prerender.d.ts.map +1 -1
- package/dist/prerender.js +80 -63
- package/dist/prerender.js.map +1 -1
- package/package.json +16 -8
- package/src/index.ts +42 -16
- package/src/loader-hook.ts +3 -13
- package/src/prerender.ts +95 -80
- package/dist/__tests__/loader-hook.test.d.ts +0 -2
- package/dist/__tests__/loader-hook.test.d.ts.map +0 -1
- package/dist/__tests__/loader-hook.test.js +0 -66
- package/dist/__tests__/loader-hook.test.js.map +0 -1
- package/dist/__tests__/plugin.test.d.ts +0 -2
- package/dist/__tests__/plugin.test.d.ts.map +0 -1
- package/dist/__tests__/plugin.test.js +0 -128
- package/dist/__tests__/plugin.test.js.map +0 -1
- package/dist/__tests__/prerender.test.d.ts +0 -2
- package/dist/__tests__/prerender.test.d.ts.map +0 -1
- package/dist/__tests__/prerender.test.js +0 -211
- package/dist/__tests__/prerender.test.js.map +0 -1
- package/dist/__tests__/register-fallback.test.d.ts +0 -2
- package/dist/__tests__/register-fallback.test.d.ts.map +0 -1
- package/dist/__tests__/register-fallback.test.js +0 -20
- package/dist/__tests__/register-fallback.test.js.map +0 -1
- package/dist/__tests__/resolve-sync.test.d.ts +0 -2
- package/dist/__tests__/resolve-sync.test.d.ts.map +0 -1
- package/dist/__tests__/resolve-sync.test.js +0 -67
- package/dist/__tests__/resolve-sync.test.js.map +0 -1
- package/dist/__tests__/routes.test.d.ts +0 -2
- package/dist/__tests__/routes.test.d.ts.map +0 -1
- package/dist/__tests__/routes.test.js +0 -154
- package/dist/__tests__/routes.test.js.map +0 -1
- package/src/__tests__/loader-hook.test.ts +0 -76
- package/src/__tests__/plugin.test.ts +0 -161
- package/src/__tests__/prerender.test.ts +0 -181
- package/src/__tests__/register-fallback.test.ts +0 -23
- package/src/__tests__/resolve-sync.test.ts +0 -91
- package/src/__tests__/routes.test.ts +0 -175
- package/tsconfig.json +0 -11
package/src/prerender.ts
CHANGED
|
@@ -13,13 +13,13 @@ import type { ComponentConstructor } from "@praxisjs/shared/internal";
|
|
|
13
13
|
|
|
14
14
|
import { normalizeRoutes, pathToOutputFile, resolvePaths, type GetStaticPaths, type RouteEntry } from "./routes";
|
|
15
15
|
|
|
16
|
-
// Re-exported here
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
// resolved statically. See index.ts.
|
|
16
|
+
// Re-exported here rather than from the main entry so importing `ssgPlugin` alone never needs
|
|
17
|
+
// router/core/head resolved statically: this module only loads once the loader hook in index.ts is
|
|
18
|
+
// registered.
|
|
20
19
|
export { flattenRoutes, isStaticPath, normalizeRoutes, pathToOutputFile, resolvePaths, type FlattenedRoute, type ResolvePathsConfig } from "./routes";
|
|
21
20
|
|
|
22
21
|
const SSG_MARKER = "data-praxis-ssg";
|
|
22
|
+
const ORIGIN = "http://localhost";
|
|
23
23
|
|
|
24
24
|
export interface PrerenderConfig {
|
|
25
25
|
/** Root component class — same one passed to `@Router([...])`/mounted by `main.tsx`. */
|
|
@@ -44,58 +44,111 @@ export interface PrerenderedPage {
|
|
|
44
44
|
html: string;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
interface RenderOptions {
|
|
48
|
+
root: ComponentConstructor;
|
|
49
|
+
routes: RouteDefinition[];
|
|
50
|
+
routerOptions: RouterOptions | undefined;
|
|
51
|
+
containerSelector: string;
|
|
52
|
+
hydrate: boolean;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Renders every route into a full HTML page. One JSDOM window serves the whole run (parsing a new
|
|
57
|
+
* one per route cost more than most renders) and is reset before each route: a fresh copy of the
|
|
58
|
+
* template's document, the route's URL, empty storage and none of the window globals the previous
|
|
59
|
+
* route added. The window is closed at the end, which also stops any timer a page left running.
|
|
60
|
+
*/
|
|
47
61
|
export async function prerender(config: PrerenderConfig): Promise<PrerenderedPage[]> {
|
|
48
|
-
const { getStaticPaths } = config;
|
|
49
62
|
const routes = normalizeRoutes(config.routes);
|
|
50
|
-
const paths = await resolvePaths({ routes, getStaticPaths });
|
|
63
|
+
const paths = await resolvePaths({ routes, getStaticPaths: config.getStaticPaths });
|
|
64
|
+
const options: RenderOptions = {
|
|
65
|
+
root: config.root,
|
|
66
|
+
routes,
|
|
67
|
+
routerOptions: config.routerOptions,
|
|
68
|
+
containerSelector: config.containerSelector ?? "#app",
|
|
69
|
+
hydrate: config.hydrate ?? true,
|
|
70
|
+
};
|
|
51
71
|
|
|
52
72
|
const wasServerPass = isServerRenderPass();
|
|
53
73
|
setServerRenderPass(true);
|
|
54
74
|
try {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
75
|
+
return await withDomGlobals(config.template, `${ORIGIN}/`, async (dom) => {
|
|
76
|
+
const { window } = dom;
|
|
77
|
+
const pristine = window.document.documentElement.cloneNode(true);
|
|
78
|
+
const baseline = new Set(Object.getOwnPropertyNames(window));
|
|
79
|
+
|
|
80
|
+
const pages: PrerenderedPage[] = [];
|
|
81
|
+
for (const path of paths) {
|
|
82
|
+
resetWindow(dom, pristine, baseline, path);
|
|
83
|
+
pages.push(await renderPage(dom, path, options));
|
|
84
|
+
}
|
|
85
|
+
return pages;
|
|
86
|
+
});
|
|
60
87
|
} finally {
|
|
61
88
|
setServerRenderPass(wasServerPass);
|
|
62
89
|
}
|
|
63
90
|
}
|
|
64
91
|
|
|
65
|
-
|
|
92
|
+
function resetWindow(dom: JSDOM, pristine: Node, baseline: Set<string>, path: string): void {
|
|
93
|
+
const { window } = dom;
|
|
94
|
+
const { document } = window;
|
|
95
|
+
document.replaceChild(pristine.cloneNode(true), document.documentElement);
|
|
96
|
+
window.history.replaceState(null, "", `${ORIGIN}${path}`);
|
|
97
|
+
window.localStorage.clear();
|
|
98
|
+
window.sessionStorage.clear();
|
|
99
|
+
const globals = window as unknown as Record<string, unknown>;
|
|
100
|
+
for (const key of Object.getOwnPropertyNames(window)) {
|
|
101
|
+
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete -- removing globals the previous route's code added
|
|
102
|
+
if (!baseline.has(key)) delete globals[key];
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function renderPage(dom: JSDOM, path: string, options: RenderOptions): Promise<PrerenderedPage> {
|
|
107
|
+
const { root, routes, routerOptions, containerSelector, hydrate } = options;
|
|
108
|
+
resetHeadState();
|
|
109
|
+
|
|
110
|
+
const container = dom.window.document.querySelector<HTMLElement>(containerSelector);
|
|
111
|
+
if (!container) {
|
|
112
|
+
throw new Error(`[@praxisjs/ssg] No element matching "${containerSelector}" found in the HTML template.`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
createRouter(routes, routerOptions);
|
|
116
|
+
|
|
117
|
+
const dispose = render(() => mountComponent(root, {}, getCurrentScope()), container);
|
|
118
|
+
try {
|
|
119
|
+
await flushPendingResources();
|
|
120
|
+
await Promise.resolve();
|
|
121
|
+
|
|
122
|
+
// The server always mounts fresh; the marker only tells the client to hydrate instead of remounting.
|
|
123
|
+
if (hydrate) container.setAttribute(SSG_MARKER, "1");
|
|
124
|
+
|
|
125
|
+
return { path, file: pathToOutputFile(path), html: dom.serialize() };
|
|
126
|
+
} finally {
|
|
127
|
+
dispose();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
66
130
|
|
|
67
|
-
|
|
131
|
+
const PATCHED_GLOBALS = [
|
|
132
|
+
"window", "document", "navigator", "history", "location", "localStorage", "sessionStorage",
|
|
133
|
+
"Node", "Comment", "Text", "Element", "HTMLElement",
|
|
134
|
+
] as const;
|
|
68
135
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
//
|
|
73
|
-
//
|
|
136
|
+
type PatchedGlobal = (typeof PATCHED_GLOBALS)[number];
|
|
137
|
+
type GlobalSnapshot = Partial<Record<PatchedGlobal, PropertyDescriptor>>;
|
|
138
|
+
|
|
139
|
+
// Modern Node defines some of these itself (globalThis.navigator is a getter-only built-in since
|
|
140
|
+
// Node 21), where plain assignment throws. Every property is installed and restored through
|
|
141
|
+
// defineProperty, keeping the original descriptor so a getter comes back as a getter.
|
|
74
142
|
function installDomGlobals(dom: JSDOM): GlobalSnapshot {
|
|
75
|
-
const g = globalThis as unknown as Record<string, unknown>;
|
|
76
143
|
const snapshot: GlobalSnapshot = {};
|
|
144
|
+
const { window } = dom;
|
|
145
|
+
const source = window as unknown as Record<PatchedGlobal, unknown>;
|
|
77
146
|
for (const key of PATCHED_GLOBALS) {
|
|
78
147
|
const descriptor = Object.getOwnPropertyDescriptor(globalThis, key);
|
|
79
148
|
if (descriptor) snapshot[key] = descriptor;
|
|
149
|
+
const value = key === "window" ? window : source[key];
|
|
150
|
+
Object.defineProperty(globalThis, key, { value, writable: true, configurable: true, enumerable: true });
|
|
80
151
|
}
|
|
81
|
-
|
|
82
|
-
const { window } = dom;
|
|
83
|
-
const values: Record<(typeof PATCHED_GLOBALS)[number], unknown> = {
|
|
84
|
-
window,
|
|
85
|
-
document: window.document,
|
|
86
|
-
navigator: window.navigator,
|
|
87
|
-
history: window.history,
|
|
88
|
-
location: window.location,
|
|
89
|
-
Node: window.Node,
|
|
90
|
-
Comment: window.Comment,
|
|
91
|
-
Text: window.Text,
|
|
92
|
-
Element: window.Element,
|
|
93
|
-
HTMLElement: window.HTMLElement,
|
|
94
|
-
};
|
|
95
|
-
for (const key of PATCHED_GLOBALS) {
|
|
96
|
-
Object.defineProperty(g, key, { value: values[key], writable: true, configurable: true, enumerable: true });
|
|
97
|
-
}
|
|
98
|
-
|
|
99
152
|
return snapshot;
|
|
100
153
|
}
|
|
101
154
|
|
|
@@ -113,13 +166,10 @@ function restoreGlobals(snapshot: GlobalSnapshot): void {
|
|
|
113
166
|
}
|
|
114
167
|
|
|
115
168
|
/**
|
|
116
|
-
* Runs `fn` with a fresh JSDOM's `window`/`document`/etc installed as globals
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
* `createRouter()` immediately (at module-evaluation time) — that needs a
|
|
121
|
-
* `window` in place just as much as the real per-route render below does,
|
|
122
|
-
* even though it's not rendering anything itself yet.
|
|
169
|
+
* Runs `fn` with a fresh JSDOM's `window`/`document`/etc installed as globals, then restores what
|
|
170
|
+
* was there before and closes the window. Also used by index.ts's `loadEntry()`: loading the root
|
|
171
|
+
* module runs `@Router([...])`, which calls `createRouter()` at module-evaluation time and so needs
|
|
172
|
+
* a `window` even though nothing is rendered yet.
|
|
123
173
|
*/
|
|
124
174
|
export async function withDomGlobals<T>(html: string, url: string, fn: (dom: JSDOM) => Promise<T>): Promise<T> {
|
|
125
175
|
const dom = new JSDOM(html, { url });
|
|
@@ -128,41 +178,6 @@ export async function withDomGlobals<T>(html: string, url: string, fn: (dom: JSD
|
|
|
128
178
|
return await fn(dom);
|
|
129
179
|
} finally {
|
|
130
180
|
restoreGlobals(snapshot);
|
|
181
|
+
dom.window.close();
|
|
131
182
|
}
|
|
132
183
|
}
|
|
133
|
-
|
|
134
|
-
async function renderPage(
|
|
135
|
-
path: string,
|
|
136
|
-
config: Omit<PrerenderConfig, "routes"> & { routes: RouteDefinition[] },
|
|
137
|
-
): Promise<PrerenderedPage> {
|
|
138
|
-
const { root, routes, routerOptions, template, hydrate = true } = config;
|
|
139
|
-
const containerSelector = config.containerSelector ?? "#app";
|
|
140
|
-
|
|
141
|
-
return withDomGlobals(template, `http://localhost${path}`, async (dom) => {
|
|
142
|
-
resetHeadState();
|
|
143
|
-
|
|
144
|
-
const container = dom.window.document.querySelector(containerSelector);
|
|
145
|
-
if (!container) {
|
|
146
|
-
throw new Error(`[@praxisjs/ssg] No element matching "${containerSelector}" found in the HTML template.`);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
createRouter(routes, routerOptions);
|
|
150
|
-
|
|
151
|
-
const dispose = render(
|
|
152
|
-
() => mountComponent(root, {}, getCurrentScope()),
|
|
153
|
-
container as HTMLElement,
|
|
154
|
-
);
|
|
155
|
-
|
|
156
|
-
await flushPendingResources();
|
|
157
|
-
await Promise.resolve();
|
|
158
|
-
|
|
159
|
-
// Marked *after* rendering — the server always mounts fresh (create-mode);
|
|
160
|
-
// the marker only tells the client to hydrate instead of remounting.
|
|
161
|
-
if (hydrate) container.setAttribute(SSG_MARKER, "1");
|
|
162
|
-
|
|
163
|
-
const html = dom.serialize();
|
|
164
|
-
dispose();
|
|
165
|
-
|
|
166
|
-
return { path, file: pathToOutputFile(path), html };
|
|
167
|
-
});
|
|
168
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"loader-hook.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/loader-hook.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from "vitest";
|
|
2
|
-
import { resolve } from "../loader-hook";
|
|
3
|
-
const CONTEXT = {};
|
|
4
|
-
function notFound() {
|
|
5
|
-
const err = new Error("not found");
|
|
6
|
-
err.code = "ERR_MODULE_NOT_FOUND";
|
|
7
|
-
throw err;
|
|
8
|
-
}
|
|
9
|
-
function ok(url) {
|
|
10
|
-
return { url, shortCircuit: true };
|
|
11
|
-
}
|
|
12
|
-
describe("loader-hook resolve()", () => {
|
|
13
|
-
it("returns nextResolve's result directly when it succeeds", async () => {
|
|
14
|
-
const nextResolve = vi.fn(async () => ok("file:///real.js"));
|
|
15
|
-
const result = await resolve("./real", CONTEXT, nextResolve);
|
|
16
|
-
expect(result).toEqual(ok("file:///real.js"));
|
|
17
|
-
expect(nextResolve).toHaveBeenCalledOnce();
|
|
18
|
-
});
|
|
19
|
-
it("rethrows without retrying for a bare (non-relative) specifier", async () => {
|
|
20
|
-
const nextResolve = vi.fn(async () => notFound());
|
|
21
|
-
await expect(resolve("some-package", CONTEXT, nextResolve)).rejects.toThrow("not found");
|
|
22
|
-
expect(nextResolve).toHaveBeenCalledOnce();
|
|
23
|
-
});
|
|
24
|
-
it("rethrows without retrying when the error has no code", async () => {
|
|
25
|
-
const nextResolve = vi.fn(async () => {
|
|
26
|
-
throw new Error("weird failure");
|
|
27
|
-
});
|
|
28
|
-
await expect(resolve("./router", CONTEXT, nextResolve)).rejects.toThrow("weird failure");
|
|
29
|
-
expect(nextResolve).toHaveBeenCalledOnce();
|
|
30
|
-
});
|
|
31
|
-
it("rethrows without retrying for a non-retryable error code", async () => {
|
|
32
|
-
const nextResolve = vi.fn(async () => {
|
|
33
|
-
const err = new Error("permission denied");
|
|
34
|
-
err.code = "EACCES";
|
|
35
|
-
throw err;
|
|
36
|
-
});
|
|
37
|
-
await expect(resolve("./router", CONTEXT, nextResolve)).rejects.toThrow("permission denied");
|
|
38
|
-
expect(nextResolve).toHaveBeenCalledOnce();
|
|
39
|
-
});
|
|
40
|
-
it("retries with a .js suffix and returns it when that succeeds", async () => {
|
|
41
|
-
const nextResolve = vi.fn(async (specifier) => {
|
|
42
|
-
if (specifier === "./router.js")
|
|
43
|
-
return ok("file:///router.js");
|
|
44
|
-
return notFound();
|
|
45
|
-
});
|
|
46
|
-
const result = await resolve("./router", CONTEXT, nextResolve);
|
|
47
|
-
expect(result).toEqual(ok("file:///router.js"));
|
|
48
|
-
expect(nextResolve).toHaveBeenCalledTimes(2);
|
|
49
|
-
});
|
|
50
|
-
it("falls back to /index.js when the .js candidate also fails", async () => {
|
|
51
|
-
const nextResolve = vi.fn(async (specifier) => {
|
|
52
|
-
if (specifier === "./router/index.js")
|
|
53
|
-
return ok("file:///router/index.js");
|
|
54
|
-
return notFound();
|
|
55
|
-
});
|
|
56
|
-
const result = await resolve("./router", CONTEXT, nextResolve);
|
|
57
|
-
expect(result).toEqual(ok("file:///router/index.js"));
|
|
58
|
-
expect(nextResolve).toHaveBeenCalledTimes(3);
|
|
59
|
-
});
|
|
60
|
-
it("rethrows the original error when both retry candidates fail", async () => {
|
|
61
|
-
const nextResolve = vi.fn(async () => notFound());
|
|
62
|
-
await expect(resolve("../router", CONTEXT, nextResolve)).rejects.toThrow("not found");
|
|
63
|
-
expect(nextResolve).toHaveBeenCalledTimes(3);
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
//# sourceMappingURL=loader-hook.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"loader-hook.test.js","sourceRoot":"","sources":["../../src/__tests__/loader-hook.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/plugin.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import { mkdtemp, readFile, rm, writeFile, mkdir } from "node:fs/promises";
|
|
2
|
-
import { tmpdir } from "node:os";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
import { describe, it, expect, vi, afterEach } from "vitest";
|
|
5
|
-
import { prerender } from "../prerender";
|
|
6
|
-
import { ssgPlugin } from "../index";
|
|
7
|
-
vi.mock("../prerender", () => ({
|
|
8
|
-
prerender: vi.fn(),
|
|
9
|
-
// Pass-through stand-in — the real DOM-global install/restore mechanics
|
|
10
|
-
// are covered in prerender.test.ts; here we only need loadEntry() to call
|
|
11
|
-
// through to whatever function it wraps.
|
|
12
|
-
withDomGlobals: vi.fn((_html, _url, fn) => fn()),
|
|
13
|
-
}));
|
|
14
|
-
const ssrLoadModule = vi.fn();
|
|
15
|
-
const close = vi.fn();
|
|
16
|
-
const createServer = vi.fn(async (_options) => ({ ssrLoadModule, close }));
|
|
17
|
-
vi.mock("vite", () => ({
|
|
18
|
-
createServer: (options) => createServer(options),
|
|
19
|
-
}));
|
|
20
|
-
// registerLoaderHook()'s fallback path (module.register with a file URL)
|
|
21
|
-
// assumes a built dist/ layout — loader-hook.js physically next to index.js
|
|
22
|
-
// — which doesn't exist under vitest's on-the-fly source transform. The
|
|
23
|
-
// mechanism itself is covered separately by running the actual built dist/
|
|
24
|
-
// output through Node directly (see the plan's manual verification step);
|
|
25
|
-
// here we only need to confirm ssgPlugin() triggers registration.
|
|
26
|
-
const { registerHooks, register } = vi.hoisted(() => ({
|
|
27
|
-
registerHooks: vi.fn(),
|
|
28
|
-
register: vi.fn(),
|
|
29
|
-
}));
|
|
30
|
-
vi.mock("node:module", async (importOriginal) => {
|
|
31
|
-
const actual = await importOriginal();
|
|
32
|
-
return { ...actual, registerHooks, register };
|
|
33
|
-
});
|
|
34
|
-
const RootComponent = class {
|
|
35
|
-
};
|
|
36
|
-
const routes = [{ path: "/", component: RootComponent }];
|
|
37
|
-
function fakeResolvedConfig(root, outDir = "dist") {
|
|
38
|
-
return {
|
|
39
|
-
root,
|
|
40
|
-
build: { outDir },
|
|
41
|
-
configFile: `${root}/vite.config.ts`,
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
describe("ssgPlugin()", () => {
|
|
45
|
-
let dir;
|
|
46
|
-
afterEach(async () => {
|
|
47
|
-
vi.clearAllMocks();
|
|
48
|
-
if (dir)
|
|
49
|
-
await rm(dir, { recursive: true, force: true });
|
|
50
|
-
});
|
|
51
|
-
it("loads the root component and routes from a single SSR module load, prerenders, and writes files", async () => {
|
|
52
|
-
dir = await mkdtemp(join(tmpdir(), "praxisjs-ssg-"));
|
|
53
|
-
await mkdir(join(dir, "dist"), { recursive: true });
|
|
54
|
-
await writeFile(join(dir, "dist", "index.html"), "<html><body><div id=\"app\"></div></body></html>");
|
|
55
|
-
ssrLoadModule.mockResolvedValue({ default: RootComponent, routes });
|
|
56
|
-
vi.mocked(prerender).mockResolvedValue([
|
|
57
|
-
{ path: "/", file: "index.html", html: "<html>home</html>" },
|
|
58
|
-
{ path: "/about", file: "about/index.html", html: "<html>about</html>" },
|
|
59
|
-
]);
|
|
60
|
-
const plugin = ssgPlugin({ root: "./src/app.tsx" });
|
|
61
|
-
// ssgPlugin() must register the extensionless-import retry hook
|
|
62
|
-
// synchronously, before closeBundle ever dynamically imports
|
|
63
|
-
// ./prerender (which is what actually needs it) — see index.ts.
|
|
64
|
-
expect(registerHooks.mock.calls.length + register.mock.calls.length).toBeGreaterThan(0);
|
|
65
|
-
const configResolved = plugin.configResolved;
|
|
66
|
-
await configResolved(fakeResolvedConfig(dir));
|
|
67
|
-
const closeBundle = plugin.closeBundle;
|
|
68
|
-
await closeBundle();
|
|
69
|
-
expect(createServer).toHaveBeenCalledWith(expect.objectContaining({
|
|
70
|
-
root: dir,
|
|
71
|
-
configFile: `${dir}/vite.config.ts`,
|
|
72
|
-
server: { middlewareMode: true, watch: null },
|
|
73
|
-
appType: "custom",
|
|
74
|
-
ssr: { external: true },
|
|
75
|
-
optimizeDeps: { noDiscovery: true, include: [] },
|
|
76
|
-
}));
|
|
77
|
-
// A single ssrLoadModule call reads both the default export and the
|
|
78
|
-
// named `routes` export — vite.config.ts never imports app source itself.
|
|
79
|
-
expect(ssrLoadModule).toHaveBeenCalledOnce();
|
|
80
|
-
expect(ssrLoadModule).toHaveBeenCalledWith("./src/app.tsx");
|
|
81
|
-
expect(close).toHaveBeenCalledOnce();
|
|
82
|
-
expect(prerender).toHaveBeenCalledWith(expect.objectContaining({
|
|
83
|
-
root: RootComponent,
|
|
84
|
-
routes,
|
|
85
|
-
template: "<html><body><div id=\"app\"></div></body></html>",
|
|
86
|
-
}));
|
|
87
|
-
expect(await readFile(join(dir, "dist", "index.html"), "utf-8")).toBe("<html>home</html>");
|
|
88
|
-
expect(await readFile(join(dir, "dist", "about", "index.html"), "utf-8")).toBe("<html>about</html>");
|
|
89
|
-
});
|
|
90
|
-
it("throws a clear error when the root module has no default export", async () => {
|
|
91
|
-
dir = await mkdtemp(join(tmpdir(), "praxisjs-ssg-"));
|
|
92
|
-
await mkdir(join(dir, "dist"), { recursive: true });
|
|
93
|
-
await writeFile(join(dir, "dist", "index.html"), "<html><body><div id=\"app\"></div></body></html>");
|
|
94
|
-
ssrLoadModule.mockResolvedValue({ routes });
|
|
95
|
-
const plugin = ssgPlugin({ root: "./src/app.tsx" });
|
|
96
|
-
const configResolved = plugin.configResolved;
|
|
97
|
-
await configResolved(fakeResolvedConfig(dir));
|
|
98
|
-
const closeBundle = plugin.closeBundle;
|
|
99
|
-
await expect(closeBundle()).rejects.toThrow(/no default export/);
|
|
100
|
-
expect(close).toHaveBeenCalledOnce(); // server is closed even on failure
|
|
101
|
-
});
|
|
102
|
-
it("throws a clear error when the root module has no named routes export", async () => {
|
|
103
|
-
dir = await mkdtemp(join(tmpdir(), "praxisjs-ssg-"));
|
|
104
|
-
await mkdir(join(dir, "dist"), { recursive: true });
|
|
105
|
-
await writeFile(join(dir, "dist", "index.html"), "<html><body><div id=\"app\"></div></body></html>");
|
|
106
|
-
ssrLoadModule.mockResolvedValue({ default: RootComponent });
|
|
107
|
-
const plugin = ssgPlugin({ root: "./src/app.tsx" });
|
|
108
|
-
const configResolved = plugin.configResolved;
|
|
109
|
-
await configResolved(fakeResolvedConfig(dir));
|
|
110
|
-
const closeBundle = plugin.closeBundle;
|
|
111
|
-
await expect(closeBundle()).rejects.toThrow(/no named "routes" export/);
|
|
112
|
-
expect(close).toHaveBeenCalledOnce();
|
|
113
|
-
});
|
|
114
|
-
it("passes hydrate: false through to prerender()", async () => {
|
|
115
|
-
dir = await mkdtemp(join(tmpdir(), "praxisjs-ssg-"));
|
|
116
|
-
await mkdir(join(dir, "dist"), { recursive: true });
|
|
117
|
-
await writeFile(join(dir, "dist", "index.html"), "<html><body><div id=\"app\"></div></body></html>");
|
|
118
|
-
ssrLoadModule.mockResolvedValue({ default: RootComponent, routes });
|
|
119
|
-
vi.mocked(prerender).mockResolvedValue([{ path: "/", file: "index.html", html: "<html></html>" }]);
|
|
120
|
-
const plugin = ssgPlugin({ root: "./src/app.tsx", hydrate: false });
|
|
121
|
-
const configResolved = plugin.configResolved;
|
|
122
|
-
await configResolved(fakeResolvedConfig(dir));
|
|
123
|
-
const closeBundle = plugin.closeBundle;
|
|
124
|
-
await closeBundle();
|
|
125
|
-
expect(prerender).toHaveBeenCalledWith(expect.objectContaining({ hydrate: false }));
|
|
126
|
-
});
|
|
127
|
-
});
|
|
128
|
-
//# sourceMappingURL=plugin.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.test.js","sourceRoot":"","sources":["../../src/__tests__/plugin.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prerender.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/prerender.test.ts"],"names":[],"mappings":""}
|