I'm working on an npm package initializer, that is, a program that runs when the user runs the npm init <my-package-initializer>
command.
npm is not the only package manager for Node.js any more, yarn is also quite popular and pnpm is a personal favorite of mine and I want to support all three. The easy way is to ask the user which package manager they prefer or provide a command-line switch like CRA does.
But the user has already shown their preference by running, say, yarn create
instead of npm init
. It feels annoying to ask again. We could just check if yarn
or pnpm
is our parent process.
Is there a cross-platform way to get this information?
For future googlers, I ended up using the following snippet. I use it for picking the default choice but I still ask the user explicitly for their package manager preference, better safe than sorry.
function getPackageManager() {
// This environment variable is set by npm and yarn but pnpm seems less consistent
const agent = process.env.npm_config_user_agent;
if (!agent) {
// This environment variable is set on Linux but I'm not sure about other OSes.
const parent = process.env._;
if (!parent) {
// No luck, assume npm
return "npm";
}
if (parent.endsWith("pnpx") || parent.endsWith("pnpm")) return "pnpm";
if (parent.endsWith("yarn")) return "yarn";
// Assume npm for anything else
return "npm";
}
const [program] = agent.split("/");
if (program === "yarn") return "yarn";
if (program === "pnpm") return "pnpm";
// Assume npm
return "npm";
}