Update HMR. Make page reload when __root.tsx file is changed.

This commit is contained in:
2026-03-22 12:09:24 +01:00
parent 49d6781170
commit c3e1341ff8
17 changed files with 60 additions and 258 deletions
+1
View File
@@ -37,6 +37,7 @@ declare global {
var PAGES_SRC_WATCHER: FSWatcher | undefined;
var CURRENT_VERSION: string | undefined;
var PAGE_FILES: PageFiles[];
var ROOT_FILE_UPDATED: boolean;
}
export default async function bunextInit() {
+2 -3
View File
@@ -1,11 +1,10 @@
import type { ServeOptions } from "bun";
import grabAppPort from "../../utils/grab-app-port";
import isDevelopment from "../../utils/is-development";
import bunextRequestHandler from "./bunext-req-handler";
import grabConfig from "../grab-config";
import _ from "lodash";
export default async function (): Promise<ServeOptions> {
export default async function (): Promise<Bun.Serve.Options<any>> {
const port = grabAppPort();
const development = isDevelopment();
@@ -20,5 +19,5 @@ export default async function (): Promise<ServeOptions> {
development,
websocket: config?.websocket,
..._.omit(config?.serverOptions || {}, ["fetch"]),
} as ServeOptions;
} as Bun.Serve.Options<any>;
}
+13 -1
View File
@@ -42,9 +42,21 @@ export default async function serverPostBuildFn({ artifacts }: Params) {
}
try {
let final_data: { [k: string]: any } = {};
console.log("global.ROOT_FILE_UPDATED", global.ROOT_FILE_UPDATED);
if (global.ROOT_FILE_UPDATED) {
final_data = { reload: true };
} else {
final_data = final_artifact;
}
controller.controller.enqueue(
`event: update\ndata: ${JSON.stringify(final_artifact)}\n\n`,
`event: update\ndata: ${JSON.stringify(final_data)}\n\n`,
);
global.ROOT_FILE_UPDATED = false;
} catch {
global.HMR_CONTROLLERS.splice(i, 1);
}
+5
View File
@@ -48,6 +48,11 @@ export default async function watcher() {
if (filename.match(target_files_match) && global.BUNDLER_CTX) {
if (global.RECOMPILING) return;
global.RECOMPILING = true;
if (full_file_path.match(/\_\_root\.tsx?$/)) {
global.ROOT_FILE_UPDATED = true;
}
await rewritePagesModule({ page_url: full_file_path });
await global.BUNDLER_CTX.rebuild();
}
@@ -35,14 +35,21 @@ export default async function (params?: Params) {
script += `window.addEventListener("beforeunload", () => hmr.close());\n`;
script += `hmr.addEventListener("update", async (event) => {\n`;
script += ` if (event?.data) {\n`;
script += ` console.log(\`HMR Changes Detected. Updating ...\`);\n`;
script += ` try {\n`;
script += ` document.getElementById("__bunext_error_overlay")?.remove();\n`;
script += ` const data = JSON.parse(event.data);\n`;
// script += ` console.log("data", data);\n`;
script += ` console.log("data", data);\n`;
script += ` if (data.reload) {\n`;
script += ` console.log(\`Root Changes Detected. Reloading Page ...\`);\n`;
script += ` window.location.reload();\n`;
script += ` return;\n`;
script += ` }\n`;
script += ` console.log(\`HMR Changes Detected. Updating ...\`);\n`;
script += ` if (data.page_props) {\n`;
script += ` window.${ClientWindowPagePropsName} = data.page_props\n`;
script += ` window.${ClientWindowPagePropsName} = data.page_props;\n`;
script += ` }\n`;
script += ` const oldCSSLink = document.querySelector('link[rel="stylesheet"]');\n`;
@@ -1,126 +0,0 @@
import * as esbuild from "esbuild";
import tailwindEsbuildPlugin from "./tailwind-esbuild-plugin";
import type { BundlerCTXMap } from "../../../types";
import path from "path";
type Params = {
tsx: string;
out_file: string;
};
export default async function writeHMRTsxModule({ tsx, out_file }: Params) {
try {
const build = await esbuild.build({
stdin: {
contents: tsx,
resolveDir: process.cwd(),
loader: "tsx",
},
bundle: true,
format: "esm",
target: "es2020",
platform: "browser",
external: [
"react",
"react-dom",
"react/jsx-runtime",
"react-dom/client",
],
minify: true,
jsx: "automatic",
outfile: out_file,
plugins: [tailwindEsbuildPlugin],
metafile: true,
});
const artifacts: (
| Pick<BundlerCTXMap, "path" | "hash" | "css_path" | "type">
| undefined
)[] = Object.entries(build.metafile!.outputs)
.filter(([, meta]) => meta.entryPoint)
.map(([outputPath, meta]) => {
const cssPath = meta.cssBundle || undefined;
return {
path: outputPath,
hash: path.basename(outputPath, path.extname(outputPath)),
type: outputPath.endsWith(".css")
? "text/css"
: "text/javascript",
css_path: cssPath,
};
});
return artifacts?.[0];
} catch (error) {
return undefined;
}
}
// import * as esbuild from "esbuild";
// import path from "path";
// import tailwindEsbuildPlugin from "./tailwind-esbuild-plugin";
// const hmrExternalsPlugin: esbuild.Plugin = {
// name: "hmr-globals",
// setup(build) {
// const mapping: Record<string, string> = {
// react: "__REACT__",
// "react-dom": "__REACT_DOM__",
// "react-dom/client": "__REACT_DOM_CLIENT__",
// "react/jsx-runtime": "__JSX_RUNTIME__",
// };
// const filter = new RegExp(
// `^(${Object.keys(mapping)
// .map((k) => k.replace("/", "\\/"))
// .join("|")})$`,
// );
// build.onResolve({ filter }, (args) => {
// return { path: args.path, namespace: "hmr-global" };
// });
// build.onLoad({ filter: /.*/, namespace: "hmr-global" }, (args) => {
// const globalName = mapping[args.path];
// return {
// contents: `module.exports = window.${globalName};`,
// loader: "js",
// };
// });
// },
// };
// type Params = {
// tsx: string;
// file_path: string;
// out_file: string;
// };
// export default async function writeHMRTsxModule({
// tsx,
// file_path,
// out_file,
// }: Params) {
// try {
// await esbuild.build({
// stdin: {
// contents: tsx,
// resolveDir: path.dirname(file_path),
// loader: "tsx",
// },
// bundle: true,
// format: "esm",
// target: "es2020",
// platform: "browser",
// minify: true,
// jsx: "automatic",
// outfile: out_file,
// plugins: [hmrExternalsPlugin, tailwindEsbuildPlugin],
// });
// return true;
// } catch (error) {
// return false;
// }
// }
+2 -2
View File
@@ -1,4 +1,4 @@
import type { MatchedRoute, ServeOptions, Server, WebSocketHandler } from "bun";
import type { MatchedRoute, Server, WebSocketHandler } from "bun";
import type { FC, JSX, PropsWithChildren, ReactNode } from "react";
export type ServerProps = {
@@ -57,7 +57,7 @@ export type BunextConfig = {
| undefined;
defaultCacheExpiry?: number;
websocket?: WebSocketHandler<any>;
serverOptions?: ServeOptions;
serverOptions?: Bun.Serve.Options<any>;
};
export type BunextConfigMiddlewareParams = {