module: add __esModule to require()'d ESM · nodejs/node@f9dc1ea
@@ -966,6 +966,70 @@ void ModuleWrap::CreateCachedData(const FunctionCallbackInfo<Value>& args) {
966966 }
967967}
968968969+// This v8::Module::ResolveModuleCallback simply links `import 'original'`
970+// to the env->temporary_required_module_facade_original() which is stashed
971+// right before this callback is called and will be restored as soon as
972+// v8::Module::Instantiate() returns.
973+MaybeLocal<Module> LinkRequireFacadeWithOriginal(
974+ Local<Context> context,
975+ Local<String> specifier,
976+ Local<FixedArray> import_attributes,
977+ Local<Module> referrer) {
978+ Environment* env = Environment::GetCurrent(context);
979+ Isolate* isolate = context->GetIsolate();
980+CHECK(specifier->Equals(context, env->original_string()).ToChecked());
981+CHECK(!env->temporary_required_module_facade_original.IsEmpty());
982+return env->temporary_required_module_facade_original.Get(isolate);
983+}
984+985+// Wraps an existing source text module with a facade that adds
986+// .__esModule = true to the exports.
987+// See env->required_module_facade_source_string() for the source.
988+void ModuleWrap::CreateRequiredModuleFacade(
989+const FunctionCallbackInfo<Value>& args) {
990+ Isolate* isolate = args.GetIsolate();
991+ Local<Context> context = isolate->GetCurrentContext();
992+ Environment* env = Environment::GetCurrent(context);
993+CHECK(args[0]->IsObject()); // original module
994+ Local<Object> wrap = args[0].As<Object>();
995+ ModuleWrap* original;
996+ASSIGN_OR_RETURN_UNWRAP(&original, wrap);
997+998+// Use the same facade source and URL to hit the compilation cache.
999+ ScriptOrigin origin(isolate,
1000+ env->required_module_facade_url_string(),
1001+0, // line offset
1002+0, // column offset
1003+true, // is cross origin
1004+ -1, // script id
1005+ Local<Value>(), // source map URL
1006+false, // is opaque (?)
1007+false, // is WASM
1008+true); // is ES Module
1009+ ScriptCompiler::Source source(env->required_module_facade_source_string(),
1010+ origin);
1011+1012+// The module facade instantiation simply links `import 'original'` in the
1013+// facade with the original module and should never fail.
1014+ Local<Module> facade =
1015+ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
1016+// Stash the original module in temporary_required_module_facade_original
1017+// for the LinkRequireFacadeWithOriginal() callback to pick it up.
1018+CHECK(env->temporary_required_module_facade_original.IsEmpty());
1019+ env->temporary_required_module_facade_original.Reset(
1020+ isolate, original->module_.Get(isolate));
1021+CHECK(facade->InstantiateModule(context, LinkRequireFacadeWithOriginal)
1022+ .IsJust());
1023+ env->temporary_required_module_facade_original.Reset();
1024+1025+// The evaluation of the facade is synchronous.
1026+ Local<Value> evaluated = facade->Evaluate(context).ToLocalChecked();
1027+CHECK(evaluated->IsPromise());
1028+CHECK_EQ(evaluated.As<Promise>()->State(), Promise::PromiseState::kFulfilled);
1029+1030+ args.GetReturnValue().Set(facade->GetModuleNamespace());
1031+}
1032+9691033void ModuleWrap::CreatePerIsolateProperties(IsolateData* isolate_data,
9701034 Local<ObjectTemplate> target) {
9711035 Isolate* isolate = isolate_data->isolate();
@@ -998,6 +1062,10 @@ void ModuleWrap::CreatePerIsolateProperties(IsolateData* isolate_data,
9981062 target,
9991063"setInitializeImportMetaObjectCallback",
10001064 SetInitializeImportMetaObjectCallback);
1065+SetMethod(isolate,
1066+ target,
1067+"createRequiredModuleFacade",
1068+ CreateRequiredModuleFacade);
10011069}
1002107010031071void ModuleWrap::CreatePerContextProperties(Local<Object> target,
@@ -1038,6 +1106,8 @@ void ModuleWrap::RegisterExternalReferences(
10381106 registry->Register(GetStatus);
10391107 registry->Register(GetError);
104011081109+ registry->Register(CreateRequiredModuleFacade);
1110+10411111 registry->Register(SetImportModuleDynamicallyCallback);
10421112 registry->Register(SetInitializeImportMetaObjectCallback);
10431113}