Skip to content

Commit c23d2fd

Browse files
committed
src: allow embedders to disable esm loader
PR-URL: #34060 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: David Carlier <[email protected]> Reviewed-By: Gus Caplan <[email protected]>
1 parent 9e135ac commit c23d2fd

File tree

7 files changed

+76
-4
lines changed

7 files changed

+76
-4
lines changed

lib/internal/bootstrap/pre_execution.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ const {
66
SafeWeakMap,
77
} = primordials;
88

9-
const { getOptionValue } = require('internal/options');
9+
const {
10+
getOptionValue,
11+
shouldNotRegisterESMLoader
12+
} = require('internal/options');
1013
const { Buffer } = require('buffer');
1114
const { ERR_MANIFEST_ASSERT_INTEGRITY } = require('internal/errors').codes;
1215
const assert = require('internal/assert');
@@ -56,7 +59,10 @@ function prepareMainThreadExecution(expandArgv1 = false) {
5659
initializeDeprecations();
5760
initializeWASI();
5861
initializeCJSLoader();
59-
initializeESMLoader();
62+
63+
if (!shouldNotRegisterESMLoader) {
64+
initializeESMLoader();
65+
}
6066

6167
const CJSLoader = require('internal/modules/cjs/loader');
6268
assert(!CJSLoader.hasLoadedAnyUserCJSModule);

lib/internal/options.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict';
22

3-
const { getOptions } = internalBinding('options');
3+
const { getOptions, shouldNotRegisterESMLoader } = internalBinding('options');
44
const { options, aliases } = getOptions();
55

66
let warnOnAllowUnauthorized = true;
@@ -32,4 +32,5 @@ module.exports = {
3232
aliases,
3333
getOptionValue,
3434
getAllowUnauthorized,
35+
shouldNotRegisterESMLoader
3536
};

src/env-inl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,10 @@ inline bool Environment::is_main_thread() const {
767767
return worker_context() == nullptr;
768768
}
769769

770+
inline bool Environment::should_not_register_esm_loader() const {
771+
return flags_ & EnvironmentFlags::kNoRegisterESMLoader;
772+
}
773+
770774
inline bool Environment::owns_process_state() const {
771775
return flags_ & EnvironmentFlags::kOwnsProcessState;
772776
}

src/env.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,6 +1054,7 @@ class Environment : public MemoryRetainer {
10541054
inline void set_has_serialized_options(bool has_serialized_options);
10551055

10561056
inline bool is_main_thread() const;
1057+
inline bool should_not_register_esm_loader() const;
10571058
inline bool owns_process_state() const;
10581059
inline bool owns_inspector() const;
10591060
inline uint64_t thread_id() const;

src/node.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,11 @@ enum Flags : uint64_t {
408408
// Set if this Environment instance is associated with the global inspector
409409
// handling code (i.e. listening on SIGUSR1).
410410
// This is set when using kDefaultFlags.
411-
kOwnsInspector = 1 << 2
411+
kOwnsInspector = 1 << 2,
412+
// Set if Node.js should not run its own esm loader. This is needed by some
413+
// embedders, because it's possible for the Node.js esm loader to conflict
414+
// with another one in an embedder environment, e.g. Blink's in Chromium.
415+
kNoRegisterESMLoader = 1 << 3
412416
};
413417
} // namespace EnvironmentFlags
414418

src/node_options.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -979,6 +979,12 @@ void Initialize(Local<Object> target,
979979
context, FIXED_ONE_BYTE_STRING(isolate, "envSettings"), env_settings)
980980
.Check();
981981

982+
target
983+
->Set(context,
984+
FIXED_ONE_BYTE_STRING(env->isolate(), "shouldNotRegisterESMLoader"),
985+
Boolean::New(isolate, env->should_not_register_esm_loader()))
986+
.Check();
987+
982988
Local<Object> types = Object::New(isolate);
983989
NODE_DEFINE_CONSTANT(types, kNoOp);
984990
NODE_DEFINE_CONSTANT(types, kV8Option);

test/cctest/test_environment.cc

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,56 @@ class EnvironmentTest : public EnvironmentTestFixture {
3232
}
3333
};
3434

35+
TEST_F(EnvironmentTest, EnvironmentWithESMLoader) {
36+
const v8::HandleScope handle_scope(isolate_);
37+
Argv argv;
38+
Env env {handle_scope, argv};
39+
40+
node::Environment* envi = *env;
41+
envi->options()->experimental_vm_modules = true;
42+
43+
SetProcessExitHandler(*env, [&](node::Environment* env_, int exit_code) {
44+
EXPECT_EQ(*env, env_);
45+
EXPECT_EQ(exit_code, 0);
46+
node::Stop(*env);
47+
});
48+
49+
node::LoadEnvironment(
50+
*env,
51+
"const { SourceTextModule } = require('vm');"
52+
"try {"
53+
"new SourceTextModule('export const a = 1;');"
54+
"process.exit(0);"
55+
"} catch {"
56+
"process.exit(42);"
57+
"}");
58+
}
59+
60+
TEST_F(EnvironmentTest, EnvironmentWithNoESMLoader) {
61+
const v8::HandleScope handle_scope(isolate_);
62+
Argv argv;
63+
Env env {handle_scope, argv, node::EnvironmentFlags::kNoRegisterESMLoader};
64+
65+
node::Environment* envi = *env;
66+
envi->options()->experimental_vm_modules = true;
67+
68+
SetProcessExitHandler(*env, [&](node::Environment* env_, int exit_code) {
69+
EXPECT_EQ(*env, env_);
70+
EXPECT_EQ(exit_code, 42);
71+
node::Stop(*env);
72+
});
73+
74+
node::LoadEnvironment(
75+
*env,
76+
"const { SourceTextModule } = require('vm');"
77+
"try {"
78+
"new SourceTextModule('export const a = 1;');"
79+
"process.exit(0);"
80+
"} catch {"
81+
"process.exit(42);"
82+
"}");
83+
}
84+
3585
TEST_F(EnvironmentTest, PreExecutionPreparation) {
3686
const v8::HandleScope handle_scope(isolate_);
3787
const Argv argv;

0 commit comments

Comments
 (0)