checkpoint

This commit is contained in:
Rizky 2024-12-29 12:10:52 +07:00
parent aef2611d5d
commit 9577a1a5be
10 changed files with 6024 additions and 424 deletions

BIN
bun.lockb

Binary file not shown.

View File

@ -18,7 +18,7 @@ export const loadCurrentDeploy = async (ts: number) => {
)
);
prasi.site = {
prasi.deployed = {
layouts: content.layouts,
pages: content.pages,
comps: content.comps,

View File

@ -1,7 +1,9 @@
import type { Server } from "bun";
import type { BunFile, Server } from "bun";
import { prasi } from "main/prasi-var";
import { join } from "path";
import type { PrasiHttpHandler } from "typings/server";
import { route_api } from "./route-api";
import { route_index } from "./route-index";
export const createHttpHandler = (server: Server, mode: "dev" | "prod") => {
const handle: PrasiHttpHandler = async function (
@ -14,20 +16,50 @@ export const createHttpHandler = (server: Server, mode: "dev" | "prod") => {
let status = 200;
const url = this.url;
const static_file = prasi.static.exists(url.pathname);
if (static_file) {
body = Bun.file(static_file.data.fullpath);
if (url.pathname.startsWith("/nova")) {
const nova_file = join(prasi.static.nova, url.pathname.substring(6));
if (nova_file) {
body = Bun.file(nova_file);
}
} else {
const api = await route_api.handle(this.url.pathname, req);
if (api) {
body = api.body;
headers = api.headers;
status = api.status;
const frontend_file = prasi.static.frontend.exists(url.pathname);
if (frontend_file) {
body = Bun.file(frontend_file.data.fullpath);
} else {
const public_file = prasi.static.public.exists(url.pathname);
if (public_file) {
body = Bun.file(public_file.data.fullpath);
} else {
const api = await route_api.handle(this.url.pathname, req);
if (api) {
body = api.body;
headers = api.headers;
status = api.status;
}
}
}
if (
body === null &&
![".js", ".css"].find((e) => url.pathname.endsWith(e))
) {
const index = route_index.handle(prasi.site_id, {});
if (index) {
body = index.render();
headers = { "content-type": "text/html" };
}
}
}
if (body === null) {
// body = route_index.handle()
if (typeof body === "object" && body) {
const file = body as BunFile;
if (typeof file.type === "string" && typeof file.exists === "function") {
if (!headers && file.type.includes("octet")) {
headers = {
"content-type": "text/plain",
};
}
}
}
if (opt?.rewrite) {

View File

@ -1,44 +1,70 @@
import { readFileSync } from "fs";
import { prasi } from "main/prasi-var";
import { join } from "path";
import { parse } from "node-html-parser";
export const route_index = {
handle: (site_id: string, opt: { page_id?: string; params?: any }) => {
_cache: "",
_head: [] as string[],
handle(site_id: string, opt: { page_id?: string; params?: any }) {
if (!this._cache) {
this._cache = readFileSync(join(prasi.static.nova, "index.html"), {
encoding: "utf-8",
});
const html = parse(this._cache);
this._head = [
...html.querySelectorAll("script").map((e) => {
if (prasi.mode === "vm") {
e.setAttribute("src", `/prod/${site_id}${e.getAttribute("src")}`);
}
return e.toString();
}),
...html.querySelectorAll("link").map((e) => {
if (prasi.mode === "vm") {
e.setAttribute("href", `/prod/${site_id}${e.getAttribute("href")}`);
}
return e.toString();
}),
];
}
return {
head: [] as string[],
head: [...this._head],
body: [] as string[],
render() {
const base_path = prasi.mode === "vm" ? `/prod/${site_id}` : ``;
const current = { page_id: undefined, params: undefined };
return `\
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, initial-scale=1.0, user-scalable=1.0, minimum-scale=1.0, maximum-scale=1.0">
<link rel="stylesheet" href="${base_path}/index.css">
<link rel="stylesheet" href="${base_path}/main.css">
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, initial-scale=1.0, user-scalable=1.0, minimum-scale=1.0, maximum-scale=1.0">
${this.head.join("\n")}
</head>
<body class="flex-col flex-1 w-full min-h-screen flex opacity-0">
${this.body.join("\n")}
<div id="root"></div>
<script>
window._prasi = {
basepath: "${base_path}/",
site_id: "${site_id}",${
opt.page_id ? `\n page_id: "${opt.page_id}",` : ""
</head>
<body class="flex-col flex-1 w-full min-h-screen flex opacity-0">
${this.body.join("\n")}
<div id="root"></div>
<script>
window._prasi = {
basepath: "${base_path}/",
site_id: "${site_id}",${
current.page_id ? `\n page_id: "${current.page_id}",` : ""
}${
typeof opt.params === "object"
? `\n params: ${JSON.stringify(opt.params)},`
typeof current.params === "object"
? `\n params: ${JSON.stringify(current.params)},`
: ""
}
}
</script>
<script src="/main.js" type="module"></script>
</body>
</html>`;
}
</script>
</body>
</html>`;
},
};
},

View File

@ -16,6 +16,7 @@ export const init = async ({
mode,
prasi: init_prasi,
action,
handler,
}: {
site_id: string;
prasi: {
@ -26,6 +27,7 @@ export const init = async ({
server: string;
typings: string;
dir: {
nova: string;
site: string;
build: string;
upload: string;
@ -36,19 +38,23 @@ export const init = async ({
server: (server: PrasiServer) => Server;
mode: "vm" | "server";
action?: "reload" | "start";
handler: {
pages: (ids: string[]) => Promise<Record<string, any>>;
};
}) => {
prasi.mode = mode;
const script_dir = init_prasi.paths.dir.build;
const build_dir = init_prasi.paths.dir.build;
if (!script_dir) {
if (!build_dir) {
console.error(`dir.build is empty, please check prasi.json!`);
return;
}
const script_path = join(
script_dir,
const backend_path = join(
build_dir,
init_prasi.paths.server.replace(".ts", ".js")
);
const frontend_dir = dirname(join(build_dir, init_prasi.paths.index));
fs.init({
site: init_prasi.paths.dir.site,
@ -63,18 +69,23 @@ export const init = async ({
const { route_api: api_route } = await import("./handler/route-api");
await api_route.init();
prasi.static = await staticFile(script_dir);
prasi.static = {
frontend: await staticFile(frontend_dir),
public: await staticFile(init_prasi.paths.dir.public),
nova: init_prasi.paths.dir.nova,
};
prasi.site_id = site_id;
if (mode === "vm") {
const src = await Bun.file(script_path).text();
const script = new Script(src, { filename: script_path });
const src = await Bun.file(backend_path).text();
const script = new Script(src, { filename: backend_path });
const ctx = { module: { exports: { server: null as any } } };
const cjs = script.runInThisContext();
cjs(ctx.module.exports, require, ctx.module);
prasi.server = ctx.module.exports.server;
} else {
delete require.cache[script_path];
const module = require(script_path);
delete require.cache[backend_path];
const module = require(backend_path);
prasi.server = module.server;
}
process.chdir(

View File

@ -13,8 +13,13 @@ if (!(globalThis as any).prasi) {
export const prasi = (globalThis as any).prasi as unknown as {
static_cache: any;
static: StaticFile;
mode: "vm" | "server"
site_id: string;
static: {
frontend: StaticFile;
public: StaticFile;
nova: string;
};
mode: "vm" | "server";
ext: {
kv?: BunSqliteKeyValue;
firebase?: {
@ -30,7 +35,7 @@ export const prasi = (globalThis as any).prasi as unknown as {
http: (req: Request) => Promise<Response>;
ws: WebSocketHandler<{ url: URL }>;
};
site?: {
deployed?: {
db?: SiteConfig["db"];
layouts: {
id: string;

View File

@ -44,6 +44,7 @@ export const staticFile = async (
const static_file = {
scanning: false,
paths: new Set<string>(),
root: path,
async rescan(arg?: { immediately?: boolean }) {
// rescan will be overwritten after static_file definition.
},
@ -98,7 +99,7 @@ export const staticFile = async (
return;
}
static_file.scanning = true;
if (await existsAsync(path)) {
if (path && await existsAsync(path)) {
if (static_file.paths.size > 0) {
store.gz.delete([...static_file.paths]);
store.zstd.delete([...static_file.paths]);

5
internal/vm/.readme.md Normal file
View File

@ -0,0 +1,5 @@
WARNING: This VM folder is auto generated from main/init.ts,
The purpose of directory is to be loaded as vm server from prasi editor.
Creating a VM only works when it is loaded as single file, hence it is built.
Do not directly change files in this directory, as it will be re-generated.

File diff suppressed because one or more lines are too long

View File

@ -28,6 +28,7 @@
"mime": "^4.0.6",
"msgpackr": "^1.11.2",
"multipasta": "^0.2.5",
"node-html-parser": "^7.0.1",
"rou3": "^0.5.1",
"sharp": "^0.33.5",
"uuid": "^11.0.3"