From 35c6f2fda0b5f11a1ac0a103dbf46bff3a746389 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Fri, 21 Aug 2026 09:17:19 +0000 Subject: [PATCH] fix: fall back to bun resolution on a node without import.meta.resolve Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_014bq66fSmaPvLtjnDPfMYcj --- backend/tests/bun_jobs.rs | 13 ++++--------- backend/windmill-worker/node_cjs_interop.js | 5 +++-- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/backend/tests/bun_jobs.rs b/backend/tests/bun_jobs.rs index e2fa85d246..dcfbf1d196 100644 --- a/backend/tests/bun_jobs.rs +++ b/backend/tests/bun_jobs.rs @@ -1279,15 +1279,10 @@ fn test_generate_bun_bundle_propagates_exit_status() { ); } -/// `//nodejs` bundles keep the packages installed under `node_modules` external, -/// so node — not bun — resolves them at runtime. Node's cjs-module-lexer cannot -/// see the named exports of a CommonJS package that builds `module.exports` -/// dynamically (lodash & co.), so a named import fails to instantiate and a -/// namespace import yields nothing but `default`. The bundle must import such a -/// package as a namespace and read the names off `default` instead, while -/// leaving alone anything node loads as ESM — including a package whose -/// conditional exports hand bun a different file than they hand node — so its -/// named imports stay the live bindings node gives them. +/// Pins the two halves of the `//nodejs` CommonJS interop: a package whose +/// exports only exist once it has run must resolve through `default`, and one +/// node loads as ESM — including through conditional exports that hand bun a +/// different file — must keep its named imports as live bindings. #[test] fn test_node_loader_cjs_named_export_interop() { use std::process::Command; diff --git a/backend/windmill-worker/node_cjs_interop.js b/backend/windmill-worker/node_cjs_interop.js index e8024fbd5e..4d8b0c7fda 100644 --- a/backend/windmill-worker/node_cjs_interop.js +++ b/backend/windmill-worker/node_cjs_interop.js @@ -129,7 +129,8 @@ function wmRewriteExternalImports(code, externals, jobDir, nodePath) { "throw new SyntaxError(`The requested module '${s}' does not provide an export named '${k}'`)};" + `var ${nsHelper}=(n)=>{let d=n.default;if(d==null||typeof d!=="object"&&typeof d!=="function")return n;` + `let t={},a=(o,k)=>Object.defineProperty(t,k,{get:()=>o[k],enumerable:!0,configurable:!0});` + - `for(let k of Object.keys(d))a(d,k);for(let k of Object.keys(n))a(n,k);return t};` + + `for(let k of Object.keys(d))a(d,k);for(let k of Object.keys(n))a(n,k);` + + `return new Proxy(t,{get:(x,k,r)=>k in x?Reflect.get(x,k,r):d[k],has:(x,k)=>k in x||k in d})};` + out + code.slice(cursor) ); @@ -142,7 +143,7 @@ function wmCommonJsSpecs(specs, jobDir, nodePath) { const commonjs = new Set(); let resolved = null; const probe = - "const out={};" + + "if(typeof import.meta.resolve!=='function')process.exit(3);const out={};" + "for(const s of JSON.parse(process.argv[1])){try{out[s]=import.meta.resolve(s)}catch(e){out[s]=null}}" + "console.log(JSON.stringify(out))"; try {