-
Notifications
You must be signed in to change notification settings - Fork 3
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
Execution Environments #7
base: main
Are you sure you want to change the base?
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
# Execution Environments | ||
|
||
## Summary | ||
|
||
This RFC introduces settings for controlling what execution environment (Node.js, Bun, Deno) will be used for a package during: | ||
|
||
* runnings its lifecycle scripts | ||
* building | ||
* running it as a CLI app | ||
|
||
## Motivation | ||
|
||
Running multiple versions of Node.js on the same computer isn't easy. Also, there is currently no way for a package to tell the package manager that it needs to be executed with a specific version of Node.js. Node.js versions should be locked the same way as other dependencies of projects are locked for reproducibility. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is already a way: engines https://docs.npmjs.com/cli/v10/configuring-npm/package-json#engines Perhaps this RFC could explain why engines is not sufficient and why we need a new feature. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As you can see in the alternatives section:
|
||
|
||
## Detailed Explanation | ||
|
||
We will support a new field in `package.json`: `pnpm.executionEnv.js`. This field will be similar to the `packageManager` field introduced by Corepack but will feature `<js runtime>@<version>` instead. For example: | ||
zkochan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
```json | ||
{ | ||
"pnpm": { | ||
"executionEnv": { | ||
"js": "[email protected]" | ||
} | ||
} | ||
} | ||
``` | ||
|
||
or | ||
|
||
```json | ||
{ | ||
"pnpm": { | ||
"executionEnv": { | ||
"js": "[email protected]" | ||
} | ||
} | ||
} | ||
``` | ||
|
||
or | ||
|
||
```json | ||
{ | ||
"pnpm": { | ||
"executionEnv": { | ||
"js": "[email protected]" | ||
} | ||
} | ||
} | ||
``` | ||
|
||
When pnpm sees this setting, it will load the specified runtime and use it for: | ||
|
||
* running scripts locally (via the `pnpm run` and `pnpm exec` command) | ||
* running build scripts, when installed as a dependency. If the package has a postinstall script, it will be executed by the specified runtime. | ||
* running the package, when it is executed as a CLI. | ||
|
||
If we don't want to control the execution env of the published package, set the optional `localOnly` setting to `true`. For instance: | ||
|
||
```json | ||
{ | ||
"name": "cowsay", | ||
"version": "1.0.0", | ||
"bin": "bin.js", | ||
"pnpm": { | ||
"executionEnv": { | ||
"js": "[email protected]", | ||
"localOnly": true | ||
} | ||
} | ||
} | ||
``` | ||
|
||
In this case, pnpm will remove the `executionEnv` setting from the `package.json` file on publish and the binary of the package will be executed with whatever runtime will be installed globally on the target machine. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't pnpm already remove the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It does remove the field currently. But this new subfield should not be removed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Effectively, you are creating a pnpm-specific extension for the whole JS packages ecosystem. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Those packages will work with other package managers just fine. But with pnpm they will be more stable as the runtime will be locked. |
||
|
||
Some environments might not want to allow pnpm to control the js runtime. For thes cases we need to support a setting that will instruct pnpm to ignore all the execution env settings: `ignore-execution-env=true`. | ||
|
||
## Rationale and Alternatives | ||
|
||
The alternative would be to use a third party tool for this (like Volta) but then we would have one more prerequisite for using pnpm. | ||
|
||
## Implementation | ||
|
||
The implementation can leverage the logic that is already present in pnpm for the `pnpm env` command, the `pnpm.executionEnv.nodeVersion` setting, the `use-node-version` setting. | ||
|
||
Binding CLI apps to specific Node.js versions can be done via command shims. This currently works for globally installed packages. pnpm links globally installed packages to the active Node.js version. | ||
|
||
## Prior Art | ||
|
||
We already have some functionality for managing Node.js versions: | ||
|
||
* the [pnpm env](https://pnpm.io/cli/env) command | ||
* the [use-node-version](https://pnpm.io/npmrc#use-node-version) setting | ||
* the [pnpm.executionEnv.nodeVersion](https://pnpm.io/package_json#pnpmexecutionenvnodeversion) setting. | ||
|
||
## Unresolved Questions and Bikeshedding | ||
|
||
{{Write about any arbitrary decisions that need to be made (syntax, colors, formatting, minor UX decisions), and any questions for the proposal that have not been answered.}} | ||
|
||
{{THIS SECTION SHOULD BE REMOVED BEFORE RATIFICATION}} | ||
|
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.
One thing to note is that lifecycle scripts can technically choose to execute
node
,deno
, andbun
in the same command because they are shell scripts.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.
yes, you are right. So, should we support specifying all of them?
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.
There should still be a primary runtime for installing and running CLI app.
Lifecycles OTOH can take advantage of
executionEnv.nodeVersion
,executionEnv.denoVersion
,executionEnv.bunVersion
.I don't quite understand the
building
item, is it lifecycle?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.
The building part is when the package is installed as a dependency. If it has a "postinstall" script, it will be executed to build the package. Or if it has a
binding.gyp
file, thennode-gyp
will run to build the package (it can still run node under the hood).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.
ok, so you suggest to keep the
nodeVersion
field, add [runtime]Version fields and ajsRuntime
field. In that case, I guess jsRuntime will always be used, when the package is installed as a dependency (so the localOnly field is not needed).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.
For reference, there is also this RFC: openjs-foundation/package-metadata-interoperability-collab-space#15
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.
In the referenced issue they have also pointed out that there is an existing field for specifying runtime environments: engines.
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 am fine with your suggestion to have
nodeVersion
,denoVersion
,bunVersion
. I am not sure about the rest of the suggestion though. Especially as having a cliRuntime should be optional, so automatically generating it doesn't makes sense.Something like an object with setting could work too:
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'm not sure about adding another nesting level. Besides that, this also creates an invalid state where
nodeRuntime.cli
,denoRuntime.cli
, andbunRuntime.cli
are all defined, compared tocliRuntime
which doesn't have invalid state.We can improve it a bit:
cliRuntime
is only required when the package definebin
and there are more than 1{x}Version
.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.
Right, but even when there is a
bin
field, this is optional. The nesting can be not required. Like in the dependencies inCargo.toml
. For instance: