Updates
This commit is contained in:
@@ -1,21 +1,60 @@
|
||||
import { describe, expect, test, beforeAll, afterAll } from "bun:test";
|
||||
import startServer from "../../../src/functions/server/start-server";
|
||||
import bunextInit from "../../../src/functions/bunext-init";
|
||||
import rewritePagesModule from "../../../src/utils/rewrite-pages-module";
|
||||
import pagePathTransform from "../../../src/utils/page-path-transform";
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
|
||||
// Fixture lives under test/ so the framework's directory guard allows it
|
||||
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;
|
||||
|
||||
describe("E2E Integration", () => {
|
||||
let server: any;
|
||||
|
||||
|
||||
beforeAll(async () => {
|
||||
// Change to the fixture directory to simulate actual user repo
|
||||
const fixtureDir = path.resolve(__dirname, "../__fixtures__/app");
|
||||
originalPort = process.env.PORT;
|
||||
// Use port 0 so Bun.serve picks a random available port
|
||||
process.env.PORT = "0";
|
||||
|
||||
process.chdir(fixtureDir);
|
||||
|
||||
// Mock grabAppPort to assign dynamically to avoid port conflicts
|
||||
|
||||
global.CONFIG = { development: true };
|
||||
global.HMR_CONTROLLERS = [];
|
||||
global.BUNDLER_REBUILDS = 0;
|
||||
global.PAGE_FILES = [];
|
||||
|
||||
// Set up router pointing at the fixture's pages directory
|
||||
global.ROUTER = new Bun.FileSystemRouter({
|
||||
style: "nextjs",
|
||||
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.
|
||||
global.BUNDLER_CTX_MAP = {
|
||||
[fixtureIndexPage]: {
|
||||
path: ".bunext/public/pages/index.js",
|
||||
hash: "index",
|
||||
type: "text/javascript",
|
||||
entrypoint: fixtureIndexPage,
|
||||
local_path: fixtureIndexPage,
|
||||
url_path: "/",
|
||||
file_name: "index",
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
@@ -23,32 +62,35 @@ describe("E2E Integration", () => {
|
||||
server.stop(true);
|
||||
}
|
||||
process.chdir(originalCwd);
|
||||
|
||||
// Ensure to remove the dummy generated .bunext folder
|
||||
const dotBunext = path.resolve(__dirname, "../__fixtures__/app/.bunext");
|
||||
|
||||
// Restore PORT env variable
|
||||
if (originalPort !== undefined) {
|
||||
process.env.PORT = originalPort;
|
||||
} else {
|
||||
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)) {
|
||||
fs.rmSync(dotBunext, { recursive: true, force: true });
|
||||
}
|
||||
const pubBunext = path.resolve(__dirname, "../__fixtures__/app/public/__bunext");
|
||||
if (fs.existsSync(pubBunext)) {
|
||||
fs.rmSync(pubBunext, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("boots up the server and correctly routes to index.tsx page", async () => {
|
||||
// Mock to randomize port
|
||||
// Note: Bun test runs modules in isolation but startServer imports grab-app-port
|
||||
// If we can't easily mock we can set PORT env
|
||||
process.env.PORT = "0"; // Let Bun.serve pick port
|
||||
|
||||
await bunextInit();
|
||||
server = await startServer();
|
||||
expect(server).toBeDefined();
|
||||
|
||||
// Fetch the index page
|
||||
expect(server.port).toBeGreaterThan(0);
|
||||
|
||||
const response = await fetch(`http://localhost:${server.port}/`);
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
|
||||
const html = await response.text();
|
||||
expect(html).toContain("Hello E2E");
|
||||
});
|
||||
@@ -57,7 +99,7 @@ describe("E2E Integration", () => {
|
||||
const response = await fetch(`http://localhost:${server.port}/unknown-foo-bar123`);
|
||||
expect(response.status).toBe(404);
|
||||
const text = await response.text();
|
||||
// Assume default 404 preset component is rendered
|
||||
// Default 404 component is rendered
|
||||
expect(text).toContain("404");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -10,9 +10,9 @@ describe("handle-hmr", () => {
|
||||
}
|
||||
} as any;
|
||||
global.HMR_CONTROLLERS = [];
|
||||
global.BUNDLER_CTX_MAP = [
|
||||
{ local_path: "/test-file" } as any
|
||||
];
|
||||
global.BUNDLER_CTX_MAP = {
|
||||
"/test-file": { local_path: "/test-file" } as any,
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -40,11 +40,11 @@ describe("handle-routes", () => {
|
||||
mock.restore();
|
||||
});
|
||||
|
||||
test("returns 401 for unknown route", async () => {
|
||||
test("returns 404 for unknown route", async () => {
|
||||
const req = new Request("http://localhost/api/unknown");
|
||||
const res = await handleRoutes({ req });
|
||||
|
||||
expect(res.status).toBe(401);
|
||||
|
||||
expect(res.status).toBe(404);
|
||||
const json = await res.json();
|
||||
expect(json.success).toBe(false);
|
||||
expect(json.msg).toContain("not found");
|
||||
|
||||
@@ -14,17 +14,17 @@ describe("grabDirNames", () => {
|
||||
expect(dirs.PUBLIC_DIR).toBe(path.join(cwd, "public"));
|
||||
});
|
||||
|
||||
it("nests HYDRATION_DST_DIR under public/__bunext/pages", () => {
|
||||
it("nests HYDRATION_DST_DIR under .bunext/public/pages", () => {
|
||||
const dirs = grabDirNames();
|
||||
expect(dirs.HYDRATION_DST_DIR).toBe(
|
||||
path.join(dirs.PUBLIC_DIR, "__bunext", "pages"),
|
||||
path.join(dirs.BUNX_CWD_DIR, "public", "pages"),
|
||||
);
|
||||
});
|
||||
|
||||
it("nests BUNEXT_CACHE_DIR under public/__bunext/cache", () => {
|
||||
it("nests BUNEXT_CACHE_DIR under .bunext/public/cache", () => {
|
||||
const dirs = grabDirNames();
|
||||
expect(dirs.BUNEXT_CACHE_DIR).toBe(
|
||||
path.join(dirs.PUBLIC_DIR, "__bunext", "cache"),
|
||||
path.join(dirs.BUNX_CWD_DIR, "public", "cache"),
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@ export default async function allPagesBunBundler(params?: Params) {
|
||||
chunk: "chunks/[hash].[ext]",
|
||||
},
|
||||
plugins: [tailwindcss],
|
||||
// plugins: [tailwindcss, BunSkipNonBrowserPlugin],
|
||||
splitting: true,
|
||||
target,
|
||||
metafile: true,
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
const BunSkipNonBrowserPlugin: Bun.BunPlugin = {
|
||||
name: "skip-non-browser",
|
||||
setup(build) {
|
||||
build.onResolve({ filter: /^(bun:|node:)/ }, (args) => {
|
||||
return { path: args.path, external: true };
|
||||
});
|
||||
|
||||
build.onResolve({ filter: /^[^./]/ }, (args) => {
|
||||
// If it's a built-in like 'fs' or 'path', skip it immediately
|
||||
const excludes = [
|
||||
"fs",
|
||||
"path",
|
||||
"os",
|
||||
"crypto",
|
||||
"net",
|
||||
"events",
|
||||
"util",
|
||||
];
|
||||
|
||||
if (excludes.includes(args.path) || args.path.startsWith("node:")) {
|
||||
return { path: args.path, external: true };
|
||||
}
|
||||
|
||||
try {
|
||||
Bun.resolveSync(args.path, args.importer || process.cwd());
|
||||
return null;
|
||||
} catch (e) {
|
||||
console.warn(`[Skip] Mark as external: ${args.path}`);
|
||||
return { path: args.path, external: true };
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export default BunSkipNonBrowserPlugin;
|
||||
@@ -3,6 +3,7 @@ import grabDirNames from "../utils/grab-dir-names";
|
||||
import path from "path";
|
||||
import grabConfig from "./grab-config";
|
||||
import type { BunextConfig } from "../types";
|
||||
import { log } from "../utils/log";
|
||||
|
||||
export default async function () {
|
||||
const dirNames = grabDirNames();
|
||||
@@ -29,7 +30,13 @@ export default async function () {
|
||||
"react-dom",
|
||||
);
|
||||
|
||||
if (dirNames.BUNX_ROOT_DIR !== dirNames.ROOT_DIR) {
|
||||
if (
|
||||
dirNames.ROOT_DIR.startsWith(dirNames.BUNX_ROOT_DIR) &&
|
||||
!dirNames.ROOT_DIR.includes(`${dirNames.BUNX_ROOT_DIR}/test/`)
|
||||
) {
|
||||
log.error(`Can't Run From this Directory => ${dirNames.ROOT_DIR}`);
|
||||
process.exit(1);
|
||||
} else {
|
||||
rmSync(react_package_dir, { recursive: true });
|
||||
rmSync(react_dom_package_dir, { recursive: true });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user