checkpoint

This commit is contained in:
Rizky 2024-05-05 19:27:54 +07:00
parent 11ea32ac07
commit 993951eb89
6 changed files with 141 additions and 322 deletions

View File

@ -4,6 +4,7 @@ import { validate } from "uuid";
import { prodIndex } from "../util/prod-index"; import { prodIndex } from "../util/prod-index";
import { gzipAsync } from "../ws/sync/entity/zlib"; import { gzipAsync } from "../ws/sync/entity/zlib";
import { code } from "../ws/sync/code/code"; import { code } from "../ws/sync/code/code";
import { initFrontEnd } from "../ws/sync/code/parts/init/frontend";
export const _ = { export const _ = {
url: "/prod/:site_id/**", url: "/prod/:site_id/**",
@ -30,8 +31,11 @@ export const _ = {
const build_path = code.path(site_id, "site", "build", codepath); const build_path = code.path(site_id, "site", "build", codepath);
const file = Bun.file(build_path); const file = Bun.file(build_path);
if (!(await file.exists())) if (!(await file.exists())) {
const root = `/code/${site_id}/site/src`;
await initFrontEnd(root, site_id);
return new Response("Code file not found", { status: 403 }); return new Response("Code file not found", { status: 403 });
}
return new Response(file); return new Response(file);
} }

View File

@ -1,10 +1,9 @@
import { dir } from "dir"; import { dir } from "dir";
import { initFrontEnd } from "./parts/init/frontend"; import { initFrontEnd } from "./parts/init/frontend";
import { initServer } from "./parts/init/server"; import { initServer } from "./parts/init/server";
import { buildTypes } from "./parts/init/typings";
import { codeInternal } from "./parts/internal"; import { codeInternal } from "./parts/internal";
import { ensureLib } from "./utlis/ensure-lib";
import { ensureFiles } from "./utlis/ensure-files"; import { ensureFiles } from "./utlis/ensure-files";
import { ensureLib } from "./utlis/ensure-lib";
export const code = { export const code = {
internal: codeInternal, internal: codeInternal,

View File

@ -1,12 +1,12 @@
import globalExternals from "@fal-works/esbuild-plugin-global-externals"; import globalExternals from "@fal-works/esbuild-plugin-global-externals";
import style from "@hyrious/esbuild-plugin-style"; import style from "@hyrious/esbuild-plugin-style";
import { dir } from "dir"; import { dir } from "dir";
import { context } from "esbuild"; import { BuildOptions, BuildResult, context } from "esbuild";
import { removeAsync } from "fs-jetpack"; import { removeAsync } from "fs-jetpack";
import isEqual from "lodash.isequal"; import isEqual from "lodash.isequal";
import { appendFile } from "node:fs/promises";
import { code } from "../../code"; import { code } from "../../code";
import { buildTypes } from "./typings"; import { buildTypes } from "./typings";
import { appendFile } from "node:fs/promises";
const decoder = new TextDecoder(); const decoder = new TextDecoder();
export const initFrontEnd = async (root: string, id_site: string) => { export const initFrontEnd = async (root: string, id_site: string) => {
@ -21,13 +21,12 @@ export const initFrontEnd = async (root: string, id_site: string) => {
try { try {
await isInstalling(id_site); await isInstalling(id_site);
const out_dir = dir.data(`code/${id_site}/site/build`);
const build_path = dir.data(`code/${id_site}/site/build`); await removeAsync(out_dir);
await removeAsync(build_path);
const existing = await context({ const existing = await context({
absWorkingDir: dir.data(root), absWorkingDir: dir.data(root),
entryPoints: ["index.tsx"], entryPoints: ["index.tsx"],
outdir: build_path, outdir: out_dir,
format: "esm", format: "esm",
bundle: true, bundle: true,
minify: true, minify: true,
@ -52,6 +51,23 @@ export const initFrontEnd = async (root: string, id_site: string) => {
name: "prasi", name: "prasi",
async setup(setup) { async setup(setup) {
try { try {
await codeError(id_site, "Building...");
setup.onStart(async () => {
if (!(await isInstalling(id_site)))
await codeError(id_site, "Building...");
});
setup.onEnd(async (res) => {
if (res.errors.length > 0) {
if (!(await installDeps(root, res, id_site))) {
await codeError(
id_site,
res.errors.map((e) => e.text).join("\n\n")
);
}
} else {
await buildTypes(root, id_site);
}
});
} catch (e) { } catch (e) {
console.log("ERROR"); console.log("ERROR");
} }
@ -61,9 +77,9 @@ export const initFrontEnd = async (root: string, id_site: string) => {
}); });
code.internal.frontend[id_site] = existing; code.internal.frontend[id_site] = existing;
await existing.watch(); await existing.watch();
} catch (e) { } catch (e: any) {
console.error("Error building front end", id_site);
delete code.internal.frontend[id_site]; delete code.internal.frontend[id_site];
console.log("front end error", e);
} }
}; };
@ -82,8 +98,10 @@ const isInstalling = async (id_site: string) => {
const file = Bun.file(path); const file = Bun.file(path);
try { try {
const text = await file.text(); const text = await file.text();
if (text.startsWith("Installing dependencies")) return true; if (typeof text === "string" && text.startsWith("Installing dependencies"))
return true;
} catch (e) {} } catch (e) {}
return false; return false;
}; };
@ -91,6 +109,7 @@ const readPackageJSON = async (id_site: string) => {
const file = Bun.file(code.path(id_site, "site", "src", "package.json")); const file = Bun.file(code.path(id_site, "site", "src", "package.json"));
const deps = new Set<string>(); const deps = new Set<string>();
if (await file.exists()) {
const json = await file.json(); const json = await file.json();
if (json.dependencies) { if (json.dependencies) {
@ -104,5 +123,67 @@ const readPackageJSON = async (id_site: string) => {
deps.add(k); deps.add(k);
} }
} }
}
return deps; return deps;
}; };
const installDeps = async (
root: string,
res: BuildResult<BuildOptions>,
id_site: string
) => {
const pkgjson = await readPackageJSON(id_site);
const imports = new Set<string>();
if (!(await isInstalling(id_site))) await codeError(id_site, "");
if (res.errors.length > 0) {
for (const err of res.errors) {
if (err.notes?.[0].text.startsWith("You can mark the path ")) {
let im = err.notes?.[0].text.split('"')[1];
if (!im.startsWith("@")) {
im = im.split("/").shift() || "";
}
imports.add(im);
}
}
}
if (res.metafile) {
for (const [_, file] of Object.entries(res.metafile?.inputs || {})) {
for (const im of file.imports) {
if (im.kind === "import-statement" && im.external) {
if (!im.path.startsWith(".") && !im.path.startsWith("@/"))
imports.add(im.path);
}
}
}
}
if (!isEqual(imports, pkgjson)) {
await codeError(
id_site,
"Installing dependencies:\n " + [...imports].join("\n ")
);
let proc = Bun.spawn([`npm`, `install`, ...imports], {
stdio: ["inherit", "pipe", "pipe"],
cwd: dir.data(root),
});
async function print(generator: ReadableStream<Uint8Array>, prefix: any) {
for await (let value of generator) {
const str = decoder.decode(value);
await codeError(id_site, `${prefix} ${str}`, true);
}
}
print(proc.stdout, "stdout:");
print(proc.stderr, "stderr:");
await proc.exited;
await codeError(id_site, "");
return true;
}
};

View File

@ -1,261 +0,0 @@
import { ServerWebSocket } from "bun";
import { Packr } from "msgpackr";
import { WSData } from "../../../../../../pkgs/core/server/create";
import { code } from "../../code/code";
const packr = new Packr({ structuredClone: true });
const sendWS = (ws: ServerWebSocket<WSData>, msg: any) => {
ws.sendBinary(packr.pack(msg));
};
export const codeBuild = async (id_site: any) => {
return;
// const src_path = code.path(id_site, "site", "src");
// if (!(await existsAsync(src_path))) return;
// if (!code.esbuild[id_site]) {
// code.esbuild[id_site] = { site: null, server: null, site_ts: Date.now() };
// }
// if (!code.esbuild[id_site].server) {
// const server_main = code.path(id_site, "site", "src", "server.ts");
// if (!(await existsAsync(server_main))) {
// await writeAsync(
// server_main,
// `\
// import type {} from "./typings/global";
// export const server: PrasiServer = {
// async http({ req, handle, mode, url, index, server }) {
// return await handle(req);
// }
// };
// `
// );
// const bun_types = Bun.spawn({
// cmd: ["npm", "i", "-D", "@types/bun"],
// cwd: code.path(id_site, "site", "src"),
// });
// await bun_types.exited;
// }
// const build_path = code.path(id_site, "server", "build");
// await removeAsync(build_path);
// await dirAsync(build_path);
// const build_file = `${build_path}/index.js`;
// if (!(await existsAsync(build_file))) {
// await writeAsync(build_file, "");
// }
// code.esbuild[id_site].server = await context({
// absWorkingDir: src_path,
// entryPoints: ["server.ts"],
// bundle: true,
// outfile: build_file,
// platform: "node",
// treeShaking: true,
// format: "cjs",
// logLevel: "silent",
// banner: {
// js: `\
// const _fs = require('node:fs/promises');
// const console =
// typeof global.server_hook === "function"
// ? { ...global.console }
// : global.console;
// let db = new Proxy({}, {
// get(_, key) {
// const runtime = global.server_runtime["${id_site}"];
// if (runtime && runtime.db) {
// return runtime.db[key];
// }
// }
// });
// let api = {};
// if (typeof global.server_hook === "function") {
// const log = global.console.log;
// console.log = function (...arg) {
// const out = "${code.path(id_site, "site", "src", "server.log")}";
// _fs.appendFile(out, arg.map((e)=>{
// const ancestors = [];
// if (typeof e === 'object') return JSON.stringify(e, function (key, val) {
// if (val) {
// if (typeof val === 'function') {
// return '[function]';
// }
// if (typeof val === 'object') {
// while (ancestors.length > 0 && ancestors.at(-1) !== this) {
// ancestors.pop();
// }
// if (ancestors.includes(val)) {
// return "[circular]";
// }
// ancestors.push(val);
// if (val.constructor &&
// !['Object', 'Array'].includes(val.constructor.name)) {
// if (val.constructor.name === 'Error') {
// return '[Error] ' + val.message;
// }
// return '[Class] ' + val.constructor.name;
// }
// }
// }
// return val;
// }, 2);
// return e;
// }).join(" ") + "\\n");
// }.bind(console);
// } else {
// db = global.db;
// api = global.api;
// }`,
// },
// plugins: [
// style(),
// globalExternals({
// react: {
// varName: "window.React",
// type: "cjs",
// },
// "react-dom": {
// varName: "window.ReactDOM",
// type: "cjs",
// },
// }),
// {
// name: "prasi",
// setup(setup) {
// const reinit = () => {
// setup.onEnd((res) => {
// if (res.errors.length > 0) {
// Bun.write(
// Bun.file(code.path(id_site, "site", "src", "server.log")),
// JSON.stringify(res.errors, null, 2)
// );
// }
// server.init(id_site);
// });
// };
// reinit();
// },
// },
// ],
// });
// const esbuild = code.esbuild[id_site].server;
// esbuild?.watch();
// }
// if (!code.esbuild[id_site].site) {
// const build_path = code.path(id_site, "site", "build_cache");
// await removeAsync(build_path);
// await dirAsync(build_path);
// const build_file = `${build_path}/index.js`;
// await writeAsync(build_file, "");
// const index_path = code.path(id_site, "site", "src", "index.tsx");
// if (!(await existsAsync(index_path))) {
// await writeAsync(index_path, 'export const hello = "world"');
// }
// console.log("running ");
// code.esbuild[id_site].site = await context({
// absWorkingDir: src_path,
// entryPoints: ["index.tsx"],
// bundle: true,
// outdir: build_path,
// minify: true,
// treeShaking: true,
// format: "esm",
// splitting: true,
// logLevel: "silent",
// sourcemap: true,
// plugins: [
// style(),
// globalExternals({
// react: {
// varName: "window.React",
// type: "cjs",
// },
// "react-dom": {
// varName: "window.ReactDOM",
// type: "cjs",
// },
// }),
// {
// name: "prasi",
// setup(setup) {
// setup.onEnd(async (res) => {
// if (res.errors.length > 0) {
// await codeError(
// id_site,
// res.errors.map((e) => e.text).join("\n\n"),
// "site"
// );
// } else {
// codeBuildType(id_site);
// await removeAsync(code.path(id_site, "site", "build"));
// await moveAsync(
// code.path(id_site, "site", "build_cache"),
// code.path(id_site, "site", "build")
// );
// await removeAsync(
// code.path(id_site, "site", "src", "index.log")
// );
// code.esbuild[id_site].site_ts = Date.now();
// const client_ids = new Set<string>();
// user.active.findAll({ site_id: id_site }).forEach((e) => {
// client_ids.add(e.client_id);
// });
// client_ids.forEach((client_id) => {
// const ws = conns.get(client_id)?.ws;
// if (ws) {
// sendWS(ws, {
// type: SyncType.Event,
// event: "code_changes",
// data: { ts: code.esbuild[id_site].site_ts },
// });
// }
// });
// }
// });
// },
// },
// ],
// });
// const esbuild = code.esbuild[id_site].site;
// esbuild?.watch();
// }
// for (const _mode of ["site", "server"]) {
// const mode = _mode as "site" | "server";
// const esbuild = code.esbuild[id_site][mode];
// if (esbuild) {
// try {
// await esbuild.rebuild();
// } catch (e: any) {
// await codeError(id_site, e.message, mode);
// }
// }
// }
};
const codeError = async (
id_site: string,
error: string,
mode: "server" | "site"
) => {
const path = code.path(
id_site,
"site",
"src",
mode === "server" ? "server.log" : "index.log"
);
await Bun.write(path, error);
};

View File

@ -29,46 +29,42 @@ const serverMain = () => ({
init(site_id: string) { init(site_id: string) {
clearTimeout(this.init_timeout); clearTimeout(this.init_timeout);
this.init_timeout = setTimeout(async () => { this.init_timeout = setTimeout(async () => {
const server_src_path = code.path(site_id, "server", "build", "index.js"); // const server_src_path = code.path(site_id, "server", "build", "index.js");
try { // try {
delete require.cache[server_src_path]; // delete require.cache[server_src_path];
const svr = require(server_src_path); // const svr = require(server_src_path);
// if (svr && typeof svr.server === "object") {
if (svr && typeof svr.server === "object") { // this.handler[site_id] = svr.server;
this.handler[site_id] = svr.server; // this.handler[site_id].site_id = site_id;
this.handler[site_id].site_id = site_id; // if (typeof svr.server.init === "function") {
// svr.server.init({});
if (typeof svr.server.init === "function") { // }
svr.server.init({}); // Bun.write(
} // Bun.file(code.path(site_id, "site", "src", "server.log")),
// ""
Bun.write( // );
Bun.file(code.path(site_id, "site", "src", "server.log")), // } else {
"" // const file = await Bun.file(server_src_path).text();
); // const log_path = code.path(site_id, "site", "src", "server.log");
} else { // if (file.length === 0) {
const file = await Bun.file(server_src_path).text(); // await Bun.write(Bun.file(log_path), "server.ts is empty");
const log_path = code.path(site_id, "site", "src", "server.log"); // } else {
// await Bun.write(
if (file.length === 0) { // Bun.file(log_path),
await Bun.write(Bun.file(log_path), "server.ts is empty"); // "server.ts does not return server object"
} else { // );
await Bun.write( // }
Bun.file(log_path), // }
"server.ts does not return server object" // } catch (e: any) {
); // const file = await Bun.file(server_src_path).text();
} // const log_path = code.path(site_id, "site", "src", "server.log");
} // if (file.length === 0) {
} catch (e: any) { // await Bun.write(Bun.file(log_path), "server.ts is empty");
const file = await Bun.file(server_src_path).text(); // } else {
const log_path = code.path(site_id, "site", "src", "server.log"); // await Bun.write(Bun.file(log_path), e.message);
if (file.length === 0) { // console.log(`Failed to init server ${site_id}\n`, log_path);
await Bun.write(Bun.file(log_path), "server.ts is empty"); // }
} else { // }
await Bun.write(Bun.file(log_path), e.message);
console.log(`Failed to init server ${site_id}\n`, log_path);
}
}
}, 10); }, 10);
}, },
async http( async http(

View File

@ -3,6 +3,7 @@ import { Logger } from "pino";
import { RadixRouter } from "radix3"; import { RadixRouter } from "radix3";
import { syncronize } from "y-pojo"; import { syncronize } from "y-pojo";
import type * as Y from "yjs"; import type * as Y from "yjs";
//@ts-ignore
import { PrismaClient } from "../../../app/db/db"; import { PrismaClient } from "../../../app/db/db";
import { WSData } from "../server/create"; import { WSData } from "../server/create";
import { import {
@ -14,7 +15,6 @@ import { dbProxy } from "../../../app/web/src/base/load/db/db-proxy";
type SingleRoute = { type SingleRoute = {
url: string; url: string;
args: string[]; args: string[];
raw: boolean;
fn: (...arg: any[]) => Promise<any>; fn: (...arg: any[]) => Promise<any>;
path: string; path: string;
}; };