Skip to content

Commit b8634ee

Browse files
RaisinTentargos
authored andcommitted
sea: allow requiring core modules with the "node:" prefix
Previously, the `require()` function exposed to the embedded SEA code was calling the internal `require()` function if the module name belonged to the list of public core modules but the internal `require()` function does not support loading modules with the "node:" prefix, so this change forwards the calls to another `require()` function that supports this. Fixes: nodejs/single-executable#69 Signed-off-by: Darshan Sen <[email protected]> PR-URL: #47779 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Luigi Pinca <[email protected]> Reviewed-By: Michael Dawson <[email protected]> Reviewed-By: Joyee Cheung <[email protected]> Signed-off-by: Darshan Sen <[email protected]>
1 parent 9a4b57d commit b8634ee

File tree

4 files changed

+40
-16
lines changed

4 files changed

+40
-16
lines changed

lib/internal/bootstrap/realm.js

+15-1
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ const {
6363
SafeMap,
6464
SafeSet,
6565
String,
66-
StringPrototypeStartsWith,
6766
StringPrototypeSlice,
67+
StringPrototypeStartsWith,
6868
TypeError,
6969
} = primordials;
7070

@@ -299,6 +299,20 @@ class BuiltinModule {
299299
return ArrayFrom(canBeRequiredByUsersWithoutSchemeList);
300300
}
301301

302+
static normalizeRequirableId(id) {
303+
let normalizedId = id;
304+
if (StringPrototypeStartsWith(id, 'node:')) {
305+
normalizedId = StringPrototypeSlice(id, 5);
306+
}
307+
308+
if (!BuiltinModule.canBeRequiredByUsers(normalizedId) ||
309+
(id === normalizedId && !BuiltinModule.canBeRequiredWithoutScheme(normalizedId))) {
310+
return undefined;
311+
}
312+
313+
return normalizedId;
314+
}
315+
302316
static getSchemeOnlyModuleNames() {
303317
return ArrayFrom(schemelessBlockList);
304318
}

lib/internal/main/mksnapshot.js

+3-10
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,10 @@ const {
77
ObjectSetPrototypeOf,
88
SafeArrayIterator,
99
SafeSet,
10-
StringPrototypeStartsWith,
11-
StringPrototypeSlice,
1210
} = primordials;
1311

1412
const binding = internalBinding('mksnapshot');
15-
const { BuiltinModule } = require('internal/bootstrap/realm');
13+
const { BuiltinModule: { normalizeRequirableId } } = require('internal/bootstrap/realm');
1614
const {
1715
compileSerializeMain,
1816
} = binding;
@@ -97,13 +95,8 @@ function supportedInUserSnapshot(id) {
9795
}
9896

9997
function requireForUserSnapshot(id) {
100-
let normalizedId = id;
101-
if (StringPrototypeStartsWith(id, 'node:')) {
102-
normalizedId = StringPrototypeSlice(id, 5);
103-
}
104-
if (!BuiltinModule.canBeRequiredByUsers(normalizedId) ||
105-
(id !== normalizedId &&
106-
!BuiltinModule.canBeRequiredWithoutScheme(normalizedId))) {
98+
const normalizedId = normalizeRequirableId(id);
99+
if (!normalizedId) {
107100
// eslint-disable-next-line no-restricted-syntax
108101
const err = new Error(
109102
`Cannot find module '${id}'. `,

lib/internal/main/single_executable_application.js

+6-4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const { getSingleExecutableCode } = internalBinding('sea');
77
const { emitExperimentalWarning } = require('internal/util');
88
const { Module, wrapSafe } = require('internal/modules/cjs/loader');
99
const { codes: { ERR_UNKNOWN_BUILTIN_MODULE } } = require('internal/errors');
10+
const { BuiltinModule: { normalizeRequirableId } } = require('internal/bootstrap/realm');
1011

1112
prepareMainThreadExecution(false, true);
1213
markBootstrapComplete();
@@ -33,12 +34,13 @@ customModule.paths = Module._nodeModulePaths(customModule.path);
3334

3435
const customExports = customModule.exports;
3536

36-
function customRequire(path) {
37-
if (!Module.isBuiltin(path)) {
38-
throw new ERR_UNKNOWN_BUILTIN_MODULE(path);
37+
function customRequire(id) {
38+
const normalizedId = normalizeRequirableId(id);
39+
if (!normalizedId) {
40+
throw new ERR_UNKNOWN_BUILTIN_MODULE(id);
3941
}
4042

41-
return require(path);
43+
return require(normalizedId);
4244
}
4345

4446
customRequire.main = customModule;

test/fixtures/sea.js

+16-1
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,23 @@ expectWarning('ExperimentalWarning',
99
'Single executable application is an experimental feature and ' +
1010
'might change at any time');
1111

12+
// Should be possible to require core modules that optionally require the
13+
// "node:" scheme.
1214
const { deepStrictEqual, strictEqual, throws } = require('assert');
13-
const { dirname } = require('path');
15+
const { dirname } = require('node:path');
16+
17+
// Should be possible to require a core module that requires using the "node:"
18+
// scheme.
19+
{
20+
const { test } = require('node:test');
21+
strictEqual(typeof test, 'function');
22+
}
23+
24+
// Should not be possible to require a core module without the "node:" scheme if
25+
// it requires using the "node:" scheme.
26+
throws(() => require('test'), {
27+
code: 'ERR_UNKNOWN_BUILTIN_MODULE',
28+
});
1429

1530
deepStrictEqual(process.argv, [process.execPath, process.execPath, '-a', '--b=c', 'd']);
1631

0 commit comments

Comments
 (0)