From 843e10ccb54b09c6698ca73e87e749cb8ddd0ad7 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 23 Apr 2026 12:50:45 +0000 Subject: [PATCH 1/4] perf: optimize wipeDir recursively using Promise.all Co-authored-by: megawron <52606827+megawron@users.noreply.github.com> --- WebContainerGitService.js | 22 ++++++----- benchmark_wipe.js | 78 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 10 deletions(-) create mode 100644 benchmark_wipe.js diff --git a/WebContainerGitService.js b/WebContainerGitService.js index 166b15f..fc10a0e 100644 --- a/WebContainerGitService.js +++ b/WebContainerGitService.js @@ -193,16 +193,18 @@ export class WebContainerGitService { async wipeDir(dir) { try { const entries = await this.fs.readdir(dir); - for (const entry of entries) { - const path = `${dir}/${entry}`; - const stat = await this.fs.stat(path); - if (stat.isDirectory()) { - await this.wipeDir(path); - await this.fs.rmdir(path); - } else { - await this.fs.unlink(path); - } - } + await Promise.all( + entries.map(async (entry) => { + const path = `${dir}/${entry}`; + const stat = await this.fs.stat(path); + if (stat.isDirectory()) { + await this.wipeDir(path); + await this.fs.rmdir(path); + } else { + await this.fs.unlink(path); + } + }) + ); } catch (e) { // Base directory likely doesn't exist yet } diff --git a/benchmark_wipe.js b/benchmark_wipe.js new file mode 100644 index 0000000..17aca32 --- /dev/null +++ b/benchmark_wipe.js @@ -0,0 +1,78 @@ +import fs from 'fs'; +import path from 'path'; + +async function generateDummyDir(dirPath, depth, filesPerDir) { + await fs.promises.mkdir(dirPath, { recursive: true }).catch(() => {}); + if (depth === 0) return; + + const promises = []; + for (let i = 0; i < filesPerDir; i++) { + const fileNum = i; + promises.push(fs.promises.writeFile(path.join(dirPath, `file_${fileNum}.txt`), `hello ${fileNum}`)); + } + for (let i = 0; i < filesPerDir; i++) { + const subDir = path.join(dirPath, `dir_${i}`); + promises.push(generateDummyDir(subDir, depth - 1, filesPerDir)); + } + await Promise.all(promises); +} + +// Current implementation +async function wipeDirOriginal(dir) { + try { + const entries = await fs.promises.readdir(dir); + for (const entry of entries) { + const p = path.join(dir, entry); + const stat = await fs.promises.stat(p); + if (stat.isDirectory()) { + await wipeDirOriginal(p); + await fs.promises.rmdir(p); + } else { + await fs.promises.unlink(p); + } + } + } catch (e) { + } +} + +// Optimized implementation +async function wipeDirOptimized(dir) { + try { + const entries = await fs.promises.readdir(dir); + await Promise.all(entries.map(async (entry) => { + const p = path.join(dir, entry); + const stat = await fs.promises.stat(p); + if (stat.isDirectory()) { + await wipeDirOptimized(p); + await fs.promises.rmdir(p); + } else { + await fs.promises.unlink(p); + } + })); + } catch (e) { + } +} + +async function runBenchmark() { + const dir1 = './testdir1'; + const dir2 = './testdir2'; + + console.log("Generating dummy directories..."); + await generateDummyDir(dir1, 4, 5); // 5 files + 5 dirs, depth 4 + await generateDummyDir(dir2, 4, 5); + console.log("Generation complete."); + + console.log("Testing original..."); + const t1 = performance.now(); + await wipeDirOriginal(dir1); + const t2 = performance.now(); + console.log(`Original: ${t2 - t1}ms`); + + console.log("Testing optimized..."); + const t3 = performance.now(); + await wipeDirOptimized(dir2); + const t4 = performance.now(); + console.log(`Optimized: ${t4 - t3}ms`); +} + +runBenchmark().catch(console.error); From 5705b1c25e7100fd0c939b97508d58f6dab77d7b Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 23 Apr 2026 13:23:50 +0000 Subject: [PATCH 2/4] fix: recursively copy directories in lib/ during build Co-authored-by: megawron <52606827+megawron@users.noreply.github.com> --- build.mjs | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/build.mjs b/build.mjs index 26ae01c..442b317 100644 --- a/build.mjs +++ b/build.mjs @@ -31,11 +31,25 @@ async function build() { // 3. Copy Static Libraries console.log("📂 Copying libraries..."); - const libs = await readdir("lib"); + const libs = await readdir("lib", { withFileTypes: true }); for (const lib of libs) { - const src = join("lib", lib); - const dest = join(DIST, "lib", lib); - await Bun.write(dest, Bun.file(src)); + const src = join("lib", lib.name); + const dest = join(DIST, "lib", lib.name); + if (lib.isDirectory()) { + await mkdir(dest, { recursive: true }); + // Very basic recursive copy for directories + const subLibs = await readdir(src, { recursive: true, withFileTypes: true }); + for (const sub of subLibs) { + if (sub.isFile()) { + const subSrc = join(sub.parentPath, sub.name); + const subDest = join(DIST, sub.parentPath, sub.name); + await mkdir(join(DIST, sub.parentPath), { recursive: true }); + await Bun.write(subDest, Bun.file(subSrc)); + } + } + } else { + await Bun.write(dest, Bun.file(src)); + } } // Extract the generated hashed file name from Bun's output From df595d1a3cc5a3ef642d5bc4f2e5f83cb7990d51 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 23 Apr 2026 13:33:55 +0000 Subject: [PATCH 3/4] fix: recursive directory copying in build.mjs for older node versions Co-authored-by: megawron <52606827+megawron@users.noreply.github.com> --- build.mjs | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/build.mjs b/build.mjs index 442b317..7546b38 100644 --- a/build.mjs +++ b/build.mjs @@ -38,14 +38,25 @@ async function build() { if (lib.isDirectory()) { await mkdir(dest, { recursive: true }); // Very basic recursive copy for directories - const subLibs = await readdir(src, { recursive: true, withFileTypes: true }); - for (const sub of subLibs) { - if (sub.isFile()) { - const subSrc = join(sub.parentPath, sub.name); - const subDest = join(DIST, sub.parentPath, sub.name); - await mkdir(join(DIST, sub.parentPath), { recursive: true }); - await Bun.write(subDest, Bun.file(subSrc)); - } + // Note: Node 18+ does not have recursive readdir natively unless node version >= 20.1 + // If CI is on Node < 20, recursive: true on readdir will fail. + const getFiles = async (dir) => { + const dirents = await readdir(dir, { withFileTypes: true }); + const files = await Promise.all(dirents.map((dirent) => { + const res = join(dir, dirent.name); + return dirent.isDirectory() ? getFiles(res) : res; + })); + return Array.prototype.concat(...files); + }; + + const allFiles = await getFiles(src); + for (const filePath of allFiles) { + // Create target dir based on relative path + const relativePath = filePath.substring("lib/".length); + const subDest = join(DIST, "lib", relativePath); + const parentDir = join(DIST, "lib", relativePath.substring(0, relativePath.lastIndexOf("/"))); + await mkdir(parentDir, { recursive: true }); + await Bun.write(subDest, Bun.file(filePath)); } } else { await Bun.write(dest, Bun.file(src)); From a282d53d94ff2691426dded784594b93324e1d7b Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 23 Apr 2026 13:57:36 +0000 Subject: [PATCH 4/4] fix: ensure WASM files are built before bundling in build.mjs Co-authored-by: megawron <52606827+megawron@users.noreply.github.com> --- build.mjs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/build.mjs b/build.mjs index 7546b38..75526e5 100644 --- a/build.mjs +++ b/build.mjs @@ -4,9 +4,38 @@ import { join } from "node:path"; const DIST = "dist"; const ASSETS = join(DIST, "assets"); +import { exec } from "node:child_process"; +import { promisify } from "node:util"; + +const execAsync = promisify(exec); + async function build() { console.log("🚀 Starting ZeroCMS Production Build (via Bun)..."); + // 0. Ensure Tagger WASM is built + console.log("🦀 Checking for Super Tagger WASM..."); + try { + await readdir("lib"); + let hasWasm = false; + let hasJs = false; + try { + const dirContents = await readdir("lib"); + hasWasm = dirContents.includes("zerocms_tagger_bg.wasm"); + hasJs = dirContents.includes("zerocms_tagger.js"); + } catch (e) {} + + if (!hasWasm || !hasJs) { + console.log("⚠️ WASM files missing in lib/. Building them now..."); + const buildOutput = await execAsync("bash scripts/build_tagger.sh"); + console.log(buildOutput.stdout); + } else { + console.log("✅ WASM files found."); + } + } catch (error) { + console.error("❌ Failed to build WASM tagger:", error); + process.exit(1); + } + // 1. Clean and Create Directories await rm(DIST, { recursive: true, force: true }); await mkdir(ASSETS, { recursive: true });