From 74cf11fd990b181ee9c12771b695429780f6cdf6 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 8 Jun 2026 14:06:13 +0000 Subject: [PATCH 1/2] fix(nodejs plugin): use .cjs for setup-corepack so it survives "type":"module" The corepack setup script added in #2845 uses CommonJS `require()`, but was named setup-corepack.js. When a project's root package.json sets `"type": "module"`, Node treats every `.js` file in the tree as an ES module, so running the script crashed the shell with: ReferenceError: require is not defined in ES module scope Rename the script to setup-corepack.cjs (and update the plugin's init_hook and create_files references) so Node always treats it as CommonJS regardless of the project's package.json type. Bump the plugin version 0.0.3 -> 0.0.4. Adds a regression test covering a package.json with "type": "module". Fixes #2856 --- plugins/nodejs.json | 6 +++--- .../{setup-corepack.js => setup-corepack.cjs} | 6 +++++- .../plugin/nodejs_corepack_autodetect.test.txt | 13 +++++++++++++ 3 files changed, 21 insertions(+), 4 deletions(-) rename plugins/nodejs/{setup-corepack.js => setup-corepack.cjs} (87%) diff --git a/plugins/nodejs.json b/plugins/nodejs.json index 3dc93c129e4..29a23152d1c 100644 --- a/plugins/nodejs.json +++ b/plugins/nodejs.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/jetify-com/devbox/main/.schema/devbox-plugin.schema.json", - "version": "0.0.3", + "version": "0.0.4", "name": "nodejs", "readme": "Devbox automatically configures Corepack for Nodejs when DEVBOX_COREPACK_ENABLED=1. You can install Yarn or Pnpm by adding them to your `package.json` file using `packageManager`\nCorepack binaries will be installed in your local `.devbox` directory\n\nWhen Corepack is enabled, Devbox also activates the package manager pinned in your `package.json` `packageManager` field automatically. Set DEVBOX_DISABLE_NODEJS_PACKAGE_MANAGER_AUTODETECT=1 to disable this behavior.", "env": { @@ -9,11 +9,11 @@ }, "shell": { "init_hook": [ - "node \"{{ .Virtenv }}/bin/setup-corepack.js\"" + "node \"{{ .Virtenv }}/bin/setup-corepack.cjs\"" ] }, "create_files": { "{{ .Virtenv }}/corepack-bin": "", - "{{ .Virtenv }}/bin/setup-corepack.js": "nodejs/setup-corepack.js" + "{{ .Virtenv }}/bin/setup-corepack.cjs": "nodejs/setup-corepack.cjs" } } diff --git a/plugins/nodejs/setup-corepack.js b/plugins/nodejs/setup-corepack.cjs similarity index 87% rename from plugins/nodejs/setup-corepack.js rename to plugins/nodejs/setup-corepack.cjs index f2471067895..bbff1b214af 100644 --- a/plugins/nodejs/setup-corepack.js +++ b/plugins/nodejs/setup-corepack.cjs @@ -1,5 +1,9 @@ // Configures Corepack for the Devbox shell. This is the nodejs plugin's -// init_hook, invoked as: node setup-corepack.js +// init_hook, invoked as: node setup-corepack.cjs +// +// The .cjs extension forces Node to treat this as a CommonJS module even when +// the project's package.json sets "type": "module" (otherwise the require() +// calls below would throw "require is not defined in ES module scope"). // // It is a no-op unless DEVBOX_COREPACK_ENABLED is set, in which case it: // 1. Enables Corepack, installing its package-manager shims into the diff --git a/testscripts/plugin/nodejs_corepack_autodetect.test.txt b/testscripts/plugin/nodejs_corepack_autodetect.test.txt index ed10396b30b..f8f8f41528d 100644 --- a/testscripts/plugin/nodejs_corepack_autodetect.test.txt +++ b/testscripts/plugin/nodejs_corepack_autodetect.test.txt @@ -23,8 +23,21 @@ cp package-no-pkgmgr.json package.json exec devbox run -- node -e 'console.log("case2-ok")' stdout 'case2-ok' +# Case 3: package.json sets "type": "module" (regression test for #2856). +# The setup script must still run; its .cjs extension keeps it CommonJS even +# though the project package.json would otherwise make .js files ES modules. +cp package-esm.json package.json +exec devbox run -- node -e 'console.log("case3-ok")' +stdout 'case3-ok' + -- package-no-pkgmgr.json -- { "name": "nodejs-corepack-autodetect", "version": "1.0.0" } +-- package-esm.json -- +{ + "name": "nodejs-corepack-autodetect", + "version": "1.0.0", + "type": "module" +} From e1b53702e4cf8984545e34de6bcbafb5d49aa3fc Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 8 Jun 2026 14:29:40 +0000 Subject: [PATCH 2/2] fix(nodejs plugin): rewrite setup-corepack as an ESM .mjs module Rewrites the corepack setup script as a native ES module and names it setup-corepack.mjs. The .mjs extension forces Node to treat it as ESM regardless of the project's package.json "type" field, so it no longer crashes with "require is not defined in ES module scope" when a project sets "type": "module" (issue #2856), and it also works for default CommonJS projects. - require() -> import for child_process and path. - Read package.json via readFileSync + JSON.parse instead of require(), since JSON module import syntax varies across Node versions. - Update the plugin's init_hook and create_files references to the .mjs file. Verified the script exits 0 (no crash) for "type":"module", default/CommonJS, and pinned-packageManager projects. --- plugins/nodejs.json | 4 ++-- ...{setup-corepack.cjs => setup-corepack.mjs} | 24 ++++++++++++------- .../nodejs_corepack_autodetect.test.txt | 4 ++-- 3 files changed, 20 insertions(+), 12 deletions(-) rename plugins/nodejs/{setup-corepack.cjs => setup-corepack.mjs} (67%) diff --git a/plugins/nodejs.json b/plugins/nodejs.json index 29a23152d1c..f56ef938210 100644 --- a/plugins/nodejs.json +++ b/plugins/nodejs.json @@ -9,11 +9,11 @@ }, "shell": { "init_hook": [ - "node \"{{ .Virtenv }}/bin/setup-corepack.cjs\"" + "node \"{{ .Virtenv }}/bin/setup-corepack.mjs\"" ] }, "create_files": { "{{ .Virtenv }}/corepack-bin": "", - "{{ .Virtenv }}/bin/setup-corepack.cjs": "nodejs/setup-corepack.cjs" + "{{ .Virtenv }}/bin/setup-corepack.mjs": "nodejs/setup-corepack.mjs" } } diff --git a/plugins/nodejs/setup-corepack.cjs b/plugins/nodejs/setup-corepack.mjs similarity index 67% rename from plugins/nodejs/setup-corepack.cjs rename to plugins/nodejs/setup-corepack.mjs index bbff1b214af..1ca1dd175cc 100644 --- a/plugins/nodejs/setup-corepack.cjs +++ b/plugins/nodejs/setup-corepack.mjs @@ -1,9 +1,10 @@ // Configures Corepack for the Devbox shell. This is the nodejs plugin's -// init_hook, invoked as: node setup-corepack.cjs +// init_hook, invoked as: node setup-corepack.mjs // -// The .cjs extension forces Node to treat this as a CommonJS module even when -// the project's package.json sets "type": "module" (otherwise the require() -// calls below would throw "require is not defined in ES module scope"). +// The .mjs extension forces Node to treat this as an ES module regardless of +// the project's package.json "type" field. A plain .js file would be parsed as +// CommonJS or ESM depending on that field, so it would break in one case or the +// other (see issue #2856). // // It is a no-op unless DEVBOX_COREPACK_ENABLED is set, in which case it: // 1. Enables Corepack, installing its package-manager shims into the @@ -13,8 +14,9 @@ // "packageManager" field (pnpm, yarn, npm, ...), unless // DEVBOX_DISABLE_NODEJS_PACKAGE_MANAGER_AUTODETECT is set. -const { execFileSync } = require("node:child_process"); -const path = require("node:path"); +import { execFileSync } from "node:child_process"; +import { readFileSync } from "node:fs"; +import path from "node:path"; if (!process.env.DEVBOX_COREPACK_ENABLED) { process.exit(0); @@ -41,11 +43,17 @@ function activatePinnedPackageManager() { return; } + // Read package.json directly rather than importing it: JSON module import + // syntax differs across Node versions, whereas readFileSync + JSON.parse + // works everywhere. let packageManager; try { - ({ packageManager } = require(path.join(projectRoot, "package.json"))); + const pkg = JSON.parse( + readFileSync(path.join(projectRoot, "package.json"), "utf8"), + ); + ({ packageManager } = pkg); } catch { - // No package.json (or it is unreadable) — nothing to autodetect. + // No package.json (or it is unreadable/invalid) — nothing to autodetect. return; } diff --git a/testscripts/plugin/nodejs_corepack_autodetect.test.txt b/testscripts/plugin/nodejs_corepack_autodetect.test.txt index f8f8f41528d..81e05655b9a 100644 --- a/testscripts/plugin/nodejs_corepack_autodetect.test.txt +++ b/testscripts/plugin/nodejs_corepack_autodetect.test.txt @@ -24,8 +24,8 @@ exec devbox run -- node -e 'console.log("case2-ok")' stdout 'case2-ok' # Case 3: package.json sets "type": "module" (regression test for #2856). -# The setup script must still run; its .cjs extension keeps it CommonJS even -# though the project package.json would otherwise make .js files ES modules. +# The setup script must still run; its .mjs extension keeps it an ES module +# regardless of the project package.json's "type" field. cp package-esm.json package.json exec devbox run -- node -e 'console.log("case3-ok")' stdout 'case3-ok'