mirror of
https://github.com/nodejs/node.git
synced 2026-10-28 10:15:07 +08:00
module: add support for node:‑prefixed require(…) calls
Fixes: https://github.com/nodejs/node/issues/36098 Co-authored-by: Antoine du Hamel <duhamelantoine1995@gmail.com> Co-authored-by: Guy Bedford <guybedford@gmail.com> Co-authored-by: Darshan Sen <raisinten@gmail.com> PR-URL: https://github.com/nodejs/node/pull/37246 Reviewed-By: Bradley Farias <bradley.meck@gmail.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Darshan Sen <raisinten@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
This commit is contained in:
1 parent
b079960b18
commit
069b5df4f6
7 files changed
+90
-6
No files matched your search
@@ -204,6 +204,10 @@ import _ from 'data:application/json,"world!"';
|
||||
added:
|
||||
- v14.13.1
|
||||
- v12.20.0
|
||||
changes:
|
||||
- version: REPLACEME
|
||||
pr-url: https://github.com/nodejs/node/pull/37246
|
||||
description: Added `node:` import support to `require(...)`.
|
||||
-->
|
||||
|
||||
`node:` URLs are supported as an alternative means to load Node.js builtin
|
||||
|
||||
+24
-2
@@ -280,6 +280,12 @@ irrespective of whether or not `./foo` and `./FOO` are the same file.
|
||||
## Core modules
|
||||
|
||||
<!--type=misc-->
|
||||
<!-- YAML
|
||||
changes:
|
||||
- version: REPLACEME
|
||||
pr-url: https://github.com/nodejs/node/pull/37246
|
||||
description: Added `node:` import support to `require(...)`.
|
||||
-->
|
||||
|
||||
Node.js has several modules compiled into the binary. These modules are
|
||||
described in greater detail elsewhere in this documentation.
|
||||
@@ -291,6 +297,11 @@ Core modules are always preferentially loaded if their identifier is
|
||||
passed to `require()`. For instance, `require('http')` will always
|
||||
return the built in HTTP module, even if there is a file by that name.
|
||||
|
||||
Core modules can also be identified using the `node:` prefix, in which case
|
||||
it bypasses the `require` cache. For instance, `require('node:http')` will
|
||||
always return the built in HTTP module, even if there is `require.cache` entry
|
||||
by that name.
|
||||
|
||||
## Cycles
|
||||
|
||||
<!--type=misc-->
|
||||
@@ -642,8 +653,19 @@ error.
|
||||
|
||||
Adding or replacing entries is also possible. This cache is checked before
|
||||
native modules and if a name matching a native module is added to the cache,
|
||||
no require call is
|
||||
going to receive the native module anymore. Use with care!
|
||||
only `node:`-prefixed require calls are going to receive the native module.
|
||||
Use with care!
|
||||
|
||||
```js
|
||||
const assert = require('assert');
|
||||
const realFs = require('fs');
|
||||
|
||||
const fakeFs = {};
|
||||
require.cache.fs = { exports: fakeFs };
|
||||
|
||||
assert.strictEqual(require('fs'), fakeFs);
|
||||
assert.strictEqual(require('node:fs'), realFs);
|
||||
```
|
||||
|
||||
#### `require.extensions`
|
||||
<!-- YAML
|
||||
|
||||
@@ -34,8 +34,9 @@ const cjsConditions = new SafeSet(['require', 'node', ...userConditions]);
|
||||
|
||||
function loadNativeModule(filename, request) {
|
||||
const mod = NativeModule.map.get(filename);
|
||||
if (mod) {
|
||||
if (mod?.canBeRequiredByUsers) {
|
||||
debug('load native module %s', request);
|
||||
// compileForPublicLoader() throws if mod.canBeRequiredByUsers is false:
|
||||
mod.compileForPublicLoader();
|
||||
return mod;
|
||||
}
|
||||
|
||||
@@ -110,7 +110,8 @@ let hasLoadedAnyUserCJSModule = false;
|
||||
const {
|
||||
ERR_INVALID_ARG_VALUE,
|
||||
ERR_INVALID_MODULE_SPECIFIER,
|
||||
ERR_REQUIRE_ESM
|
||||
ERR_REQUIRE_ESM,
|
||||
ERR_UNKNOWN_BUILTIN_MODULE,
|
||||
} = require('internal/errors').codes;
|
||||
const { validateString } = require('internal/validators');
|
||||
const pendingDeprecation = getOptionValue('--pending-deprecation');
|
||||
@@ -770,6 +771,17 @@ Module._load = function(request, parent, isMain) {
|
||||
}
|
||||
|
||||
const filename = Module._resolveFilename(request, parent, isMain);
|
||||
if (StringPrototypeStartsWith(filename, 'node:')) {
|
||||
// Slice 'node:' prefix
|
||||
const id = StringPrototypeSlice(filename, 5);
|
||||
|
||||
const module = loadNativeModule(id, request);
|
||||
if (!module?.canBeRequiredByUsers) {
|
||||
throw new ERR_UNKNOWN_BUILTIN_MODULE(filename);
|
||||
}
|
||||
|
||||
return module.exports;
|
||||
}
|
||||
|
||||
const cachedModule = Module._cache[filename];
|
||||
if (cachedModule !== undefined) {
|
||||
@@ -841,7 +853,8 @@ Module._load = function(request, parent, isMain) {
|
||||
};
|
||||
|
||||
Module._resolveFilename = function(request, parent, isMain, options) {
|
||||
if (NativeModule.canBeRequiredByUsers(request)) {
|
||||
if (StringPrototypeStartsWith(request, 'node:') ||
|
||||
NativeModule.canBeRequiredByUsers(request)) {
|
||||
return request;
|
||||
}
|
||||
|
||||
|
||||
@@ -282,7 +282,7 @@ translators.set('builtin', async function builtinStrategy(url) {
|
||||
debug(`Translating BuiltinModule ${url}`);
|
||||
// Slice 'node:' scheme
|
||||
const id = StringPrototypeSlice(url, 5);
|
||||
const module = loadNativeModule(id, url, true);
|
||||
const module = loadNativeModule(id, url);
|
||||
if (!StringPrototypeStartsWith(url, 'node:') || !module) {
|
||||
throw new ERR_UNKNOWN_BUILTIN_MODULE(url);
|
||||
}
|
||||
|
||||
@@ -51,6 +51,8 @@ function expectFsNamespace(result) {
|
||||
|
||||
expectModuleError(import('node:unknown'),
|
||||
'ERR_UNKNOWN_BUILTIN_MODULE');
|
||||
expectModuleError(import('node:internal/test/binding'),
|
||||
'ERR_UNKNOWN_BUILTIN_MODULE');
|
||||
expectModuleError(import('./not-an-existing-module.mjs'),
|
||||
'ERR_MODULE_NOT_FOUND');
|
||||
expectModuleError(import('http://example.com/foo.js'),
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
'use strict';
|
||||
|
||||
require('../common');
|
||||
const assert = require('assert');
|
||||
const fs = require('fs');
|
||||
|
||||
const errUnknownBuiltinModuleRE = /^No such built-in module: /u;
|
||||
|
||||
// For direct use of require expressions inside of CJS modules,
|
||||
// all kinds of specifiers should work without issue.
|
||||
{
|
||||
assert.strictEqual(require('fs'), fs);
|
||||
assert.strictEqual(require('node:fs'), fs);
|
||||
|
||||
assert.throws(
|
||||
() => require('node:unknown'),
|
||||
{
|
||||
code: 'ERR_UNKNOWN_BUILTIN_MODULE',
|
||||
message: errUnknownBuiltinModuleRE,
|
||||
},
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
() => require('node:internal/test/binding'),
|
||||
{
|
||||
code: 'ERR_UNKNOWN_BUILTIN_MODULE',
|
||||
message: errUnknownBuiltinModuleRE,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// `node:`-prefixed `require(...)` calls bypass the require cache:
|
||||
{
|
||||
const fakeModule = {};
|
||||
|
||||
require.cache.fs = { exports: fakeModule };
|
||||
|
||||
assert.strictEqual(require('fs'), fakeModule);
|
||||
assert.strictEqual(require('node:fs'), fs);
|
||||
|
||||
delete require.cache.fs;
|
||||
}
|
||||
Reference in new issue
Block a user