check point
This commit is contained in:
parent
20606a83ca
commit
8aa920ac52
|
|
@ -58,6 +58,7 @@ export const _ = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
const res = JSON.stringify(await parseTypeDef(path));
|
const res = JSON.stringify(await parseTypeDef(path));
|
||||||
await Bun.write(
|
await Bun.write(
|
||||||
dir.data(
|
dir.data(
|
||||||
|
|
@ -72,6 +73,7 @@ export const _ = {
|
||||||
"content-encoding": "gzip",
|
"content-encoding": "gzip",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
return new Response("{}", {
|
return new Response("{}", {
|
||||||
headers: { "content-type": "application/json" },
|
headers: { "content-type": "application/json" },
|
||||||
|
|
@ -79,18 +81,26 @@ export const _ = {
|
||||||
}
|
}
|
||||||
case "typings.d.ts": {
|
case "typings.d.ts": {
|
||||||
const build_path = dir.data(`/code/${site_id}/site/typings.d.ts`);
|
const build_path = dir.data(`/code/${site_id}/site/typings.d.ts`);
|
||||||
const file = Bun.file(build_path);
|
let file = Bun.file(build_path);
|
||||||
|
|
||||||
if (!(await file.exists())) {
|
if (!(await file.exists())) {
|
||||||
const root = `/code/${site_id}/site/src`;
|
const root = `/code/${site_id}/site/src`;
|
||||||
await initFrontEnd(root, site_id);
|
await initFrontEnd(root, site_id);
|
||||||
|
file = Bun.file(build_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (await file.exists()) {
|
||||||
const body = Bun.gzipSync(await file.arrayBuffer());
|
const body = Bun.gzipSync(await file.arrayBuffer());
|
||||||
|
|
||||||
return new Response(body, {
|
return new Response(body, {
|
||||||
headers: { "content-type": file.type, "content-encoding": "gzip" },
|
headers: {
|
||||||
|
"content-type": file.type,
|
||||||
|
"content-encoding": "gzip",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
return new Response("", { status: 403 });
|
||||||
|
}
|
||||||
case "code": {
|
case "code": {
|
||||||
const arr = pathname.split("/").slice(2);
|
const arr = pathname.split("/").slice(2);
|
||||||
const codepath = arr.join("/");
|
const codepath = arr.join("/");
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -10,7 +10,6 @@ export const parseTypeDef = async (path: string) => {
|
||||||
const ast = await parseFile(path, { syntax: "typescript" });
|
const ast = await parseFile(path, { syntax: "typescript" });
|
||||||
|
|
||||||
const exports = {} as Record<string, SingleExport[]>;
|
const exports = {} as Record<string, SingleExport[]>;
|
||||||
|
|
||||||
visit(ast, {
|
visit(ast, {
|
||||||
visitWithPath: {
|
visitWithPath: {
|
||||||
visitDecl(node, path) {
|
visitDecl(node, path) {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,10 @@ import { cleanPlugin } from "esbuild-clean-plugin";
|
||||||
import isEqual from "lodash.isequal";
|
import isEqual from "lodash.isequal";
|
||||||
import { appendFile } from "node:fs/promises";
|
import { appendFile } from "node:fs/promises";
|
||||||
import { code } from "../../code";
|
import { code } from "../../code";
|
||||||
|
import { user } from "../../../entity/user";
|
||||||
|
import { conns } from "../../../entity/conn";
|
||||||
|
import { SyncType } from "../../../type";
|
||||||
|
import { sendWS } from "../../../sync-handler";
|
||||||
|
|
||||||
const decoder = new TextDecoder();
|
const decoder = new TextDecoder();
|
||||||
export const initFrontEnd = async (
|
export const initFrontEnd = async (
|
||||||
|
|
@ -74,6 +78,22 @@ export const initFrontEnd = async (
|
||||||
await installDeps(root, res, id_site);
|
await installDeps(root, res, id_site);
|
||||||
} else {
|
} else {
|
||||||
await codeError(id_site, "");
|
await codeError(id_site, "");
|
||||||
|
|
||||||
|
const client_ids = new Set<string>();
|
||||||
|
user.active.findAll({ site_id: id_site }).forEach((e) => {
|
||||||
|
client_ids.add(e.client_id);
|
||||||
|
});
|
||||||
|
|
||||||
|
const now = Date.now();
|
||||||
|
client_ids.forEach((client_id) => {
|
||||||
|
const ws = conns.get(client_id)?.ws;
|
||||||
|
if (ws)
|
||||||
|
sendWS(ws, {
|
||||||
|
type: SyncType.Event,
|
||||||
|
event: "code_changes",
|
||||||
|
data: { ts: now, mode: "frontend" },
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,10 @@ import { watch } from "fs";
|
||||||
import { Glob } from "bun";
|
import { Glob } from "bun";
|
||||||
import { removeAsync } from "fs-jetpack";
|
import { removeAsync } from "fs-jetpack";
|
||||||
import { parseTypeDef } from "../../../../../util/parse-type-def";
|
import { parseTypeDef } from "../../../../../util/parse-type-def";
|
||||||
|
import { user } from "../../../entity/user";
|
||||||
|
import { conns } from "../../../entity/conn";
|
||||||
|
import { sendWS } from "../../../sync-handler";
|
||||||
|
import { SyncType } from "../../../type";
|
||||||
export const initTypings = async (
|
export const initTypings = async (
|
||||||
root: string,
|
root: string,
|
||||||
id_site: string,
|
id_site: string,
|
||||||
|
|
@ -21,9 +25,15 @@ export const initTypings = async (
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const typings_path = dir.data(`/code/${id_site}/site/typings.d.ts`);
|
||||||
|
const typings_file = Bun.file(typings_path);
|
||||||
|
|
||||||
|
if (!(await typings_file.exists())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
code.internal.typings[id_site] = {
|
code.internal.typings[id_site] = {
|
||||||
timeout: Date.now(),
|
timeout: Date.now(),
|
||||||
watch: watch(dir.data(`/code/${id_site}/site/typings.d.ts`)),
|
watch: watch(typings_path),
|
||||||
spawn: Bun.spawn({
|
spawn: Bun.spawn({
|
||||||
cmd: [
|
cmd: [
|
||||||
...`tsc --watch --moduleResolution node --emitDeclarationOnly --outFile ../typings.d.ts --declaration --noEmit false`.split(
|
...`tsc --watch --moduleResolution node --emitDeclarationOnly --outFile ../typings.d.ts --declaration --noEmit false`.split(
|
||||||
|
|
@ -69,6 +79,22 @@ export const initTypings = async (
|
||||||
dir.data(`/code/${id_site}/site/type_def.${file.lastModified}.json`),
|
dir.data(`/code/${id_site}/site/type_def.${file.lastModified}.json`),
|
||||||
res
|
res
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const client_ids = new Set<string>();
|
||||||
|
user.active.findAll({ site_id: id_site }).forEach((e) => {
|
||||||
|
client_ids.add(e.client_id);
|
||||||
|
});
|
||||||
|
|
||||||
|
const now = Date.now();
|
||||||
|
client_ids.forEach((client_id) => {
|
||||||
|
const ws = conns.get(client_id)?.ws;
|
||||||
|
if (ws)
|
||||||
|
sendWS(ws, {
|
||||||
|
type: SyncType.Event,
|
||||||
|
event: "code_changes",
|
||||||
|
data: { ts: now, mode: "typings" },
|
||||||
|
});
|
||||||
|
});
|
||||||
}, 180);
|
}, 180);
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,28 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["./lib/*"],
|
"lib/*": [
|
||||||
"app/*": ["./app/*"],
|
"./lib/*"
|
||||||
"server/*": ["./server/*"]
|
],
|
||||||
|
"app/*": [
|
||||||
|
"./app/*"
|
||||||
|
],
|
||||||
|
"server/*": [
|
||||||
|
"./server/*"
|
||||||
|
],
|
||||||
|
"@/*": [
|
||||||
|
"./lib/*"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"lib": ["ESNext", "DOM"],
|
"lib": [
|
||||||
|
"ESNext",
|
||||||
|
"DOM"
|
||||||
|
],
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"moduleResolution": "bundler",
|
|
||||||
"moduleDetection": "force",
|
"moduleDetection": "force",
|
||||||
"declaration": true,
|
"moduleResolution": "Node",
|
||||||
"outFile": "types.d.ts",
|
"noEmit": true,
|
||||||
"emitDeclarationOnly": true,
|
|
||||||
"composite": true,
|
"composite": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"downlevelIteration": true,
|
"downlevelIteration": true,
|
||||||
|
|
@ -21,6 +31,9 @@
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"typeRoots": ["./node_modules/@types", "./lib/types"]
|
"typeRoots": [
|
||||||
|
"./node_modules/@types",
|
||||||
|
"./lib/types"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { PG } from "./ed-global";
|
import { PG } from "./ed-global";
|
||||||
|
|
||||||
export const loadCode = async (p: PG, ts?: number) => {
|
export const loadFrontEnd = async (p: PG, ts?: number) => {
|
||||||
const id_site = p.site.id;
|
const id_site = p.site.id;
|
||||||
const url = `/prod/${id_site}/_prasi/code/index.js?ts=${ts}`;
|
const url = `/prod/${id_site}/_prasi/code/index.js?ts=${ts}`;
|
||||||
const fn = new Function(
|
const fn = new Function(
|
||||||
|
|
@ -11,7 +11,25 @@ import("${url}")
|
||||||
.then(callback)`
|
.then(callback)`
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
Promise.all([
|
await new Promise<any>((resolve) => {
|
||||||
|
try {
|
||||||
|
fn((exports: any) => {
|
||||||
|
const w = window as any;
|
||||||
|
for (const [k, v] of Object.entries(exports)) {
|
||||||
|
w[k] = v;
|
||||||
|
p.site_exports[k] = v;
|
||||||
|
}
|
||||||
|
resolve(exports);
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.log("Failed to load site code", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (e) {}
|
||||||
|
};
|
||||||
|
export const loadTypings = async (p: PG) => {
|
||||||
|
const id_site = p.site.id;
|
||||||
|
await Promise.all([
|
||||||
fetch(`/prod/${id_site}/_prasi/typings.d.ts`)
|
fetch(`/prod/${id_site}/_prasi/typings.d.ts`)
|
||||||
.catch(() => {})
|
.catch(() => {})
|
||||||
.then(async (res) => {
|
.then(async (res) => {
|
||||||
|
|
@ -28,24 +46,13 @@ import("${url}")
|
||||||
p.render();
|
p.render();
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
new Promise<any>((resolve) => {
|
|
||||||
try {
|
|
||||||
fn((exports: any) => {
|
|
||||||
const w = window as any;
|
|
||||||
for (const [k, v] of Object.entries(exports)) {
|
|
||||||
w[k] = v;
|
|
||||||
p.site_exports[k] = v;
|
|
||||||
}
|
|
||||||
resolve(exports);
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
console.log("Failed to load site code", e);
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
]);
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const loadCode = async (p: PG, ts?: number) => {
|
||||||
|
try {
|
||||||
|
await Promise.all([loadTypings(p), loadFrontEnd(p, ts)]);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("Failed to load site code", e);
|
console.log("Failed to load site code", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -202,6 +202,7 @@ export const EDGlobal = {
|
||||||
code: {} as Record<string, { doc: null | DCode }>,
|
code: {} as Record<string, { doc: null | DCode }>,
|
||||||
global_prop: [] as string[],
|
global_prop: [] as string[],
|
||||||
ui: {
|
ui: {
|
||||||
|
monaco: null as any,
|
||||||
comp_editable: localStorage.getItem("prasi-comp-editable") === "yes",
|
comp_editable: localStorage.getItem("prasi-comp-editable") === "yes",
|
||||||
zoom: localStorage.zoom || "100%",
|
zoom: localStorage.zoom || "100%",
|
||||||
side: { prop: true },
|
side: { prop: true },
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@ import { reloadPage } from "./ed-route";
|
||||||
import { loadSite } from "./ed-site";
|
import { loadSite } from "./ed-site";
|
||||||
import { updateComponentMeta } from "./comp/load";
|
import { updateComponentMeta } from "./comp/load";
|
||||||
import { createRouter, RadixRouter } from "radix3";
|
import { createRouter, RadixRouter } from "radix3";
|
||||||
import { loadCode } from "./code-loader";
|
import { loadCode, loadFrontEnd, loadTypings } from "./code-loader";
|
||||||
|
import { registerSiteTypings } from "../../../utils/script/typings";
|
||||||
|
|
||||||
const decoder = new TextDecoder();
|
const decoder = new TextDecoder();
|
||||||
|
|
||||||
|
|
@ -183,8 +184,16 @@ export const edInitSync = (p: PG) => {
|
||||||
}
|
}
|
||||||
p.render();
|
p.render();
|
||||||
},
|
},
|
||||||
async code_changes({ ts }) {
|
async code_changes({ ts, mode }) {
|
||||||
await loadCode(p, ts);
|
if (mode === "frontend") {
|
||||||
|
await loadFrontEnd(p, ts);
|
||||||
|
} else {
|
||||||
|
console.log("Code updated");
|
||||||
|
await loadTypings(p);
|
||||||
|
if (p.ui.monaco) {
|
||||||
|
registerSiteTypings(p.ui.monaco, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
await treeRebuild(p);
|
await treeRebuild(p);
|
||||||
p.render();
|
p.render();
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -52,10 +52,15 @@ export const EdScriptMonaco: FC<{}> = () => {
|
||||||
let val = "";
|
let val = "";
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
|
p.ui.monaco = null;
|
||||||
p.script.do_edit = async () => {};
|
p.script.do_edit = async () => {};
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
if (local.monaco) {
|
||||||
|
p.ui.monaco = local.monaco;
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
clearTimeout(scriptEdit.timeout);
|
clearTimeout(scriptEdit.timeout);
|
||||||
(async () => {
|
(async () => {
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ export const jsMount = async (editor: MonacoEditor, monaco: Monaco, p?: PG) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const compilerOptions: CompilerOptions = {
|
const compilerOptions: CompilerOptions = {
|
||||||
jsx: monaco.languages.typescript.JsxEmit.ReactNative,
|
jsx: monaco.languages.typescript.JsxEmit.ReactJSX,
|
||||||
jsxFactory: "React.createElement",
|
jsxFactory: "React.createElement",
|
||||||
jsxFragmentFactory: "React.Fragment",
|
jsxFragmentFactory: "React.Fragment",
|
||||||
target: monaco.languages.typescript.ScriptTarget.ES2015,
|
target: monaco.languages.typescript.ScriptTarget.ES2015,
|
||||||
|
|
|
||||||
|
|
@ -8,16 +8,12 @@ type Monaco = Parameters<OnMount>[1];
|
||||||
|
|
||||||
const map = new WeakMap<any>();
|
const map = new WeakMap<any>();
|
||||||
|
|
||||||
export const monacoTypings = async (
|
export const registerSiteTypings = (
|
||||||
|
monaco: Monaco,
|
||||||
p: {
|
p: {
|
||||||
site_dts: string;
|
site_dts: string;
|
||||||
site_dts_entry: any;
|
site_dts_entry: any;
|
||||||
site: { api_url: string };
|
}
|
||||||
site_exports: Record<string, any>;
|
|
||||||
script: { siteTypes: Record<string, string> };
|
|
||||||
},
|
|
||||||
monaco: Monaco,
|
|
||||||
prop: { values: Record<string, any>; types: Record<string, string> }
|
|
||||||
) => {
|
) => {
|
||||||
if (p.site_dts) {
|
if (p.site_dts) {
|
||||||
register(monaco, p.site_dts, "ts:site.d.ts");
|
register(monaco, p.site_dts, "ts:site.d.ts");
|
||||||
|
|
@ -38,7 +34,20 @@ export const monacoTypings = async (
|
||||||
"ts:active_global.d.ts"
|
"ts:active_global.d.ts"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const monacoTypings = async (
|
||||||
|
p: {
|
||||||
|
site_dts: string;
|
||||||
|
site_dts_entry: any;
|
||||||
|
site: { api_url: string };
|
||||||
|
site_exports: Record<string, any>;
|
||||||
|
script: { siteTypes: Record<string, string> };
|
||||||
|
},
|
||||||
|
monaco: Monaco,
|
||||||
|
prop: { values: Record<string, any>; types: Record<string, string> }
|
||||||
|
) => {
|
||||||
|
registerSiteTypings(monaco, p);
|
||||||
if (!map.has(prop.values)) {
|
if (!map.has(prop.values)) {
|
||||||
map.set(prop.values, true);
|
map.set(prop.values, true);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -94,15 +103,19 @@ declare module "ts:prisma" {
|
||||||
monaco.languages.typescript.typescriptDefaults.setExtraLibs([
|
monaco.languages.typescript.typescriptDefaults.setExtraLibs([
|
||||||
{
|
{
|
||||||
filePath: "react.d.ts",
|
filePath: "react.d.ts",
|
||||||
content: await loadText(
|
content: `declare module "react" {
|
||||||
"https://cdn.jsdelivr.net/npm/@types/react@18.2.0/index.d.ts"
|
${await loadText("https://cdn.jsdelivr.net/npm/@types/react@18.3.1/index.d.ts")}
|
||||||
),
|
}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
filePath: "jsx-runtime.d.ts",
|
filePath: "jsx-runtime.d.ts",
|
||||||
content: await loadText(
|
content: `declare module "react/jsx-runtime" {
|
||||||
"https://cdn.jsdelivr.net/npm/@types/react@18.2.0/jsx-runtime.d.ts"
|
${(
|
||||||
),
|
await loadText(
|
||||||
|
"https://cdn.jsdelivr.net/npm/@types/react@18.3.1/jsx-runtime.d.ts"
|
||||||
|
)
|
||||||
|
).replaceAll('from "./"', 'from "react"')}
|
||||||
|
}`,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,7 @@ export const clientStartSync = async (arg: {
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
) => void;
|
) => void;
|
||||||
code_changes: (arg: { ts: number }) => void;
|
code_changes: (arg: { ts: number; mode: "frontend" | "typings" }) => void;
|
||||||
disconnected: () => { reconnect: boolean };
|
disconnected: () => { reconnect: boolean };
|
||||||
opened: () => void;
|
opened: () => void;
|
||||||
shakehand: (client_id: string) => void;
|
shakehand: (client_id: string) => void;
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ import { ensureNotRunning } from "./utils/ensure";
|
||||||
import { g } from "./utils/global";
|
import { g } from "./utils/global";
|
||||||
import { createLogger } from "./utils/logger";
|
import { createLogger } from "./utils/logger";
|
||||||
import { preparePrisma } from "./utils/prisma";
|
import { preparePrisma } from "./utils/prisma";
|
||||||
// import "../docker-prep";
|
|
||||||
|
|
||||||
g.status = "init";
|
g.status = "init";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,11 @@ export const ${name}: SAction${saction} = async function (
|
||||||
index_js.push(`export * from "./${name}";`);
|
index_js.push(`export * from "./${name}";`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const existing = await Bun.file(
|
||||||
|
dir.path(`app/srv/ws/sync/actions/index.ts`)
|
||||||
|
).text();
|
||||||
|
|
||||||
|
if (existing !== index_js.join("\n")) {
|
||||||
await writeAsync(
|
await writeAsync(
|
||||||
dir.path(`app/srv/ws/sync/actions/index.ts`),
|
dir.path(`app/srv/ws/sync/actions/index.ts`),
|
||||||
index_js.join("\n")
|
index_js.join("\n")
|
||||||
|
|
@ -61,4 +66,5 @@ export const SyncActionPaths = ${JSON.stringify(paths, null, 2)};
|
||||||
if ((await readAsync(path)) !== content) {
|
if ((await readAsync(path)) !== content) {
|
||||||
await writeAsync(path, content);
|
await writeAsync(path, content);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue