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
process: add process.getBuiltinModule(id) #52762
base: main
Are you sure you want to change the base?
Conversation
Review requested:
|
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.
nice, quite simple :)
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.
lgtm
This is obviously exactly what I asked for (😄) and gets it "done" the quickest, but I'm curious if there are any other opinions about this in general. Is it possible that |
Not quite sure if I am following this but I think |
Yeah, I guess it's no different than detecting calls to Just poking holes in my own idea. |
We can also suggest in the documentation that users should only consider using this for code paths that can only be run in Node.js (the code example is basically already suggesting that but we can make it clearer). If they want the code depending on the built-ins to be polyfill-able in the browser, they should still use require or import. |
There is a TC39 proposal to get original built-in functions, through a new |
Just to prove this out to its full extent (and to procrastinate other work I didn't want to do), I polyfilled this API using |
`process.getBuiltinModule(id)` provides a way to load built-in modules in a globally available function. ES Modules that need to support other environments can use it to conditionally load a Node.js built-in when it is run in Node.js, without having to deal with the resolution error that can be thrown by `import` in a non-Node.js environment or having to use dynamic `import()` which either turns the module into an asynchronous module, or turns a synchronous API into an asynchronous one. ```mjs if (globalThis.process.getBuiltinModule) { // Run in Node.js, use the Node.js fs module. const fs = globalThis.process.getBuiltinModule('fs'); // If `require()` is needed to load user-modules, use // createRequire() const module = globalThis.process.getBuiltinModule('module'); const require = module.createRequire(import.meta.url); const foo = require('foo'); } ``` If `id` specifies a built-in module available in the current Node.js process, `process.getBuiltinModule(id)` method returns the corresponding built-in module. If `id` does not correspond to any built-in module, `undefined` is returned. `process.getBuiltinModule(id)` accept built-in module IDs that are recognized by `module.isBuiltin(id)`. Some built-in modules must be loaded with the `node:` prefix. The built-in modules returned by `process.getBuiltinModule(id)` are always the original modules - that is, it's not affected by `require.cache`.
719213c
to
e83917e
Compare
Updated the PR a bit:
|
Now it mismatches Alternatively we can add |
|
Fair enough. I still think we should create an alias on |
efd0f35
to
4051f58
Compare
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 a core collaborator, so this is only a suggestion: Shouldn't this become a no-op with --experimental-permission
?
I don't think it's relevant for the permission model as that guards things at the native layer when resources are actually accessed. The removed policy feature did guard access to builtins at the module loader level, but that's..removed (in general guarding things at the module loader level isn't super useful anyway because how widely monkey-patching of the module loader is used). But cc @nodejs/security-wg to be sure. |
Thanks, I was thinking this was like |
Co-authored-by: Michaël Zasso <targos@protonmail.com>
The `nodejs_compat_v2` flag supersedes the 'nodejs_compat' flag. When enabled... 1. Node.js built-ins are available for import/require 2. Unlike the original `nodejs_compat` flag, Node.js imports do not require the 'node:' specifier prefix. Internally, the implementation will detect a Node.js raw specifier and convert it into the appropriate prefixed specifier, e.g. 'fs' becomes 'node:fs' 3. The `Buffer` and `process` global objects are exposed on the global 4. A user worker bundle can still provide it's own implementations of all `node:` modules which will take precendence over the built-ins 5. The new `process.getBuiltinModule(...)` API is implemented. See nodejs/node#52762 A worker can replace the implementation of `node:process` if they choose, which may mean that `getBuiltinModule(...)` is not available.
The `nodejs_compat_v2` flag supersedes the 'nodejs_compat' flag. When enabled... 1. Node.js built-ins are available for import/require 2. Unlike the original `nodejs_compat` flag, Node.js imports do not require the 'node:' specifier prefix. Internally, the implementation will detect a Node.js raw specifier and convert it into the appropriate prefixed specifier, e.g. 'fs' becomes 'node:fs' 3. The `Buffer` and `process` global objects are exposed on the global 4. A user worker bundle can still provide it's own implementations of all `node:` modules which will take precendence over the built-ins 5. The new `process.getBuiltinModule(...)` API is implemented. See nodejs/node#52762 A worker can replace the implementation of `node:process` if they choose, which may mean that `getBuiltinModule(...)` is not available.
The `nodejs_compat_v2` flag supersedes the 'nodejs_compat' flag. When enabled... 1. Node.js built-ins are available for import/require 2. Unlike the original `nodejs_compat` flag, Node.js imports do not require the 'node:' specifier prefix. Internally, the implementation will detect a Node.js raw specifier and convert it into the appropriate prefixed specifier, e.g. 'fs' becomes 'node:fs' 3. The `Buffer` and `process` global objects are exposed on the global 4. A user worker bundle can still provide it's own implementations of all `node:` modules which will take precendence over the built-ins 5. The new `process.getBuiltinModule(...)` API is implemented. See nodejs/node#52762 A worker can replace the implementation of `node:process` if they choose, which may mean that `getBuiltinModule(...)` is not available.
The `nodejs_compat_v2` flag supersedes the 'nodejs_compat' flag. When enabled... 1. Node.js built-ins are available for import/require 2. Unlike the original `nodejs_compat` flag, Node.js imports do not require the 'node:' specifier prefix. Internally, the implementation will detect a Node.js raw specifier and convert it into the appropriate prefixed specifier, e.g. 'fs' becomes 'node:fs' 3. The `Buffer` and `process` global objects are exposed on the global 4. A user worker bundle can still provide it's own implementations of all `node:` modules which will take precendence over the built-ins 5. The new `process.getBuiltinModule(...)` API is implemented. See nodejs/node#52762 A worker can replace the implementation of `node:process` if they choose, which may mean that `getBuiltinModule(...)` is not available.
process: add process.getBuiltinModule(id)
process.getBuiltinModule(id)
provides a way to load built-in modulesin a globally available function. ES Modules that need to support
other environments can use it to conditionally load a Node.js built-in
when it is run in Node.js, without having to deal with the resolution
error that can be thrown by
import
in a non-Node.js environment orhaving to use dynamic
import()
which either turns the module into anasynchronous module, or turns a synchronous API into an asynchronous
one.
If
id
specifies a built-in module available in the current Node.jsprocess,
process.getBuiltinModule(id)
method returns thecorresponding built-in module. If
id
does not correspond to anybuilt-in module,
undefined
is returned.process.getBuiltinModule(id)
accept built-in module IDs that arerecognized by
module.isBuiltin(id)
. Some built-in modules must beloaded with the
node:
prefix.The built-in modules returned by
process.getBuiltinModule(id)
arealways the original modules - that is, it's not affected by
require.cache
.Fixes: #52599