@@ -524,6 +524,7 @@ Maybe<std::string> ReadIfFile(const std::string& path) {
524524using Exists = PackageConfig::Exists;
525525using IsValid = PackageConfig::IsValid;
526526using HasMain = PackageConfig::HasMain;
527+ using HasExports = PackageConfig::HasExports;
527528using IsESM = PackageConfig::IsESM;
528529
529530Maybe<const PackageConfig*> GetPackageConfig (Environment* env,
@@ -538,8 +539,8 @@ Maybe<const PackageConfig*> GetPackageConfig(Environment* env,
538539
539540 if (source.IsNothing ()) {
540541 auto entry = env->package_json_cache .emplace (path,
541- PackageConfig { Exists::No, IsValid::Yes, HasMain::No, " " ,
542- IsESM::No });
542+ PackageConfig { Exists::No, IsValid::Yes, HasMain::No, HasExports::No ,
543+ " " , IsESM::No });
543544 return Just (&entry.first ->second );
544545 }
545546
@@ -565,8 +566,8 @@ Maybe<const PackageConfig*> GetPackageConfig(Environment* env,
565566
566567 if (!parsed) {
567568 (void )env->package_json_cache .emplace (path,
568- PackageConfig { Exists::Yes, IsValid::No, HasMain::No, " " ,
569- IsESM::No });
569+ PackageConfig { Exists::Yes, IsValid::No, HasMain::No, HasExports::No ,
570+ " " , IsESM::No });
570571 std::string msg = " Invalid JSON in '" + path +
571572 " ' imported from " + base.ToFilePath ();
572573 node::THROW_ERR_INVALID_PACKAGE_CONFIG (env, msg.c_str ());
@@ -575,8 +576,17 @@ Maybe<const PackageConfig*> GetPackageConfig(Environment* env,
575576
576577 Local<Value> pkg_main;
577578 HasMain::Bool has_main = HasMain::No;
579+ HasExports::Bool has_exports = HasExports::No;
578580 std::string main_std;
579- if (pkg_json->Get (env->context (), env->main_string ()).ToLocal (&pkg_main)) {
581+ if (pkg_json->Get (env->context (), env->exports_string ()).ToLocal (&pkg_main)) {
582+ if (pkg_main->IsString ()) {
583+ has_main = HasMain::Yes;
584+ has_exports = HasExports::Yes;
585+ }
586+ Utf8Value main_utf8 (isolate, pkg_main);
587+ main_std.assign (std::string (*main_utf8, main_utf8.length ()));
588+ } else if (pkg_json->Get (env->context (),
589+ env->main_string ()).ToLocal (&pkg_main)) {
580590 if (pkg_main->IsString ()) {
581591 has_main = HasMain::Yes;
582592 }
@@ -592,24 +602,9 @@ Maybe<const PackageConfig*> GetPackageConfig(Environment* env,
592602 }
593603 }
594604
595- Local<Value> exports_v;
596- if (pkg_json->Get (env->context (),
597- env->exports_string ()).ToLocal (&exports_v) &&
598- (exports_v->IsObject () || exports_v->IsString () ||
599- exports_v->IsBoolean ())) {
600- Persistent<Value> exports;
601- // esm = IsESM::Yes;
602- exports.Reset (env->isolate (), exports_v);
603-
604- auto entry = env->package_json_cache .emplace (path,
605- PackageConfig { Exists::Yes, IsValid::Yes, has_main, main_std,
606- esm });
607- return Just (&entry.first ->second );
608- }
609-
610605 auto entry = env->package_json_cache .emplace (path,
611- PackageConfig { Exists::Yes, IsValid::Yes, has_main, main_std ,
612- esm });
606+ PackageConfig { Exists::Yes, IsValid::Yes, has_main, has_exports ,
607+ main_std, esm });
613608 return Just (&entry.first ->second );
614609}
615610
@@ -630,8 +625,8 @@ Maybe<const PackageConfig*> GetPackageBoundaryConfig(Environment* env,
630625 // (can't just check "/package.json" for Windows support).
631626 if (pjson_url.path () == last_pjson_url.path ()) {
632627 auto entry = env->package_json_cache .emplace (pjson_url.ToFilePath (),
633- PackageConfig { Exists::No, IsValid::Yes, HasMain::No, " " ,
634- IsESM::No });
628+ PackageConfig { Exists::No, IsValid::Yes, HasMain::No,
629+ HasExports::No, " " , IsESM::No });
635630 return Just (&entry.first ->second );
636631 }
637632 }
@@ -757,15 +752,20 @@ Maybe<ModuleResolution> PackageMainResolve(Environment* env,
757752 node::THROW_ERR_MODULE_NOT_FOUND (env, msg.c_str ());
758753 return Nothing<ModuleResolution>();
759754 }
760- if (pcfg.has_main == HasMain::Yes &&
761- pcfg.main .substr (pcfg.main .length () - 4 , 4 ) == " .mjs" ) {
762- return FinalizeResolution (env, URL (pcfg.main , pjson_url), base, true );
763- }
764- if (pcfg.esm == IsESM::Yes &&
765- pcfg.main .substr (pcfg.main .length () - 3 , 3 ) == " .js" ) {
755+ if (pcfg.has_exports == HasExports::Yes) {
756+ const size_t main_len = pcfg.main .length ();
757+ if (main_len > 4 && pcfg.main .substr (main_len - 4 , 4 ) == " .cjs" ||
758+ (pcfg.esm == IsESM::No &&
759+ main_len > 3 && pcfg.main .substr (main_len - 3 , 3 ) == " .js" )) {
760+ std::string msg = " Cannot load exports entry point '" +
761+ pcfg.main + " ' in " + URL (" ." , pjson_url).ToFilePath () +
762+ " imported from " + base.ToFilePath () +
763+ " as it would be loaded as CommonJS." ;
764+ node::THROW_ERR_UNSUPPORTED_MODULE_FORMAT (env, msg.c_str ());
765+ return Nothing<ModuleResolution>();
766+ }
766767 return FinalizeResolution (env, URL (pcfg.main , pjson_url), base, true );
767768 }
768-
769769 Maybe<URL> resolved = LegacyMainResolve (pjson_url, pcfg);
770770 // Legacy main resolution error
771771 if (resolved.IsNothing ()) {
0 commit comments