Server Refactor

This commit is contained in:
2026-03-24 07:17:03 +01:00
parent 7dd8d87be8
commit 342f56f3f5
14 changed files with 278 additions and 111 deletions
+37 -15
View File
@@ -1,7 +1,5 @@
import { describe, expect, test, beforeAll, afterAll } from "bun:test";
import startServer from "../../../src/functions/server/start-server";
import rewritePagesModule from "../../../src/utils/rewrite-pages-module";
import pagePathTransform from "../../../src/utils/page-path-transform";
import path from "path";
import fs from "fs";
@@ -10,9 +8,6 @@ const fixtureDir = path.resolve(__dirname, "../../../test/e2e-fixture");
const fixturePagesDir = path.join(fixtureDir, "src", "pages");
const fixtureIndexPage = path.join(fixturePagesDir, "index.tsx");
// The rewritten page path (inside .bunext/pages, stripped of server logic)
const rewrittenIndexPage = pagePathTransform({ page_path: fixtureIndexPage });
let originalCwd = process.cwd();
let originalPort: string | undefined;
@@ -37,10 +32,6 @@ describe("E2E Integration", () => {
dir: fixturePagesDir,
});
// Rewrite the fixture page (strips server logic) into .bunext/pages
// so that grab-page-react-component-string can resolve the import
await rewritePagesModule({ page_file_path: fixtureIndexPage });
// Pre-populate the bundler context map so grab-page-component can
// look up the compiled path. The `path` value only needs to be
// present for the guard check; SSR does not require the file to exist.
@@ -70,12 +61,6 @@ describe("E2E Integration", () => {
delete process.env.PORT;
}
// Remove the rewritten page created during setup
const rewrittenDir = path.dirname(rewrittenIndexPage);
if (fs.existsSync(rewrittenDir)) {
fs.rmSync(rewrittenDir, { recursive: true, force: true });
}
// Remove any generated .bunext artifacts from the fixture
const dotBunext = path.join(fixtureDir, ".bunext");
if (fs.existsSync(dotBunext)) {
@@ -102,4 +87,41 @@ describe("E2E Integration", () => {
// Default 404 component is rendered
expect(text).toContain("404");
});
test("server props injected from .server.ts companion file", async () => {
const serverFilePath = path.join(fixturePagesDir, "index.server.ts");
const pageFilePath = fixtureIndexPage;
// Write a temporary .server.ts companion that injects a prop
await Bun.write(serverFilePath, `
import type { BunextPageServerFn } from "../../../../../src/types";
const server: BunextPageServerFn<{ greeting: string }> = async () => {
return { props: { greeting: "Hello from server" } };
};
export default server;
`);
// Add the fixture page to the BUNDLER_CTX_MAP
global.BUNDLER_CTX_MAP[pageFilePath] = {
path: ".bunext/public/pages/index.js",
hash: "index",
type: "text/javascript",
entrypoint: pageFilePath,
local_path: pageFilePath,
url_path: "/",
file_name: "index",
};
const response = await fetch(`http://localhost:${server.port}/`);
expect(response.status).toBe(200);
const html = await response.text();
// __PAGE_PROPS__ should include the prop from the server companion
expect(html).toContain("Hello from server");
// Clean up
fs.unlinkSync(serverFilePath);
});
});
@@ -0,0 +1,69 @@
import { describe, it, expect, beforeAll, afterAll } from "bun:test";
import path from "path";
import fs from "fs";
import grabPageServerPath from "../../../../src/functions/server/web-pages/grab-page-server-path";
const tmpDir = path.join(import.meta.dir, "__tmp_server_path__");
beforeAll(() => {
fs.mkdirSync(tmpDir, { recursive: true });
});
afterAll(() => {
fs.rmSync(tmpDir, { recursive: true, force: true });
});
describe("grabPageServerPath", () => {
it("returns undefined when no companion file exists", () => {
const { server_file_path } = grabPageServerPath({
file_path: path.join(tmpDir, "index.tsx"),
});
expect(server_file_path).toBeUndefined();
});
it("resolves .server.ts companion for a .tsx page", () => {
const serverFile = path.join(tmpDir, "profile.server.ts");
fs.writeFileSync(serverFile, "export default async () => ({})");
const { server_file_path } = grabPageServerPath({
file_path: path.join(tmpDir, "profile.tsx"),
});
expect(server_file_path).toBe(serverFile);
});
it("resolves .server.tsx companion when only .server.tsx exists", () => {
const serverFile = path.join(tmpDir, "about.server.tsx");
fs.writeFileSync(serverFile, "export default async () => ({})");
const { server_file_path } = grabPageServerPath({
file_path: path.join(tmpDir, "about.tsx"),
});
expect(server_file_path).toBe(serverFile);
});
it("prefers .server.ts over .server.tsx when both exist", () => {
const tsFile = path.join(tmpDir, "blog.server.ts");
const tsxFile = path.join(tmpDir, "blog.server.tsx");
fs.writeFileSync(tsFile, "export default async () => ({})");
fs.writeFileSync(tsxFile, "export default async () => ({})");
const { server_file_path } = grabPageServerPath({
file_path: path.join(tmpDir, "blog.tsx"),
});
expect(server_file_path).toBe(tsFile);
});
it("resolves companion for a .ts page file", () => {
const serverFile = path.join(tmpDir, "api-page.server.ts");
fs.writeFileSync(serverFile, "export default async () => ({})");
const { server_file_path } = grabPageServerPath({
file_path: path.join(tmpDir, "api-page.ts"),
});
expect(server_file_path).toBe(serverFile);
});
});