From 9cdc1765375c857e2434e8b76031bf6869282061 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Fri, 7 Nov 2025 23:10:21 +0000 Subject: [PATCH] fix(cli): add automatic handler of .node files for codebase bundler --- cli/src/commands/script/script.ts | 68 +++++++++++++++++++++++++------ cli/src/core/conf.ts | 1 + cli/src/utils/codebase.ts | 15 ++++--- 3 files changed, 67 insertions(+), 17 deletions(-) diff --git a/cli/src/commands/script/script.ts b/cli/src/commands/script/script.ts index 3903be6f71..1c95cb297d 100644 --- a/cli/src/commands/script/script.ts +++ b/cli/src/commands/script/script.ts @@ -180,6 +180,14 @@ export async function handleScriptMetadata( } } +export interface OutputFile { + path: string + contents: Uint8Array + hash: string + /** "contents" as text (changes automatically with "contents") */ + readonly text: string +} + export async function handleFile( path: string, workspace: Workspace, @@ -210,7 +218,9 @@ export async function handleFile( let bundleContent: string | Tarball | undefined = undefined; + let forceTar = false; if (codebase) { + let outputFiles: OutputFile[] = []; if (codebase.customBundler) { log.info(`Using custom bundler ${codebase.customBundler} for ${path}`); bundleContent = execSync( @@ -232,35 +242,42 @@ export async function handleFile( external: codebase.external, inject: codebase.inject, define: codebase.define, + loader: codebase.loader ?? { ".node": "file" }, + outdir: '/', platform: "node", packages: "bundle", target: format == "cjs" ? "node20.15.1" : "esnext", }); const endTime = performance.now(); bundleContent = out.outputFiles[0].text; + outputFiles = out.outputFiles; log.info( `Finished bundling ${path}: ${(bundleContent.length / 1024).toFixed( 0 )}kB (${(endTime - startTime).toFixed(0)}ms)` ); } - if (Array.isArray(codebase.assets) && codebase.assets.length > 0) { + if (outputFiles.length > 1) { const archiveNpm = await import("npm:@ayonli/jsext/archive"); log.info( - `Using the following asset configuration for ${path}: ${JSON.stringify( - codebase.assets - )}` + `Found multiple output files for ${path}, creating a tarball... ${outputFiles.map((file) => file.path).join(", ")}` ); + forceTar = true; const startTime = performance.now(); const tarball = new archiveNpm.Tarball(); + const mainPath = path.split(SEP).pop()?.split(".")[0] + ".js"; + const content = outputFiles.find((file) => file.path == "/" + mainPath)?.text ?? ''; + log.info(`Main content: ${content.length}chars`); tarball.append( - new File([bundleContent], "main.js", { type: "text/plain" }) + new File([content], "main.js", { type: "text/plain" }) ); - for (const asset of codebase.assets) { - const data = fs.readFileSync(asset.from); - const blob = new Blob([data], { type: "text/plain" }); - const file = new File([blob], asset.to); - tarball.append(file); + for (const file of outputFiles) { + if (file.path == "/" + mainPath) { + continue; + } + log.info(`Adding file: ${file.path.substring(1)}`); + const fil = new File([file.contents], file.path.substring(1)); + tarball.append(fil); } const endTime = performance.now(); log.info( @@ -269,6 +286,33 @@ export async function handleFile( ).toFixed(0)}kB (${(endTime - startTime).toFixed(0)}ms)` ); bundleContent = tarball; + } else { + if (Array.isArray(codebase.assets) && codebase.assets.length > 0) { + const archiveNpm = await import("npm:@ayonli/jsext/archive"); + log.info( + `Using the following asset configuration for ${path}: ${JSON.stringify( + codebase.assets + )}` + ); + const startTime = performance.now(); + const tarball = new archiveNpm.Tarball(); + tarball.append( + new File([bundleContent], "main.js", { type: "text/plain" }) + ); + for (const asset of codebase.assets) { + const data = fs.readFileSync(asset.from); + const blob = new Blob([data], { type: "text/plain" }); + const file = new File([blob], asset.to); + tarball.append(file); + } + const endTime = performance.now(); + log.info( + `Finished creating tarball for ${path}: ${( + tarball.size / 1024 + ).toFixed(0)}kB (${(endTime - startTime).toFixed(0)}ms)` + ); + bundleContent = tarball; + } } } let typed = opts?.skipScriptsMetadata @@ -325,7 +369,7 @@ export async function handleFile( } if (typed && codebase) { - typed.codebase = await codebase.getDigest(); + typed.codebase = await codebase.getDigest(forceTar); } const requestBodyCommon: NewScript = { @@ -352,7 +396,7 @@ export async function handleFile( concurrency_key: typed?.concurrency_key, debounce_key: typed?.debounce_key, debounce_delay_s: typed?.debounce_delay_s, - codebase: await codebase?.getDigest(), + codebase: await codebase?.getDigest(forceTar), timeout: typed?.timeout, on_behalf_of_email: typed?.on_behalf_of_email, }; diff --git a/cli/src/core/conf.ts b/cli/src/core/conf.ts index 5a56f97435..0a6dbe8167 100644 --- a/cli/src/core/conf.ts +++ b/cli/src/core/conf.ts @@ -99,6 +99,7 @@ export interface Codebase { external?: string[]; define?: { [key: string]: string }; inject?: string[]; + loader?: any, format?: "cjs" | "esm"; } diff --git a/cli/src/utils/codebase.ts b/cli/src/utils/codebase.ts index 36dfbb16ed..3391f6f795 100644 --- a/cli/src/utils/codebase.ts +++ b/cli/src/utils/codebase.ts @@ -2,7 +2,7 @@ import { Codebase, SyncOptions } from "../core/conf.ts"; import { log } from "../../deps.ts"; import { digestDir } from "./utils.ts"; -export type SyncCodebase = Codebase & { getDigest: () => Promise }; +export type SyncCodebase = Codebase & { getDigest: (forceTar?: boolean) => Promise }; export function listSyncCodebases( options: SyncOptions ): SyncCodebase[] { @@ -13,16 +13,21 @@ export function listSyncCodebases( } for (const codebase of options?.codebases ?? []) { let _digest: string | undefined = undefined; - const getDigest: () => Promise = async () => { - if (_digest == undefined) { + let alreadyPrinted = false; + const getDigest: (forceTar?: boolean) => Promise = async (forceTar?: boolean) => { + if (_digest == undefined || forceTar) { _digest = await digestDir( codebase.relative_path, JSON.stringify(codebase) ); - if (Array.isArray(codebase.assets) && codebase.assets.length > 0) { + if (forceTar || (Array.isArray(codebase.assets) && codebase.assets.length > 0)) { _digest += ".tar"; } - log.info(`Codebase ${codebase.relative_path}, digest: ${_digest}`); + if (!alreadyPrinted) { + alreadyPrinted = true; + log.info(`Codebase ${codebase.relative_path}, digest: ${_digest}`); + } + return _digest; } return _digest; };