Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions plugins/nodejs.json
Original file line number Diff line number Diff line change
@@ -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": {
Expand All @@ -9,11 +9,11 @@
},
"shell": {
"init_hook": [
"node \"{{ .Virtenv }}/bin/setup-corepack.js\""
"node \"{{ .Virtenv }}/bin/setup-corepack.mjs\""
]
},
"create_files": {
"{{ .Virtenv }}/corepack-bin": "",
"{{ .Virtenv }}/bin/setup-corepack.js": "nodejs/setup-corepack.js"
"{{ .Virtenv }}/bin/setup-corepack.mjs": "nodejs/setup-corepack.mjs"
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
// 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.mjs
//
// 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
Expand All @@ -9,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);
Expand All @@ -37,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;
}

Expand Down
13 changes: 13 additions & 0 deletions testscripts/plugin/nodejs_corepack_autodetect.test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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 .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'

-- 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"
}
Loading