mirror of
https://github.com/cloudflare/vinext.git
synced 2026-09-14 19:04:59 +08:00
bcd4e44d96
* feat(build): support prerender vite config * feat(init): offer prerender config opt-in * fix(cloudflare): export prerender deploy helper * fix(cloudflare): avoid redundant prerender config load * fix(build): quiet adapter fallback warnings
152 lines
5.4 KiB
TypeScript
152 lines
5.4 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, vi } from "vite-plus/test";
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
|
|
const runPrerenderMock = vi.hoisted(() => vi.fn(async () => ({ routes: [] })));
|
|
|
|
vi.mock("vinext/internal/build/run-prerender", () => ({
|
|
runPrerender: runPrerenderMock,
|
|
}));
|
|
|
|
vi.mock("vinext/internal/utils/project", async (importOriginal) => {
|
|
const actual = await importOriginal<typeof import("../packages/vinext/src/utils/project.js")>();
|
|
return {
|
|
...actual,
|
|
getMissingDeps: vi.fn(() => []),
|
|
};
|
|
});
|
|
|
|
vi.mock("node:child_process", async (importOriginal) => {
|
|
const actual = await importOriginal<typeof import("node:child_process")>();
|
|
return {
|
|
...actual,
|
|
execFileSync: vi.fn(() => "Published app\n https://app.example.workers.dev\n"),
|
|
};
|
|
});
|
|
|
|
let tmpDir: string;
|
|
|
|
function writeFile(relativePath: string, content: string): void {
|
|
const fullPath = path.join(tmpDir, relativePath);
|
|
fs.mkdirSync(path.dirname(fullPath), { recursive: true });
|
|
fs.writeFileSync(fullPath, content, "utf-8");
|
|
}
|
|
|
|
function writeProject(prerenderConfig: string): void {
|
|
writeFile("package.json", JSON.stringify({ name: "prerender-config-app", type: "module" }));
|
|
writeFile("app/page.tsx", "export default function Page() { return <div>home</div>; }\n");
|
|
writeFile(
|
|
"node_modules/@cloudflare/vite-plugin/package.json",
|
|
JSON.stringify({ name: "@cloudflare/vite-plugin", type: "module", main: "index.js" }),
|
|
);
|
|
writeFile(
|
|
"node_modules/@cloudflare/vite-plugin/index.js",
|
|
"export function cloudflare() { return { name: 'test-cloudflare-plugin' }; }\n",
|
|
);
|
|
writeFile(
|
|
"wrangler.jsonc",
|
|
'{"main":"vinext/server/app-router-entry","assets":{"directory":"dist/client"}}\n',
|
|
);
|
|
writeFile(
|
|
"vite.config.ts",
|
|
[
|
|
'import { defineConfig } from "vite";',
|
|
'import { cloudflare } from "@cloudflare/vite-plugin";',
|
|
'import vinext from "../packages/vinext/src/index";',
|
|
"",
|
|
"export default defineConfig({",
|
|
` plugins: [vinext({ prerender: ${prerenderConfig} }), cloudflare()],`,
|
|
"});",
|
|
"",
|
|
].join("\n"),
|
|
);
|
|
}
|
|
|
|
function writeProjectWithThrowingViteConfig(): void {
|
|
writeFile("package.json", JSON.stringify({ name: "prerender-config-app", type: "module" }));
|
|
writeFile("app/page.tsx", "export default function Page() { return <div>home</div>; }\n");
|
|
writeFile(
|
|
"node_modules/@cloudflare/vite-plugin/package.json",
|
|
JSON.stringify({ name: "@cloudflare/vite-plugin", type: "module", main: "index.js" }),
|
|
);
|
|
writeFile(
|
|
"node_modules/@cloudflare/vite-plugin/index.js",
|
|
"export function cloudflare() { return { name: 'test-cloudflare-plugin' }; }\n",
|
|
);
|
|
writeFile(
|
|
"wrangler.jsonc",
|
|
'{"main":"vinext/server/app-router-entry","assets":{"directory":"dist/client"}}\n',
|
|
);
|
|
writeFile("throws-on-load.js", 'throw new Error("vite config loaded unexpectedly");\n');
|
|
writeFile(
|
|
"vite.config.ts",
|
|
[
|
|
'import "./throws-on-load.js";',
|
|
'import { cloudflare } from "@cloudflare/vite-plugin";',
|
|
'import vinext from "../packages/vinext/src/index";',
|
|
"",
|
|
"export default {",
|
|
" plugins: [vinext(), cloudflare({ viteEnvironment: { name: 'rsc', childEnvironments: ['ssr'] } })],",
|
|
"};",
|
|
"",
|
|
].join("\n"),
|
|
);
|
|
}
|
|
|
|
describe("deploy prerender config wiring", () => {
|
|
beforeEach(() => {
|
|
tmpDir = fs.mkdtempSync(path.join(process.cwd(), ".tmp-vinext-deploy-prerender-"));
|
|
runPrerenderMock.mockClear();
|
|
});
|
|
|
|
afterEach(() => {
|
|
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
});
|
|
|
|
it("runs prerender during deploy when vinext config uses the true shorthand", async () => {
|
|
writeProject("true");
|
|
const { deploy } = await import("../packages/cloudflare/src/deploy.js");
|
|
|
|
await deploy({ root: tmpDir, skipBuild: true });
|
|
|
|
expect(runPrerenderMock).toHaveBeenCalledWith({ root: tmpDir, concurrency: undefined });
|
|
});
|
|
|
|
it("runs prerender during deploy when vinext config uses routes star", async () => {
|
|
writeProject('{ routes: "*" }');
|
|
const { deploy } = await import("../packages/cloudflare/src/deploy.js");
|
|
|
|
await deploy({ root: tmpDir, skipBuild: true });
|
|
|
|
expect(runPrerenderMock).toHaveBeenCalledWith({ root: tmpDir, concurrency: undefined });
|
|
});
|
|
|
|
it("passes deploy prerender concurrency through config-triggered prerender", async () => {
|
|
writeProject('{ routes: "*" }');
|
|
const { deploy } = await import("../packages/cloudflare/src/deploy.js");
|
|
|
|
await deploy({ root: tmpDir, skipBuild: true, prerenderConcurrency: 3 });
|
|
|
|
expect(runPrerenderMock).toHaveBeenCalledWith({ root: tmpDir, concurrency: 3 });
|
|
});
|
|
|
|
it("does not load Vite config when the prerender-all flag already wins", async () => {
|
|
writeProjectWithThrowingViteConfig();
|
|
const { deploy } = await import("../packages/cloudflare/src/deploy.js");
|
|
|
|
await deploy({ root: tmpDir, skipBuild: true, prerenderAll: true });
|
|
|
|
expect(runPrerenderMock).toHaveBeenCalledWith({ root: tmpDir, concurrency: undefined });
|
|
});
|
|
|
|
it("does not load Vite config when static export already wins", async () => {
|
|
writeProjectWithThrowingViteConfig();
|
|
writeFile("next.config.mjs", 'export default { output: "export" };\n');
|
|
const { deploy } = await import("../packages/cloudflare/src/deploy.js");
|
|
|
|
await deploy({ root: tmpDir, skipBuild: true });
|
|
|
|
expect(runPrerenderMock).toHaveBeenCalledWith({ root: tmpDir, concurrency: undefined });
|
|
});
|
|
});
|