wip fix code

This commit is contained in:
Rizky 2024-04-29 20:42:30 +07:00
parent 34a356ccbd
commit d6d62c7df0
29 changed files with 596 additions and 363 deletions

View File

@ -1,5 +1,5 @@
import { apiContext } from "../../../pkgs/core/server/api/api-ctx";
import { code } from "../ws/sync/editor/code/util-code";
import { code } from "../ws/sync/code/code";
export const _ = {
url: "/nova-load/:mode/:id_site/**",

View File

@ -1,11 +1,11 @@
import { apiContext } from "service-srv";
import { code } from "../ws/sync/editor/code/util-code";
import fs from "fs";
import path from "path";
import { gzipAsync } from "../ws/sync/entity/zlib";
import { validate } from "uuid";
import { dir } from "dir";
import { existsAsync, readAsync } from "fs-jetpack";
import { code } from "../ws/sync/code/code";
export const _ = {
url: "/prod-zip/:site_id",

View File

@ -2,8 +2,8 @@ import { dir } from "dir";
import { apiContext } from "service-srv";
import { validate } from "uuid";
import { prodIndex } from "../util/prod-index";
import { code } from "../ws/sync/editor/code/util-code";
import { gzipAsync } from "../ws/sync/entity/zlib";
import { code } from "../ws/sync/code/code";
export const _ = {
url: "/prod/:site_id/**",
@ -20,6 +20,8 @@ export const _ = {
if (!validate(site_id))
return new Response("site not found", { status: 403 });
code;
if (pathname.startsWith("_prasi")) {
const action = pathname.split("/")[1];

File diff suppressed because one or more lines are too long

View File

@ -119,7 +119,7 @@ export const SyncActions = {
| { type: "startup-check" }
| { type: "startup-run" }
| { type: "startup-stop" }
| { type: "push-typings"; body: Uint8Array; hash: number }
// | { type: "push-typings"; body: Uint8Array; hash: number }
| { type: "check-typings"; hash: number }
))
| { type: "flush-page-cache"; page_id: string }

View File

@ -1,7 +1,6 @@
import { Subprocess, spawn } from "bun";
import { waitUntil } from "web-utils";
import { SAction } from "../actions";
import { code, codeGlobalTypings } from "../editor/code/util-code";
import { docs } from "../entity/docs";
import { snapshot } from "../entity/snapshot";
import { SyncConnection } from "../type";
@ -9,6 +8,7 @@ import { dirAsync } from "fs-jetpack";
import path from "path";
import { gunzipAsync } from "../entity/zlib";
import { prismaExtendType } from "../../../../web/src/utils/script/prisma-extend";
import { code } from "../code/code";
const decoder = new TextDecoder();
const code_startup = {
@ -84,41 +84,41 @@ export const code_action: SAction["code"]["action"] = async function (
} catch (e) {}
return { type: "check-typings", hash: false };
}
case "push-typings": {
const dir = code.path(arg.site_id, "site", "src", "typings");
await dirAsync(dir);
await dirAsync(path.join(dir, "runtime"));
Bun.write(Bun.file(path.join(dir, "hash")), arg.hash.toString());
const res = JSON.parse(decoder.decode(await gunzipAsync(arg.body)));
await Bun.write(Bun.file(path.join(dir, "api.d.ts")), res.api);
await Bun.write(
Bun.file(path.join(dir, "prisma.d.ts")),
res.prisma["prisma.d.ts"]
);
await Bun.write(
Bun.file(path.join(dir, "runtime/index.d.ts")),
res.prisma["runtime/index.d.ts"]
);
await Bun.write(
Bun.file(path.join(dir, "runtime/library.d.ts")),
res.prisma["runtime/library.d.ts"]
);
await Bun.write(
Bun.file(path.join(dir, "global.d.ts")),
codeGlobalTypings.replace(
`declare global {`,
`declare global {
const db: prisma.PrismaClient & ${prismaExtendType};
`
)
);
// case "push-typings": {
// const dir = code.path(arg.site_id, "site", "src", "typings");
// await dirAsync(dir);
// await dirAsync(path.join(dir, "runtime"));
// Bun.write(Bun.file(path.join(dir, "hash")), arg.hash.toString());
// const res = JSON.parse(decoder.decode(await gunzipAsync(arg.body)));
// await Bun.write(Bun.file(path.join(dir, "api.d.ts")), res.api);
// await Bun.write(
// Bun.file(path.join(dir, "prisma.d.ts")),
// res.prisma["prisma.d.ts"]
// );
// await Bun.write(
// Bun.file(path.join(dir, "runtime/index.d.ts")),
// res.prisma["runtime/index.d.ts"]
// );
// await Bun.write(
// Bun.file(path.join(dir, "runtime/library.d.ts")),
// res.prisma["runtime/library.d.ts"]
// );
// await Bun.write(
// Bun.file(path.join(dir, "global.d.ts")),
// codeGlobalTypings.replace(
// `declare global {`,
// `declare global {
// const db: prisma.PrismaClient & ${prismaExtendType};
// `
// )
// );
Bun.spawn({
cmd: ["chmod", "-R", "777", "."],
cwd: code.path(arg.site_id, "site", "src"),
});
// Bun.spawn({
// cmd: ["chmod", "-R", "777", "."],
// cwd: code.path(arg.site_id, "site", "src"),
// });
break;
}
// break;
// }
}
};

View File

@ -1,5 +1,4 @@
import { SAction } from "../actions";
import { prepCodeSnapshot } from "../editor/code/prep-code";
import { SyncConnection } from "../type";
export const code_load: SAction["code"]["load"] = async function (
@ -7,7 +6,5 @@ export const code_load: SAction["code"]["load"] = async function (
site_id,
type
) {
const snap = await prepCodeSnapshot(site_id, "site");
return { id: site_id };
};

View File

@ -2,7 +2,7 @@ import { validate } from "uuid";
import { ESite } from "../../../../web/src/nova/ed/logic/ed-global";
import { SAction } from "../actions";
import { SyncConnection } from "../type";
import { prepCodeSnapshot } from "../editor/code/prep-code";
import { code } from "../code/code";
export const site_load: SAction["site"]["load"] = async function (
this: SyncConnection,
@ -13,6 +13,8 @@ export const site_load: SAction["site"]["load"] = async function (
if (site) {
if (this.conf) this.conf.site_id = site.id;
code.init(site.id, "init site_load");
const config =
typeof site.config === "object" && site.config
? { api_url: (site.config as any).api_url || "" }
@ -43,8 +45,6 @@ export const site_load: SAction["site"]["load"] = async function (
}
}
const code = await prepCodeSnapshot(site.id, "site");
return {
id: site.id,
name: site.name,
@ -58,7 +58,6 @@ export const site_load: SAction["site"]["load"] = async function (
meta: undefined,
entry: [],
},
code_ts: code.ts,
};
}
}

View File

@ -0,0 +1,37 @@
import { dir } from "dir";
import { initFrontEnd } from "./parts/init/frontend";
import { initServer } from "./parts/init/server";
import { initTypings } from "./parts/init/typings";
import { codeInternal } from "./parts/internal";
import { ensureLib } from "./utlis/ensure-lib";
import { ensure } from "./utlis/ensure";
export const code = {
internal: codeInternal,
async init(id_site: string, note: string) {
const { frontend, server, typings } = this.internal;
if (!frontend[id_site] || !server[id_site] || !typings[id_site]) {
const root = `/code/${id_site}/site/src`;
if (!frontend[id_site]) await initFrontEnd(root, id_site);
if (!server[id_site]) await initServer(root, id_site);
if (!typings[id_site]) await initTypings(root, id_site);
await ensureLib(root, id_site);
await ensure(`${root}/index.tsx`, ``);
}
},
path(
id_site: string,
mode: "site" | "server",
type: "src" | "build" | "build_cache",
path?: string
) {
let file_path = "";
if (path) {
file_path = path[0] === "/" ? path : `/${path}`;
}
return dir.data(`/code/${id_site}/${mode}/${type}${file_path}`);
},
};

View File

@ -0,0 +1,10 @@
import { code } from "../../code";
export const initFrontEnd = async (root: string, id_site: string) => {
const existing = code.internal.frontend[id_site];
if (existing) {
await existing.dispose();
}
code.internal.frontend[id_site] = true as any;
};

View File

@ -0,0 +1,88 @@
import { context } from "esbuild";
import { code } from "../../code";
import { ensure } from "../../utlis/ensure";
import { dir } from "dir";
import { dirAsync, removeAsync, existsAsync, writeAsync } from "fs-jetpack";
export const initServer = async (root: string, id_site: string) => {
const existing = code.internal.server[id_site];
if (existing) {
await existing.dispose();
}
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.internal.server[id_site] = await context({
absWorkingDir: dir.data(root),
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;
}`,
},
});
};

View File

@ -0,0 +1,5 @@
import { code } from "../../code";
export const initTypings = async (root_dir: string, id_site: string) => {
code.internal.typings[id_site] = true as any;
};

View File

@ -0,0 +1,25 @@
import { Subprocess } from "bun";
import type { BuildContext } from "esbuild";
const g = global as unknown as {
prasi_code: any;
};
type SITE_ID = string;
export const codeInternal = {
get server() {
if (!g.prasi_code) g.prasi_code = {};
if (!g.prasi_code.server) g.prasi_code.server = {};
return g.prasi_code.server as Record<SITE_ID, BuildContext>;
},
get frontend() {
if (!g.prasi_code) g.prasi_code = {};
if (!g.prasi_code.frontend) g.prasi_code.frontend = {};
return g.prasi_code.frontend as Record<SITE_ID, BuildContext>;
},
get typings() {
if (!g.prasi_code) g.prasi_code = {};
if (!g.prasi_code.typings) g.prasi_code.typings = {};
return g.prasi_code.typings as Record<SITE_ID, Subprocess>;
},
};

View File

@ -0,0 +1,2 @@
export * from "@/data";
export * from "@/exports";

View File

@ -0,0 +1,7 @@
import type {} from "./typings/global";
export const server: PrasiServer = {
async http({ req, handle, mode, url, index, server }) {
return await handle(req);
}
};

View File

@ -0,0 +1,26 @@
{
"compilerOptions": {
"paths": {
"@/*": ["./lib/*"],
"app/*": ["./app/*"],
"server/*": ["./server/*"]
},
"lib": ["ESNext", "DOM"],
"module": "esnext",
"target": "esnext",
"moduleResolution": "bundler",
"moduleDetection": "force",
"declaration": true,
"outFile": "types.d.ts",
"emitDeclarationOnly": true,
"composite": true,
"strict": true,
"downlevelIteration": true,
"skipLibCheck": true,
"jsx": "react-jsx",
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"allowJs": true,
"typeRoots": ["./node_modules/@types", "./lib/types"]
}
}

View File

@ -0,0 +1,68 @@
//@ts-ignore
import type * as SRVAPI from "gen/srv/api/srv";
import { Server, WebSocketHandler } from "bun";
import prisma from "./prisma";
declare global {
type Api = typeof SRVAPI;
type ApiName = keyof Api;
const api: { [k in ApiName]: Awaited<Api[k]["handler"]>["_"]["api"] } & {
_raw: any;
};
const db: prisma.PrismaClient & {
_batch: {
update: (
batch: {
table: string;
data: any;
where: any;
}[]
) => Promise<void>;
};
_schema: {
tables: () => Promise<string[]>;
columns: (table: string) => Promise<
Record<
string,
{
is_pk: boolean;
type: string;
optional: boolean;
db_type: string;
default?: any;
}
>
>;
rels: (table: string) => Promise<
Record<
string,
{
type: "has-many" | "has-one";
to: {
table: string;
fields: string[];
};
from: {
table: string;
fields: string[];
};
}
>
>;
};
};
type PrasiServer = {
ws?: WebSocketHandler<{ url: string }>;
http: (arg: {
url: { raw: URL; pathname: string };
req: Request;
server: Server;
mode: "dev" | "prod";
handle: (req: Request) => Promise<Response>;
index: { head: string[]; body: string[]; render: () => string };
prasi: { page_id?: string; params?: Record<string, any> };
}) => Promise<Response>;
init: (arg: { port?: number }) => Promise<void>;
};
}

View File

@ -0,0 +1,15 @@
import { $ } from "bun";
import { dir } from "dir";
import { exists, dirAsync } from "fs-jetpack";
export const ensureLib = async (src_dir: string, id_site: string) => {
if (!exists(dir.data(src_dir))) {
await dirAsync(dir.data(src_dir));
}
if (!exists(dir.data(`${src_dir}/lib`))) {
console.log(`${src_dir}/lib not found.`);
const _ = $.cwd(dir.data(src_dir));
await _`git clone https://github.com/avolut/prasi-lib lib`;
}
};

View File

@ -0,0 +1,14 @@
import { exists, dirAsync } from "fs-jetpack";
import { dirname } from "path";
import { dir } from "dir";
export const ensure = async (path: string, content: string) => {
const _path = dir.data(path);
const _dir = dirname(_path);
if (!exists(_dir)) {
await dirAsync(_dir);
}
if (!exists(_path)) {
await Bun.write(_path, content);
}
};

View File

@ -1,22 +1,7 @@
import globalExternals from "@fal-works/esbuild-plugin-global-externals";
import { style } from "@hyrious/esbuild-plugin-style";
import { context } from "esbuild";
import {
dirAsync,
existsAsync,
removeAsync,
writeAsync,
moveAsync,
} from "fs-jetpack";
import { server } from "./server-main";
import { code } from "./util-code";
import { user } from "../../entity/user";
import { conns } from "../../entity/conn";
import { SyncType } from "../../type";
import { Packr } from "msgpackr";
import { ServerWebSocket } from "bun";
import { Packr } from "msgpackr";
import { WSData } from "../../../../../../pkgs/core/server/create";
import { g } from "utils/global";
import { code } from "../../code/code";
const packr = new Packr({ structuredClone: true });
@ -25,267 +10,240 @@ const sendWS = (ws: ServerWebSocket<WSData>, msg: any) => {
};
export const codeBuild = async (id_site: any) => {
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"');
}
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 {
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 build_file = code.path(id_site, mode, "build", "index.js");
// const out = Bun.file(build_file);
// const src = (await out.text()).replace(
// "//# sourceMappingURL=index.js.map",
// `//# sourceMappingURL=/nova-load/code/${id_site}/${mode}/index.js.map`
// );
// // await Bun.write(out, src);
}
};
// const codeApplyChanges = (path: string, doc: DCode) => {
// const map = doc.getMap("map");
// const files = map.get("files");
// const dirs = readDirectoryRecursively(path);
// doc.transact(() => {
// files?.forEach((v, k) => {
// if (!dirs[k]) {
// files?.delete(k);
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() };
// }
// });
// for (const [k, v] of Object.entries(dirs)) {
// if (files) {
// files.set(k, v);
// }
// }
// });
// return doc;
// 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,

View File

@ -1,19 +0,0 @@
import { g } from "utils/global";
import { codeBuild } from "./build-code";
import { CodeMode, code, codeGlobalTypings } from "./util-code";
export const prepCodeSnapshot = async (id_site: string, mode: CodeMode) => {
await code
.prep(id_site, mode)
.new_file("index.tsx", "export const sample = 'hello_world'")
.new_file(
"package.json",
JSON.stringify({ name: `${mode}-${id_site}`, dependencies: {} }, null, 2)
)
.new_file("typings/global.d.ts", codeGlobalTypings)
.await();
await codeBuild(id_site);
return { ts: code.esbuild[id_site].site_ts };
};

View File

@ -1,13 +1,12 @@
import type { Server, WebSocketHandler, ServerWebSocket } from "bun";
import type { Server, WebSocketHandler } from "bun";
import { existsAsync } from "fs-jetpack";
import _fs from "node:fs/promises";
import { g } from "utils/global";
import { waitUntil } from "web-utils";
import { code } from "./util-code";
import { WSData } from "../../../../../../pkgs/core/server/create";
import { codeBuild } from "./build-code";
import { prodIndex } from "../../../../util/prod-index";
import { code } from "../../code/code";
import "./server-runtime";
const serverMain = () => ({
@ -61,10 +60,9 @@ const serverMain = () => ({
site_id: string,
arg: Parameters<Exclude<(typeof g)["server_hook"], undefined>>[0]
) {
if (!code.esbuild[site_id]) {
await codeBuild(site_id);
if (arg.url.pathname.endsWith("main.js")) {
code.init(site_id, "init http");
}
if (typeof this.handler[site_id] === "undefined") {
if (
await existsAsync(code.path(site_id, "server", "build", "index.js"))
@ -130,13 +128,11 @@ type PrasiServer = {
index: { head: string[]; body: string[]; render: () => string };
prasi: { page_id?: string; params?: Record<string, any> };
}) => Promise<Response>;
init?: () => Promise<void>;
init?: (arg: { port?: number }) => Promise<void>;
};
const glb = global as unknown as {
_server: ReturnType<typeof serverMain>;
};
if (!glb._server) {
glb._server = serverMain();
}
export const server = glb._server;

View File

@ -3,6 +3,7 @@ import { dir } from "dir";
import { BuildContext } from "esbuild";
import { dirAsync, exists, existsAsync, writeAsync } from "fs-jetpack";
import { dirname } from "path";
import { prismaExtendType } from "../../../../../web/src/utils/script/prisma-extend";
export type CodeBuild = {
server: BuildContext | null;
@ -11,7 +12,7 @@ export type CodeBuild = {
};
export type CodeMode = keyof CodeBuild;
export const code = {
const code = {
path(
id_site: string,
mode: CodeMode,
@ -69,6 +70,8 @@ declare global {
type Api = typeof SRVAPI;
type ApiName = keyof Api;
const api: { [k in ApiName]: Awaited<Api[k]["handler"]>["_"]["api"] } & { _raw: any };
const db: prisma.PrismaClient & ${prismaExtendType};
type PrasiServer = {
ws?: WebSocketHandler<{ url: string }>;
@ -81,7 +84,7 @@ declare global {
index: { head: string[]; body: string[]; render: () => string };
prasi: { page_id?: string; params?: Record<string, any> };
}) => Promise<Response>;
init: () => Promise<void>;
init: (arg: { port?: number }) => Promise<void>;
};
}
`;

View File

@ -24,7 +24,6 @@ export const EmptySite = {
meta: undefined as void | Record<string, IMeta>,
entry: [] as string[],
},
code_ts: 0,
};
export type ESite = typeof EmptySite;
@ -150,6 +149,7 @@ export const EDGlobal = {
sync: null as null | Awaited<ReturnType<typeof clientStartSync>>,
sync_assigned: false,
site: deepClone(EmptySite),
site_tstamp: Date.now(),
site_exports: {} as Record<string, any>,
site_dts: "",
script: {

View File

@ -62,7 +62,7 @@ export const applyEnv = async (p: PG) => {
w.api = apiProxy(p.site.config.api_url);
}
const url = `/prod/${p.site.id}/_prasi/code/index.js?ts=${p.site.code_ts}`;
const url = `/prod/${p.site.id}/_prasi/code/index.js?ts=${p.site_tstamp}`;
const fn = new Function("callback", `import("${url}").then(callback)`);
try {

View File

@ -41,8 +41,8 @@ export const createViLocal = (
const [_, set] = useState({});
const local = ref.current;
local.render = () => {
if ((window as any).prasiContext?.render) {
(window as any).prasiContext?.render();
if ((window as any).prasiContext.render) {
(window as any).prasiContext.render();
} else {
set({});
}

BIN
bun.lockb

Binary file not shown.

View File

@ -3,7 +3,7 @@
"module": "src/index.ts",
"type": "module",
"scripts": {
"dev": "bun run ./pkgs/core/index.ts dev",
"dev": "bun run --hot ./pkgs/core/index.ts dev",
"clean": "rm -rf data/lmdb && rm -rf app/static && rm -rf app/web/.parcel-cache",
"build": "bun run --silent ./pkgs/core/build.ts",
"build-site": "bun run --silent ./pkgs/core/build-site.ts",
@ -19,9 +19,6 @@
"app/*",
"pkgs/*"
],
"peerDependencies": {
"typescript": "^5.0.0"
},
"dependencies": {
"brotli-wasm": "^2.0.1",
"fdir": "^6.1.0",

View File

@ -17,7 +17,6 @@
"pino-pretty": "^10.2.3",
"radash": "^11.0.0",
"radix3": "^1.1.0",
"typescript": "^5.2.2",
"unzipper": "^0.10.14"
}
}