mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-16 04:27:21 +00:00
changed build workflow – for auth it's required to have better control over html and assets
This commit is contained in:
@@ -1,59 +1,34 @@
|
||||
import { readFile } from "node:fs/promises";
|
||||
import { serveStatic } from "@hono/node-server/serve-static";
|
||||
import type { BkndConfig } from "bknd";
|
||||
import { App } from "bknd";
|
||||
|
||||
async function getHtml() {
|
||||
return readFile("index.html", "utf8");
|
||||
}
|
||||
function addViteScripts(html: string) {
|
||||
return html.replace(
|
||||
"<head>",
|
||||
`<script type="module">
|
||||
import RefreshRuntime from "/@react-refresh"
|
||||
RefreshRuntime.injectIntoGlobalHook(window)
|
||||
window.$RefreshReg$ = () => {}
|
||||
window.$RefreshSig$ = () => (type) => type
|
||||
window.__vite_plugin_react_preamble_installed__ = true
|
||||
</script>
|
||||
<script type="module" src="/@vite/client"></script>
|
||||
`
|
||||
);
|
||||
}
|
||||
|
||||
function createApp(config: BkndConfig, env: any) {
|
||||
const create_config = typeof config.app === "function" ? config.app(env) : config.app;
|
||||
return App.create(create_config);
|
||||
}
|
||||
|
||||
function setAppBuildListener(app: App, config: BkndConfig, html: string) {
|
||||
function setAppBuildListener(app: App, config: BkndConfig, html?: string) {
|
||||
app.emgr.on(
|
||||
"app-built",
|
||||
async () => {
|
||||
await config.onBuilt?.(app);
|
||||
app.registerAdminController();
|
||||
app.module.server.client.get("/assets/!*", serveStatic({ root: "./" }));
|
||||
if (config.setAdminHtml) {
|
||||
app.registerAdminController({ html, forceDev: true });
|
||||
app.module.server.client.get("/assets/*", serveStatic({ root: "./" }));
|
||||
}
|
||||
},
|
||||
"sync"
|
||||
);
|
||||
}
|
||||
|
||||
export async function serveFresh(config: BkndConfig, _html?: string) {
|
||||
let html = _html;
|
||||
if (!html) {
|
||||
html = await getHtml();
|
||||
}
|
||||
|
||||
html = addViteScripts(html);
|
||||
|
||||
return {
|
||||
async fetch(request: Request, env: any, ctx: ExecutionContext) {
|
||||
const app = createApp(config, env);
|
||||
|
||||
setAppBuildListener(app, config, html);
|
||||
setAppBuildListener(app, config, _html);
|
||||
await app.build();
|
||||
|
||||
//console.log("routes", app.module.server.client.routes);
|
||||
return app.fetch(request, env, ctx);
|
||||
}
|
||||
};
|
||||
@@ -61,18 +36,11 @@ export async function serveFresh(config: BkndConfig, _html?: string) {
|
||||
|
||||
let app: App;
|
||||
export async function serveCached(config: BkndConfig, _html?: string) {
|
||||
let html = _html;
|
||||
if (!html) {
|
||||
html = await getHtml();
|
||||
}
|
||||
|
||||
html = addViteScripts(html);
|
||||
|
||||
return {
|
||||
async fetch(request: Request, env: any, ctx: ExecutionContext) {
|
||||
if (!app) {
|
||||
app = createApp(config, env);
|
||||
setAppBuildListener(app, config, html);
|
||||
setAppBuildListener(app, config, _html);
|
||||
await app.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ export async function serveStatic(server: Platform): Promise<MiddlewareHandler>
|
||||
}
|
||||
|
||||
export async function attachServeStatic(app: any, platform: Platform) {
|
||||
app.module.server.client.get("/assets/*", await serveStatic(platform));
|
||||
app.module.server.client.get("/*", await serveStatic(platform));
|
||||
}
|
||||
|
||||
export async function startServer(server: Platform, app: any, options: { port: number }) {
|
||||
|
||||
@@ -54,7 +54,7 @@ async function makeApp(config: MakeAppConfig) {
|
||||
"app-built",
|
||||
async () => {
|
||||
await attachServeStatic(app, config.server?.platform ?? "node");
|
||||
app.registerAdminController({ html: await getHtml() });
|
||||
app.registerAdminController();
|
||||
|
||||
if (config.onBuilt) {
|
||||
await config.onBuilt(app);
|
||||
@@ -75,7 +75,7 @@ export async function makeConfigApp(config: BkndConfig, platform?: Platform) {
|
||||
"app-built",
|
||||
async () => {
|
||||
await attachServeStatic(app, platform ?? "node");
|
||||
app.registerAdminController({ html: await getHtml() });
|
||||
app.registerAdminController();
|
||||
|
||||
if (config.onBuilt) {
|
||||
await config.onBuilt(app);
|
||||
|
||||
@@ -7,20 +7,12 @@ import { Hono } from "hono";
|
||||
import { html } from "hono/html";
|
||||
import { Fragment } from "hono/jsx";
|
||||
import * as SystemPermissions from "modules/permissions";
|
||||
import type { Manifest } from "vite";
|
||||
|
||||
const viteInject = `
|
||||
import RefreshRuntime from "/@react-refresh"
|
||||
RefreshRuntime.injectIntoGlobalHook(window)
|
||||
window.$RefreshReg$ = () => {}
|
||||
window.$RefreshSig$ = () => (type) => type
|
||||
window.__vite_plugin_react_preamble_installed__ = true
|
||||
`;
|
||||
const htmlBkndContextReplace = "<!-- BKND_CONTEXT -->";
|
||||
|
||||
export type AdminControllerOptions = {
|
||||
html?: string;
|
||||
viteManifest?: Manifest;
|
||||
forceDev?: boolean;
|
||||
};
|
||||
|
||||
export class AdminController implements ClassController {
|
||||
@@ -114,44 +106,36 @@ export class AdminController implements ClassController {
|
||||
}
|
||||
|
||||
console.warn(
|
||||
"Custom HTML needs to include '<!-- BKND_CONTEXT -->' to inject BKND context"
|
||||
`Custom HTML needs to include '${htmlBkndContextReplace}' to inject BKND context`
|
||||
);
|
||||
return this.options.html as string;
|
||||
}
|
||||
|
||||
const configs = this.app.modules.configs();
|
||||
const isProd = !isDebug() && !this.options.forceDev;
|
||||
|
||||
// @todo: implement guard redirect once cookie sessions arrive
|
||||
const assets = {
|
||||
js: "main.js",
|
||||
css: "styles.css"
|
||||
};
|
||||
|
||||
const isProd = !isDebug();
|
||||
let script: string | undefined;
|
||||
let css: string[] = [];
|
||||
|
||||
// @todo: check why nextjs imports manifest, it's not required
|
||||
if (isProd) {
|
||||
const manifest: Manifest = this.options.viteManifest
|
||||
? this.options.viteManifest
|
||||
: isProd
|
||||
? // @ts-ignore cases issues when building types
|
||||
await import("bknd/dist/manifest.json", { assert: { type: "json" } }).then(
|
||||
(m) => m.default
|
||||
)
|
||||
: {};
|
||||
//console.log("manifest", manifest, manifest["index.html"]);
|
||||
const entry = Object.values(manifest).find((f: any) => f.isEntry === true);
|
||||
if (!entry) {
|
||||
// do something smart
|
||||
return;
|
||||
try {
|
||||
// @ts-ignore
|
||||
const manifest = await import("bknd/dist/manifest.json", {
|
||||
assert: { type: "json" }
|
||||
}).then((m) => m.default);
|
||||
assets.js = manifest["src/ui/main.tsx"].name;
|
||||
assets.css = manifest["src/ui/main.css"].name;
|
||||
} catch (e) {
|
||||
console.error("Error loading manifest", e);
|
||||
}
|
||||
|
||||
script = "/" + entry.file;
|
||||
css = entry.css?.map((c: string) => "/" + c) ?? [];
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{/* dnd complains otherwise */}
|
||||
{html`<!doctype html>`}
|
||||
{html`<!DOCTYPE html>`}
|
||||
<html lang="en" class={configs.server.admin.color_scheme ?? "light"}>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
@@ -162,14 +146,21 @@ export class AdminController implements ClassController {
|
||||
<title>BKND</title>
|
||||
{isProd ? (
|
||||
<Fragment>
|
||||
<script type="module" CrossOrigin src={script} />
|
||||
{css.map((c) => (
|
||||
<link rel="stylesheet" CrossOrigin href={c} key={c} />
|
||||
))}
|
||||
<script type="module" CrossOrigin src={"/" + assets?.js} />
|
||||
<link rel="stylesheet" crossOrigin href={"/" + assets?.css} />
|
||||
</Fragment>
|
||||
) : (
|
||||
<Fragment>
|
||||
<script type="module" dangerouslySetInnerHTML={{ __html: viteInject }} />
|
||||
<script
|
||||
type="module"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `import RefreshRuntime from "/@react-refresh"
|
||||
RefreshRuntime.injectIntoGlobalHook(window)
|
||||
window.$RefreshReg$ = () => {}
|
||||
window.$RefreshSig$ = () => (type) => type
|
||||
window.__vite_plugin_react_preamble_installed__ = true`
|
||||
}}
|
||||
/>
|
||||
<script type="module" src={"/@vite/client"} />
|
||||
</Fragment>
|
||||
)}
|
||||
|
||||
@@ -2,3 +2,4 @@ export { ClientProvider, useClient, useBaseUrl } from "./ClientProvider";
|
||||
export { BkndProvider, useBknd } from "./BkndProvider";
|
||||
|
||||
export { useAuth } from "./schema/auth/use-auth";
|
||||
export { Api } from "../../Api";
|
||||
|
||||
5
app/src/ui/inject.js
Normal file
5
app/src/ui/inject.js
Normal file
@@ -0,0 +1,5 @@
|
||||
// react shim
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom/client";
|
||||
|
||||
export { React, ReactDOM };
|
||||
@@ -3,7 +3,6 @@
|
||||
@import "@mantine/core/styles.css";
|
||||
@import '@mantine/notifications/styles.css';
|
||||
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { StrictMode } from "react";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import "./styles.css";
|
||||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom/client";
|
||||
import "./main.css";
|
||||
|
||||
import Admin from "./Admin";
|
||||
|
||||
@@ -13,9 +13,9 @@ const rootElement = document.getElementById("app")!;
|
||||
if (!rootElement.innerHTML) {
|
||||
const root = ReactDOM.createRoot(rootElement);
|
||||
root.render(
|
||||
<StrictMode>
|
||||
<React.StrictMode>
|
||||
<ClientApp />
|
||||
</StrictMode>
|
||||
</React.StrictMode>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user