src: add initial support for ESM in embedder API · nodejs/node@563ab69 · GitHub
Skip to content

Commit 563ab69

Browse files
joyeecheungaduh95
authored andcommitted
src: add initial support for ESM in embedder API
This patch extends `LoadEnvironment` to support loading ES modules, and adds the following new types: ```cpp enum class ModuleFormat : uint8_t { kCommonJS, kModule, }; // Data for specifying an entry point script for LoadEnvironment(). // This class uses an opaque layout to allow future additions without // breaking ABI. Use the setter methods to configure the entry point. class ModuleData { void set_source(std::string_view source); void set_format(ModuleFormat format); void set_resource_name(std::string_view name); std::string_view source() const; ModuleFormat format() const; std::string_view resource_name() const; }; class StartExecutionCallbackInfoWithModule { void set_env(Environment* env); void set_process_object(v8::Local<v8::Object> process_object); void set_native_require(v8::Local<v8::Function> native_require); void set_run_module(v8::Local<v8::Function> run_module); void set_data(void* data); Environment* env(); v8::Local<v8::Object> process(); v8::Local<v8::Function> native_require(); v8::Local<v8::Function> run_module(); void* data(); }; ``` And two new `LoadEnvironment()` overloads: ```cpp // Run entry point with ModuleData configuration MaybeLocal<Value> LoadEnvironment( Environment* env, const ModuleData* entry_point, EmbedderPreloadCallback preload = nullptr); // Callback-based with new StartExecutionCallbackInfoWithModule MaybeLocal<Value> LoadEnvironment( Environment* env, StartExecutionCallbackWithModule cb, EmbedderPreloadCallback preload = nullptr, void* callback_data = nullptr); ``` PR-URL: #61548 Refs: #53565 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Aditi Singh <aditisingh1400@gmail.com>
1 parent 83bcd38 commit 563ab69

10 files changed

Lines changed: 502 additions & 58 deletions

File tree

lib/internal/main/embedding.js

Lines changed: 80 additions & 17 deletions

src/api/environment.cc

Lines changed: 138 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,7 @@ NODE_EXTERN std::unique_ptr<InspectorParentHandle> GetInspectorParentHandle(
574574
}
575575

576576
MaybeLocal<Value> LoadEnvironment(Environment* env,
577-
StartExecutionCallback cb,
577+
StartExecutionCallbackWithModule cb,
578578
EmbedderPreloadCallback preload) {
579579
env->InitializeLibuv();
580580
env->InitializeDiagnostics();
@@ -586,22 +586,149 @@ MaybeLocal<Value> LoadEnvironment(Environment* env,
586586
return StartExecution(env, cb);
587587
}
588588

589+
struct StartExecutionCallbackInfoWithModule::Impl {
590+
Environment* env = nullptr;
591+
Local<Object> process_object;
592+
Local<Function> native_require;
593+
Local<Function> run_module;
594+
};
595+
596+
StartExecutionCallbackInfoWithModule::StartExecutionCallbackInfoWithModule()
597+
: impl_(std::make_unique<Impl>()) {}
598+
599+
StartExecutionCallbackInfoWithModule::~StartExecutionCallbackInfoWithModule() =
600+
default;
601+
602+
StartExecutionCallbackInfoWithModule::StartExecutionCallbackInfoWithModule(
603+
StartExecutionCallbackInfoWithModule&&) = default;
604+
605+
StartExecutionCallbackInfoWithModule&
606+
StartExecutionCallbackInfoWithModule::operator=(
607+
StartExecutionCallbackInfoWithModule&&) = default;
608+
609+
Environment* StartExecutionCallbackInfoWithModule::env() const {
610+
return impl_->env;
611+
}
612+
613+
Local<Object> StartExecutionCallbackInfoWithModule::process_object() const {
614+
return impl_->process_object;
615+
}
616+
617+
Local<Function> StartExecutionCallbackInfoWithModule::native_require() const {
618+
return impl_->native_require;
619+
}
620+
621+
Local<Function> StartExecutionCallbackInfoWithModule::run_module() const {
622+
return impl_->run_module;
623+
}
624+
625+
void StartExecutionCallbackInfoWithModule::set_env(Environment* env) {
626+
impl_->env = env;
627+
}
628+
629+
void StartExecutionCallbackInfoWithModule::set_process_object(
630+
Local<Object> process_object) {
631+
impl_->process_object = process_object;
632+
}
633+
634+
void StartExecutionCallbackInfoWithModule::set_native_require(
635+
Local<Function> native_require) {
636+
impl_->native_require = native_require;
637+
}
638+
639+
void StartExecutionCallbackInfoWithModule::set_run_module(
640+
Local<Function> run_module) {
641+
impl_->run_module = run_module;
642+
}
643+
644+
struct ModuleData::Impl {
645+
std::string_view source;
646+
ModuleFormat format = ModuleFormat::kCommonJS;
647+
std::string_view resource_name;
648+
};
649+
650+
ModuleData::ModuleData() : impl_(std::make_unique<Impl>()) {}
651+
652+
ModuleData::~ModuleData() = default;
653+
654+
ModuleData::ModuleData(ModuleData&&) = default;
655+
656+
ModuleData& ModuleData::operator=(ModuleData&&) = default;
657+
658+
void ModuleData::set_source(std::string_view source) {
659+
impl_->source = source;
660+
}
661+
662+
void ModuleData::set_format(ModuleFormat format) {
663+
impl_->format = format;
664+
}
665+
666+
void ModuleData::set_resource_name(std::string_view name) {
667+
impl_->resource_name = name;
668+
}
669+
670+
std::string_view ModuleData::source() const {
671+
return impl_->source;
672+
}
673+
674+
ModuleFormat ModuleData::format() const {
675+
return impl_->format;
676+
}
677+
678+
std::string_view ModuleData::resource_name() const {
679+
return impl_->resource_name;
680+
}
681+
682+
MaybeLocal<Value> LoadEnvironment(Environment* env,
683+
StartExecutionCallback cb,
684+
EmbedderPreloadCallback preload) {
685+
if (!cb) {
686+
return LoadEnvironment(
687+
env, StartExecutionCallbackWithModule{}, std::move(preload));
688+
}
689+
690+
return LoadEnvironment(
691+
env,
692+
[cb = std::move(cb)](const StartExecutionCallbackInfoWithModule& info)
693+
-> MaybeLocal<Value> {
694+
StartExecutionCallbackInfo legacy_info{
695+
info.process_object(), info.native_require(), info.run_module()};
696+
return cb(legacy_info);
697+
},
698+
std::move(preload));
699+
}
700+
589701
MaybeLocal<Value> LoadEnvironment(Environment* env,
590702
std::string_view main_script_source_utf8,
591703
EmbedderPreloadCallback preload) {
704+
ModuleData data;
705+
data.set_source(main_script_source_utf8);
706+
data.set_format(ModuleFormat::kCommonJS);
707+
data.set_resource_name(env->exec_path());
708+
return LoadEnvironment(env, &data, std::move(preload));
709+
}
710+
711+
MaybeLocal<Value> LoadEnvironment(Environment* env,
712+
const ModuleData* data,
713+
EmbedderPreloadCallback preload) {
592714
// It could be empty when it's used by SEA to load an empty script.
593-
CHECK_IMPLIES(main_script_source_utf8.size() > 0,
594-
main_script_source_utf8.data());
715+
CHECK_IMPLIES(data->source().size() > 0, data->source().data());
595716
return LoadEnvironment(
596717
env,
597-
[&](const StartExecutionCallbackInfo& info) -> MaybeLocal<Value> {
598-
Local<Value> main_script;
599-
if (!ToV8Value(env->context(), main_script_source_utf8)
600-
.ToLocal(&main_script)) {
601-
return {};
602-
}
603-
return info.run_cjs->Call(
604-
env->context(), Null(env->isolate()), 1, &main_script);
718+
[data](const StartExecutionCallbackInfoWithModule& info)
719+
-> MaybeLocal<Value> {
720+
Environment* env = info.env();
721+
Local<Context> context = env->context();
722+
Isolate* isolate = env->isolate();
723+
Local<Value> main_script =
724+
ToV8Value(context, data->source()).ToLocalChecked();
725+
Local<Value> format =
726+
v8::Integer::New(isolate, static_cast<int>(data->format()));
727+
Local<Value> resource_name =
728+
ToV8Value(context, data->resource_name()).ToLocalChecked();
729+
Local<Value> args[] = {main_script, format, resource_name};
730+
return info.run_module()->Call(
731+
context, Null(isolate), arraysize(args), args);
605732
},
606733
std::move(preload));
607734
}

src/node.cc

Lines changed: 18 additions & 22 deletions

0 commit comments

Comments
 (0)