diff --git a/app/srv/package.json b/app/srv/package.json index 902ffad4..37a72e01 100644 --- a/app/srv/package.json +++ b/app/srv/package.json @@ -6,6 +6,7 @@ "@hyrious/esbuild-plugin-style": "^0.3.5", "@node-rs/argon2": "^1.5.2", "@paralleldrive/cuid2": "^2.2.2", + "@parcel/watcher": "^2.4.1", "@types/lodash.isequal": "^4.5.8", "@types/mime-types": "^2.1.4", "esbuild": "^0.21.5", diff --git a/app/srv/ws/sync/code/parts/init/frontend.ts b/app/srv/ws/sync/code/parts/init/frontend.ts index 2382a544..444f1aeb 100644 --- a/app/srv/ws/sync/code/parts/init/frontend.ts +++ b/app/srv/ws/sync/code/parts/init/frontend.ts @@ -4,7 +4,6 @@ import { $ } from "bun"; import { dir } from "dir"; import { context, formatMessages } from "esbuild"; import { cleanPlugin } from "esbuild-clean-plugin"; -import { watch } from "fs"; import { existsAsync } from "fs-jetpack"; import { appendFile } from "node:fs/promises"; import { conns } from "../../../entity/conn"; @@ -12,6 +11,7 @@ import { user } from "../../../entity/user"; import { sendWS } from "../../../sync-handler"; import { SyncType } from "../../../type"; import { code } from "../../code"; +import { Watcher } from "../watcher"; const pending = {} as any; export const initFrontEnd = async ( @@ -50,83 +50,16 @@ export const initFrontEnd = async ( try { await isInstalling(id_site); - const broadcastLoading = async () => { - const client_ids = user.active - .findAll({ site_id: id_site }) - .map((e) => 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", status: "building" }, - }); - }); - }; + if (code.internal.frontend[id_site]?.watch) { + await code.internal.frontend[id_site].watch.close(); + } code.internal.frontend[id_site] = { - ...(code.internal.frontend[id_site] || {}), ctx: await initBuildCtx({ id_site, root }), timeout: null, rebuilding: false, + watch: new Watcher(dir.data(root), id_site), }; - - if (code.internal.frontend[id_site].watch) { - code.internal.frontend[id_site].watch.close(); - } - console.log("watching", dir.data(root)); - code.internal.frontend[id_site].watch = watch( - dir.data(root), - { - recursive: true, - persistent: true - }, - async (event, filename) => { - const fe = code.internal.frontend[id_site]; - const srv = code.internal.server[id_site]; - - if ( - filename?.startsWith("node_modules") || - filename?.startsWith("typings") || - filename?.endsWith(".log") - ) - return; - - console.log( - event, - filename, - typeof fe !== "undefined" && !fe.rebuilding - ? "start-rebuild" - : "rebuilding..." - ); - if ( - filename?.endsWith(".tsx") || - filename?.endsWith(".ts") || - filename?.endsWith(".css") || - filename?.endsWith(".html") - ) { - if (typeof fe !== "undefined" && !fe.rebuilding) { - fe.rebuilding = true; - clearTimeout(fe.timeout); - fe.timeout = setTimeout(async () => { - try { - broadcastLoading(); - await fe.ctx.rebuild(); - fe.rebuilding = false; - } catch (e: any) { - console.error(`Frontend failed rebuild (site: ${id_site})`); - console.error(e.message); - fe.rebuilding = false; - } - }, 500); - } - } - } - ); const fe = code.internal.frontend[id_site]; fe.rebuilding = true; try { diff --git a/app/srv/ws/sync/code/parts/internal.ts b/app/srv/ws/sync/code/parts/internal.ts index 1d313a31..2699a3b8 100644 --- a/app/srv/ws/sync/code/parts/internal.ts +++ b/app/srv/ws/sync/code/parts/internal.ts @@ -2,6 +2,7 @@ import Parcel from "@parcel/core"; import { Subprocess } from "bun"; import type { BuildContext } from "esbuild"; import { FSWatcher } from "fs"; +import { Watcher } from "./watcher"; const g = global as unknown as { prasi_code: any; }; @@ -24,7 +25,7 @@ export const codeInternal = { { ctx: BuildContext; timeout: any; - watch?: FSWatcher; + watch?: Watcher; rebuilding: boolean; npm?: Promise; } diff --git a/app/srv/ws/sync/code/parts/watcher.ts b/app/srv/ws/sync/code/parts/watcher.ts new file mode 100644 index 00000000..3a9788d6 --- /dev/null +++ b/app/srv/ws/sync/code/parts/watcher.ts @@ -0,0 +1,92 @@ +import watcher, { AsyncSubscription } from "@parcel/watcher"; +import { readdir } from "node:fs/promises"; +import { statSync } from "node:fs"; +import { join } from "path"; +import { code } from "../code"; +import { user } from "../../entity/user"; +import { conns } from "../../entity/conn"; +import { sendWS } from "../../sync-handler"; +import { SyncType } from "../../type"; +export class Watcher { + subcription = null as null | AsyncSubscription; + + constructor(path: string, id_site: string) { + this.init(path, id_site); + // watcher.subscribe(path, (err, events) => { + // console.log(events); + // }); + // watch( + // path, + // { + // recursive: true, + // persistent: true, + // }, + // async (event, filename) => { + // } + // ); + } + + async init(path: string, id_site: string) { + const broadcastLoading = async () => { + const client_ids = user.active + .findAll({ site_id: id_site }) + .map((e) => 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", status: "building" }, + }); + }); + }; + + this.subcription = await watcher.subscribe(path, (err, events) => { + for (const e of events) { + const filename = e.path.substring(path.length + 1); + if (e.type === "create" || e.type === "update") { + const fe = code.internal.frontend[id_site]; + if ( + filename?.startsWith("node_modules") || + filename?.startsWith("typings") || + filename?.endsWith(".log") + ) + return; + + if ( + filename?.endsWith(".tsx") || + filename?.endsWith(".ts") || + filename?.endsWith(".css") || + filename?.endsWith(".html") + ) { + if (typeof fe !== "undefined" && !fe.rebuilding) { + fe.rebuilding = true; + clearTimeout(fe.timeout); + fe.timeout = setTimeout(async () => { + try { + broadcastLoading(); + await fe.ctx.rebuild(); + fe.rebuilding = false; + } catch (e: any) { + console.error(`Frontend failed rebuild (site: ${id_site})`); + console.error(e.message); + fe.rebuilding = false; + } + }, 500); + } + } + } + } + }); + } + + async close() { + if (this.subcription) { + await this.subcription.unsubscribe(); + } + } +} diff --git a/bun.lockb b/bun.lockb index aba236dd..f35e3a41 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/dockerzip b/dockerzip index 02c8b7a3..bf243598 100644 Binary files a/dockerzip and b/dockerzip differ