diff --git a/dist/functions/bundler/grab-client-hydration-script.js b/dist/functions/bundler/grab-client-hydration-script.js
index c15b846..c7f597e 100644
--- a/dist/functions/bundler/grab-client-hydration-script.js
+++ b/dist/functions/bundler/grab-client-hydration-script.js
@@ -44,7 +44,7 @@ export default async function grabClientHydrationScript({ page_local_path, }) {
txt += ` window.${ClientRootComponentWindowName}.render(component);\n`;
txt += `} else {\n`;
txt += ` const root = hydrateRoot(document.getElementById("${ClientRootElementIDName}"), component, { onRecoverableError: () => {\n\n`;
- txt += ` console.log(\`Hydration Error.\`)\n\n`;
+ // txt += ` console.log(\`Hydration Error.\`)\n\n`;
txt += ` } });\n\n`;
txt += ` window.${ClientRootComponentWindowName} = root;\n`;
txt += ` window.__BUNEXT_RERENDER__ = (NewPage) => {\n`;
diff --git a/dist/functions/server/watcher-esbuild-ctx.js b/dist/functions/server/watcher-esbuild-ctx.js
index 1bdf4e1..8035ec1 100644
--- a/dist/functions/server/watcher-esbuild-ctx.js
+++ b/dist/functions/server/watcher-esbuild-ctx.js
@@ -10,8 +10,6 @@ export default async function watcherEsbuildCTX() {
recursive: true,
persistent: true,
}, async (event, filename) => {
- // log.info(`event: ${event}`);
- // log.info(`filename: ${filename}`);
if (!filename)
return;
if (filename.match(/^\.\w+/)) {
@@ -105,7 +103,7 @@ async function fullRebuild(params) {
watcherEsbuildCTX();
}
}
-function reloadWatcher(params) {
+function reloadWatcher() {
if (global.PAGES_SRC_WATCHER) {
global.PAGES_SRC_WATCHER.close();
watcherEsbuildCTX();
diff --git a/dist/functions/server/web-pages/generate-web-html.js b/dist/functions/server/web-pages/generate-web-html.js
index 719f4d7..6f55ceb 100644
--- a/dist/functions/server/web-pages/generate-web-html.js
+++ b/dist/functions/server/web-pages/generate-web-html.js
@@ -56,6 +56,26 @@ export default async function genWebHTML({ component, pageProps, bundledMap, mod
},
});
const htmlBody = await new Response(stream).text();
+ // const originalConsole = {
+ // log: console.log,
+ // warn: console.warn,
+ // error: console.error,
+ // info: console.info,
+ // debug: console.debug,
+ // };
+ // console.log = () => {};
+ // console.warn = () => {};
+ // console.error = () => {};
+ // console.info = () => {};
+ // console.debug = () => {};
+ // const stream = await renderToReadableStream(final_component, {
+ // onError(error: any) {
+ // if (error.message.includes('unique "key" prop')) return;
+ // originalConsole.error(error);
+ // },
+ // });
+ // const htmlBody = await new Response(stream).text();
+ // Object.assign(console, originalConsole);
html += htmlBody;
return html;
}
diff --git a/dist/functions/server/web-pages/grab-page-react-component-string.js b/dist/functions/server/web-pages/grab-page-react-component-string.js
index 23cea5d..a006258 100644
--- a/dist/functions/server/web-pages/grab-page-react-component-string.js
+++ b/dist/functions/server/web-pages/grab-page-react-component-string.js
@@ -1,22 +1,16 @@
import EJSON from "../../../utils/ejson";
-import isDevelopment from "../../../utils/is-development";
import { log } from "../../../utils/log";
export default function grabPageReactComponentString({ file_path, root_file_path, server_res, }) {
- const now = Date.now();
- const dev = isDevelopment();
try {
- const import_suffix = dev ? `?t=${now}` : "";
let tsx = ``;
const server_res_json = JSON.stringify(EJSON.stringify(server_res || {}) ?? "{}");
- // Import Root from its original source path so that all sub-components
- // that import __root (e.g. AppContext) resolve to the same module instance.
- // Using the rewritten .bunext/pages/__root would create a separate
- // createContext() call, breaking context for any sub-component that
- // imports AppContext via a relative path to the source __root.
+ // Import directly from the source page files. The generated TSX is
+ // bundled before execution, which keeps Root, Page, and any __root
+ // context consumers inside one module graph for SSR.
if (root_file_path) {
- tsx += `import Root from "${root_file_path}${import_suffix}"\n`;
+ tsx += `import Root from "${root_file_path}"\n`;
}
- tsx += `import Page from "${file_path}${import_suffix}"\n`;
+ tsx += `import Page from "${file_path}"\n`;
tsx += `export default function Main() {\n\n`;
tsx += `const props = JSON.parse(${server_res_json})\n\n`;
tsx += ` return (\n`;
diff --git a/dist/functions/server/web-pages/grab-tsx-string-module.js b/dist/functions/server/web-pages/grab-tsx-string-module.js
index 95acea4..91ddb9c 100644
--- a/dist/functions/server/web-pages/grab-tsx-string-module.js
+++ b/dist/functions/server/web-pages/grab-tsx-string-module.js
@@ -1,75 +1,36 @@
import isDevelopment from "../../../utils/is-development";
-import { transform } from "esbuild";
+import * as esbuild from "esbuild";
+import grabDirNames from "../../../utils/grab-dir-names";
+import path from "path";
export default async function grabTsxStringModule({ tsx, }) {
const dev = isDevelopment();
const now = Date.now();
- const final_tsx = dev ? tsx + `\n// v_${now}` : tsx;
- const result = await transform(final_tsx, {
- loader: "tsx",
+ const { BUNX_CWD_MODULE_CACHE_DIR } = grabDirNames();
+ const target_cache_file_path = path.join(BUNX_CWD_MODULE_CACHE_DIR, `server-render-${now}.js`);
+ await esbuild.build({
+ stdin: {
+ contents: dev ? tsx + `\n// v_${now}` : tsx,
+ resolveDir: process.cwd(),
+ loader: "tsx",
+ },
+ bundle: true,
format: "esm",
- jsx: "automatic",
+ target: "es2020",
+ platform: "node",
+ external: [
+ "react",
+ "react-dom",
+ "react/jsx-runtime",
+ "react/jsx-dev-runtime",
+ ],
minify: !dev,
+ define: {
+ "process.env.NODE_ENV": JSON.stringify(dev ? "development" : "production"),
+ },
+ jsx: "automatic",
+ outfile: target_cache_file_path,
});
- const blob = new Blob([result.code], { type: "text/javascript" });
- const url = URL.createObjectURL(blob);
- const mod = await import(url);
- URL.revokeObjectURL(url);
+ Loader.registry.delete(target_cache_file_path);
+ const mod = await import(`${target_cache_file_path}?t=${now}`);
return mod;
}
-// const trimmed_file_path = file_path
-// .replace(/.*\/src\/pages\//, "")
-// .replace(/\.tsx$/, "");
-// const src_file_path = path.join(
-// BUNX_CWD_MODULE_CACHE_DIR,
-// `${trimmed_file_path}.tsx`,
-// );
-// const out_file_path = path.join(
-// BUNX_CWD_MODULE_CACHE_DIR,
-// `${trimmed_file_path}.js`,
-// );
-// await Bun.write(src_file_path, tsx);
-// const build = await Bun.build({
-// entrypoints: [src_file_path],
-// format: "esm",
-// target: "bun",
-// // external: ["react", "react-dom"],
-// minify: true,
-// define: {
-// "process.env.NODE_ENV": JSON.stringify(
-// dev ? "development" : "production",
-// ),
-// },
-// metafile: true,
-// plugins: [tailwindcss, BunSkipNonBrowserPlugin],
-// jsx: {
-// runtime: "automatic",
-// development: dev,
-// },
-// outdir: BUNX_CWD_MODULE_CACHE_DIR,
-// });
-// Loader.registry.delete(out_file_path);
-// const module = await import(`${out_file_path}?t=${Date.now()}`);
-// return module as T;
-// await esbuild.build({
-// stdin: {
-// contents: tsx,
-// resolveDir: process.cwd(),
-// loader: "tsx",
-// },
-// bundle: true,
-// format: "esm",
-// target: "es2020",
-// platform: "node",
-// external: ["react", "react-dom"],
-// minify: true,
-// define: {
-// "process.env.NODE_ENV": JSON.stringify(
-// dev ? "development" : "production",
-// ),
-// },
-// metafile: true,
-// plugins: [tailwindEsbuildPlugin],
-// jsx: "automatic",
-// write: true,
-// outfile: out_file_path,
-// });
diff --git a/src/__tests__/functions/server/grab-page-bundled-react-component.test.tsx b/src/__tests__/functions/server/grab-page-bundled-react-component.test.tsx
new file mode 100644
index 0000000..249e55b
--- /dev/null
+++ b/src/__tests__/functions/server/grab-page-bundled-react-component.test.tsx
@@ -0,0 +1,75 @@
+import { afterAll, afterEach, describe, expect, test } from "bun:test";
+import fs from "fs";
+import path from "path";
+import { renderToString } from "react-dom/server";
+import grabPageBundledReactComponent from "../../../../src/functions/server/web-pages/grab-page-bundled-react-component";
+import grabDirNames from "../../../../src/utils/grab-dir-names";
+
+const { BUNX_CWD_MODULE_CACHE_DIR, BUNX_TMP_DIR } = grabDirNames();
+
+describe("grabPageBundledReactComponent", () => {
+ const fixtureDirs: string[] = [];
+ const originalConfig = global.CONFIG;
+
+ global.CONFIG = { development: true } as any;
+
+ afterEach(() => {
+ for (const fixtureDir of fixtureDirs.splice(0)) {
+ fs.rmSync(fixtureDir, { recursive: true, force: true });
+ }
+
+ global.CONFIG = { development: true } as any;
+ });
+
+ afterAll(() => {
+ global.CONFIG = originalConfig;
+ });
+
+ test("keeps __root context connected during SSR", async () => {
+ fs.mkdirSync(BUNX_CWD_MODULE_CACHE_DIR, { recursive: true });
+ fs.mkdirSync(BUNX_TMP_DIR, { recursive: true });
+
+ const fixtureDir = path.join(BUNX_TMP_DIR, `ssr-context-${Date.now()}`);
+ fixtureDirs.push(fixtureDir);
+ fs.mkdirSync(fixtureDir, { recursive: true });
+
+ const rootFilePath = path.join(fixtureDir, "__root.tsx");
+ const pageFilePath = path.join(fixtureDir, "page.tsx");
+
+ fs.writeFileSync(
+ rootFilePath,
+ `import { createContext } from "react";
+export const AppContext = createContext("missing-context");
+
+export default function Root({ children }: { children: React.ReactNode }) {
+ return (
+