Repository: denoland/deno
Pull request: fix(ext/node): provide CJS globals in worker_threads eval mode

## Summary
- When using `new Worker(code, { eval: true })` in `node:worker_threads`, Node.js evaluates the code as CommonJS, making `require()` available. Deno was wrapping the code in a `data:text/javascript` URL (ESM), causing `require is not defined` errors.
- Wraps eval worker code with CJS globals (`require`, `__filename`, `__dirname`, `module`, `exports`) by prepending ESM imports from `node:module` and `node:process`.
- Adds a spec test verifying `require("worker_threads")` works in eval workers.

Closes #27181
Closes #27167

## Test plan
- [x] New spec test `eval_cjs_require` passes — creates an eval worker using `require("worker_threads")` and verifies it can communicate back via `parentPort`
- [x] All existing `worker_threads` spec tests continue to pass
- [x] Manually verified the exact reproduction from the issue works

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Changed files:
filename: ext/node/polyfills/worker_threads.ts
patch: @@ -364,10 +364,22 @@ class NodeWorker extends EventEmitter {
 
     if (options?.eval) {
       const code = typeof specifier === "string"
-        ? encodeURIComponent(specifier)
+        ? specifier
         // deno-lint-ignore prefer-primordials
         : specifier.toString();
-      specifier = `data:text/javascript,${code}`;
+      // Node.js evaluates worker eval code as CommonJS, so we wrap
+      // the code to provide CJS globals (require, __filename, etc.)
+      // since the data: URL will be loaded as ESM.
+      const wrapped =
+        `import { createRequire as __cjsRequire } from "node:module";\n` +
+        `import { cwd as __cjsCwd } from "node:process";\n` +
+        `const require = __cjsRequire(__cjsCwd() + "/[worker eval]");\n` +
+        `const __filename = __cjsCwd() + "/[worker eval]";\n` +
+        `const __dirname = __cjsCwd();\n` +
+        `const module = { exports: {} };\n` +
+        `const exports = module.exports;\n` +
+        code;
+      specifier = `data:text/javascript,${encodeURIComponent(wrapped)}`;
     } else if (
       !(typeof specifier === "object" && specifier.protocol === "data:")
     ) {

filename: tests/specs/node/worker_threads/__test__.jsonc
patch: @@ -35,6 +35,12 @@
       },
       "output": "message_port_unref.out",
       "exitCode": 0
+    },
+    "eval_cjs_require": {
+      // Test for https://github.com/denoland/deno/issues/27181
+      "args": "run --quiet eval_cjs_require.mjs",
+      "output": "ok\n",
+      "exitCode": 0
     }
   }
 }

filename: tests/specs/node/worker_threads/eval_cjs_require.mjs
patch: @@ -0,0 +1,17 @@
+import { Worker } from "node:worker_threads";
+import { once } from "node:events";
+
+// Test that eval workers can use require() (CJS globals),
+// matching Node.js behavior where eval code runs as CommonJS.
+// See https://github.com/denoland/deno/issues/27181
+const worker = new Worker(
+  `
+const { parentPort } = require("worker_threads");
+parentPort.postMessage("ok");
+`,
+  { eval: true },
+);
+
+const [msg] = await once(worker, "message");
+console.log(msg);
+worker.terminate();