-
-
Notifications
You must be signed in to change notification settings - Fork 535
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(core): pnpm support #3822
base: main
Are you sure you want to change the base?
feat(core): pnpm support #3822
Conversation
@@ -46,7 +46,7 @@ commands: | |||
- run: | |||
name: 'Run fast tests' | |||
command: | | |||
yarn test:fast --reporter=junit --outputFile="./reports/out/test_output.xml" | |||
yarn test:fast --reporter=default --reporter=junit --outputFile="./reports/out/test_output.xml" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using the default
reporter both gives us a clearer idea of the failures in CI and prevents us from hitting the 10-minute CircleCI no output
timeout.
- run: | ||
name: 'Install pnpm' | ||
command: | | ||
npm install -g [email protected] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could also do this in corepack
in theory, but I found this to be easier to grok.
all: '>= 1.0.0', | ||
}, | ||
pnpm: { | ||
all: '>= 8.0.0', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know if this is necessary, but the Node compatibility matrix in the pnpm docs only lists up to pnpm 8 so I feel like this is a decent lower bound: https://pnpm.io/installation#compatibility
|
||
function warnIfPackageManagerIsntAKnownGoodVersion(packageManager: string, version: string, allowlistedVersions: { [key: string]: string }) { | ||
const osVersions = allowlistedVersions[process.platform]; | ||
const versions = osVersions ? `${allowlistedVersions.all} || ${osVersions}` : allowlistedVersions.all; | ||
const versionString = version.toString(); | ||
checkValidPackageManagerVersion(packageManager, versionString, versions); | ||
} | ||
|
||
async function checkPackageManagerVersion() { | ||
const version = await forgeUtils.yarnOrNpmSpawn(['--version']); | ||
const versionString = version.toString().trim(); | ||
if (await forgeUtils.hasYarn()) { | ||
warnIfPackageManagerIsntAKnownGoodVersion('Yarn', versionString, YARN_ALLOWLISTED_VERSIONS); | ||
return `yarn@${versionString}`; | ||
} else { | ||
warnIfPackageManagerIsntAKnownGoodVersion('NPM', versionString, NPM_ALLOWLISTED_VERSIONS); | ||
return `npm@${versionString}`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These functions were refactored out into a single checkPackageManager
utility.
hasYarn = hasYarn; | ||
|
||
yarnOrNpmSpawn = yarnOrNpmSpawn; | ||
spawnPackageManager = spawnPackageManager; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is a change in API signatures for @electron-forge/core-utils
a breaking change? If it is, I can add a temporary shim for these utils and deprecate them.
Closes #2633
Closes #3574
ref #3813
This PR aims to provide a basic level of pnpm support for Electron Forge.
Context
Under the hood, Forge's
init
andimport
commands use a Node.js package manager to install dependencies and otherwise execute commands. The logic is set up to useyarn
if detected, and falls back tonpm
otherwise.With the proliferation of alternative package managers in recent years, one of the most popular requests on our issue tracker was to support pnpm (#2633).
However, this required a decent amount of refactoring since we relied on the unmaintained (
yarn-or-npm
) package to perform this package manager detection. This locked us out of support for other package managers until this utility was completely refactored.Prior art
Big thanks to @makeryi and @goosewobbler for opening their respective PRs attempting support (#3351 and #3574).
Based on their efforts, I first landed #3813, which replaces
yarn-or-npm
with the more generalizeddetect-package-manager
package without changing the API signature for our utility APIs.This PR follows that up by replacing our package manager utilities (which still only supported yarn or npm) with a generic package manager detection system that returns the current package manager as well as its associated commands and flags.
Implementation
Package manager detection
The core of this PR refactors the
yarn-or-npm
file in@electron-forge/core-utils
to instead be a genericpackage-manager
util.Instead of returning just the name of the package manager, resolving which package manager to use also returns its
install
command as well as the command flags we may want to use.forge/packages/utils/core-utils/src/package-manager.ts
Lines 6 to 28 in 1592d85
Note
In theory, we could do away with these objects for now because the shorthand
<pm> install -E -D
works across npm, yarn, and pnpm. However, this setup future-proofs us against future commands/flags that we'd want to add that aren't necessarily compatible.The behaviour for
resolvePackageManager
now differs. If an unsupported package manager is detected viaNODE_INSTALLER
ordetect-package-manager
, we default tonpm
instead of whatever the detected system package manager is.This solves the case where we'd detect an unsupported package manager (e.g.
bun
).node-linker=hoisted
Out of the box, pnpm provides improved disk space efficiency and install speed because it symlinks all dependencies and stores them in a central location on disk (see Motivation section of the pnpm docs for more details).
However, Forge expects
node_modules
to exist on disk at specific locations because we bundle all production npm dependencies into the Electron app when packaging.To that end, we expect the config to be
node-linker=hoisted
when running Electron Forge. I added a clause tocheck-system.ts
to ensure this by checking the value ofpnpm config get node-linker
.forge/packages/api/cli/src/util/check-system.ts
Lines 30 to 36 in 1592d85
This setting is added out of the box when initializing Forge templates with
pnpm
via.npmrc
:forge/packages/template/base/tmpl/.npmrc
Line 1 in 1592d85
forge/packages/template/base/src/BaseTemplate.ts
Lines 65 to 67 in 1592d85
pnpm workspaces
I think we actually already supported pnpm workspaces via:
forge/packages/utils/core-utils/src/electron-version.ts
Lines 21 to 33 in f084010
Supported pnpm version ranges
I'm not sure if
v8.0.0
is a correct lower bound for pnpm, but it's the lowest version they have for their documentation so I'm assuming something has to do with their support policy.Testing
This PR expands the existing test suite to also support
pnpm
(mostly inapi.slow.spec.ts
).Note
Previously, we actually didn't test packaging/making for
npm
. This PR has the side effect of fully testing the API across all supported package managers, which does bring up the Time to Green for our CI.