|
| 1 | +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
| 2 | +From: Fedor Indutny < [email protected]> |
| 3 | +Date: Mon, 31 Mar 2025 11:21:29 -0700 |
| 4 | +Subject: fix: expose ReadFileSync override for modules |
| 5 | + |
| 6 | +To avoid copying out `package.json` files out of the ASAR file we need |
| 7 | +an API override to replace the native `ReadFileSync` in the `modules` |
| 8 | +binding. |
| 9 | + |
| 10 | +diff --git a/src/env_properties.h b/src/env_properties.h |
| 11 | +index 9f89823170782242093bc5ee0df6a2a2ef5b919f..b9374ee1acceb3d0aab51c6c5ae6a79be1cc71a9 100644 |
| 12 | +--- a/src/env_properties.h |
| 13 | ++++ b/src/env_properties.h |
| 14 | +@@ -478,6 +478,7 @@ |
| 15 | + V(maybe_cache_generated_source_map, v8::Function) \ |
| 16 | + V(messaging_deserialize_create_object, v8::Function) \ |
| 17 | + V(message_port, v8::Object) \ |
| 18 | ++ V(modules_read_file_sync, v8::Function) \ |
| 19 | + V(builtin_module_require, v8::Function) \ |
| 20 | + V(performance_entry_callback, v8::Function) \ |
| 21 | + V(prepare_stack_trace_callback, v8::Function) \ |
| 22 | +diff --git a/src/node_modules.cc b/src/node_modules.cc |
| 23 | +index 4e9f70a1c41b44d2a1863b778d4f1e37279178d9..c56a32885b8debbd5b95a2c11f3838d4088e05ac 100644 |
| 24 | +--- a/src/node_modules.cc |
| 25 | ++++ b/src/node_modules.cc |
| 26 | +@@ -21,6 +21,7 @@ namespace modules { |
| 27 | + |
| 28 | + using v8::Array; |
| 29 | + using v8::Context; |
| 30 | ++using v8::Function; |
| 31 | + using v8::FunctionCallbackInfo; |
| 32 | + using v8::HandleScope; |
| 33 | + using v8::Isolate; |
| 34 | +@@ -88,6 +89,7 @@ Local<Array> BindingData::PackageConfig::Serialize(Realm* realm) const { |
| 35 | + |
| 36 | + const BindingData::PackageConfig* BindingData::GetPackageJSON( |
| 37 | + Realm* realm, std::string_view path, ErrorContext* error_context) { |
| 38 | ++ auto isolate = realm->isolate(); |
| 39 | + auto binding_data = realm->GetBindingData<BindingData>(); |
| 40 | + |
| 41 | + auto cache_entry = binding_data->package_configs_.find(path.data()); |
| 42 | +@@ -97,8 +99,36 @@ const BindingData::PackageConfig* BindingData::GetPackageJSON( |
| 43 | + |
| 44 | + PackageConfig package_config{}; |
| 45 | + package_config.file_path = path; |
| 46 | ++ |
| 47 | ++ Local<Function> modules_read_file_sync = realm->modules_read_file_sync(); |
| 48 | ++ |
| 49 | ++ int read_err; |
| 50 | + // No need to exclude BOM since simdjson will skip it. |
| 51 | +- if (ReadFileSync(&package_config.raw_json, path.data()) < 0) { |
| 52 | ++ if (modules_read_file_sync.IsEmpty()) { |
| 53 | ++ read_err = ReadFileSync(&package_config.raw_json, path.data()); |
| 54 | ++ } else { |
| 55 | ++ Local<Value> args[] = { |
| 56 | ++ v8::String::NewFromUtf8(isolate, path.data()).ToLocalChecked(), |
| 57 | ++ }; |
| 58 | ++ Local<Value> result = modules_read_file_sync->Call( |
| 59 | ++ realm->context(), |
| 60 | ++ Undefined(isolate), |
| 61 | ++ arraysize(args), |
| 62 | ++ args).ToLocalChecked(); |
| 63 | ++ |
| 64 | ++ if (result->IsUndefined()) { |
| 65 | ++ // Fallback |
| 66 | ++ read_err = ReadFileSync(&package_config.raw_json, path.data()); |
| 67 | ++ } else if (result->IsFalse()) { |
| 68 | ++ // Not found |
| 69 | ++ read_err = -1; |
| 70 | ++ } else { |
| 71 | ++ BufferValue data(isolate, result); |
| 72 | ++ package_config.raw_json = data.ToString(); |
| 73 | ++ read_err = 0; |
| 74 | ++ } |
| 75 | ++ } |
| 76 | ++ if (read_err < 0) { |
| 77 | + return nullptr; |
| 78 | + } |
| 79 | + // In some systems, std::string is annotated to generate an |
| 80 | +@@ -248,6 +278,12 @@ const BindingData::PackageConfig* BindingData::GetPackageJSON( |
| 81 | + return &cached.first->second; |
| 82 | + } |
| 83 | + |
| 84 | ++void BindingData::OverrideReadFileSync(const FunctionCallbackInfo<Value>& args) { |
| 85 | ++ Realm* realm = Realm::GetCurrent(args); |
| 86 | ++ CHECK(args[0]->IsFunction()); |
| 87 | ++ realm->set_modules_read_file_sync(args[0].As<Function>()); |
| 88 | ++} |
| 89 | ++ |
| 90 | + void BindingData::ReadPackageJSON(const FunctionCallbackInfo<Value>& args) { |
| 91 | + CHECK_GE(args.Length(), 1); // path, [is_esm, base, specifier] |
| 92 | + CHECK(args[0]->IsString()); // path |
| 93 | +@@ -556,6 +592,8 @@ void GetCompileCacheDir(const FunctionCallbackInfo<Value>& args) { |
| 94 | + void BindingData::CreatePerIsolateProperties(IsolateData* isolate_data, |
| 95 | + Local<ObjectTemplate> target) { |
| 96 | + Isolate* isolate = isolate_data->isolate(); |
| 97 | ++ SetMethod(isolate, target, "overrideReadFileSync", OverrideReadFileSync); |
| 98 | ++ |
| 99 | + SetMethod(isolate, target, "readPackageJSON", ReadPackageJSON); |
| 100 | + SetMethod(isolate, |
| 101 | + target, |
| 102 | +@@ -595,6 +633,8 @@ void BindingData::CreatePerContextProperties(Local<Object> target, |
| 103 | + |
| 104 | + void BindingData::RegisterExternalReferences( |
| 105 | + ExternalReferenceRegistry* registry) { |
| 106 | ++ registry->Register(OverrideReadFileSync); |
| 107 | ++ |
| 108 | + registry->Register(ReadPackageJSON); |
| 109 | + registry->Register(GetNearestParentPackageJSONType); |
| 110 | + registry->Register(GetNearestParentPackageJSON); |
| 111 | +diff --git a/src/node_modules.h b/src/node_modules.h |
| 112 | +index 17909b2270454b3275c7bf2e50d4b9b35673ecc8..3d5b0e3ac65524adfe221bfd6f85360dee1f0bee 100644 |
| 113 | +--- a/src/node_modules.h |
| 114 | ++++ b/src/node_modules.h |
| 115 | +@@ -54,6 +54,8 @@ class BindingData : public SnapshotableObject { |
| 116 | + SET_SELF_SIZE(BindingData) |
| 117 | + SET_MEMORY_INFO_NAME(BindingData) |
| 118 | + |
| 119 | ++ static void OverrideReadFileSync( |
| 120 | ++ const v8::FunctionCallbackInfo<v8::Value>& args); |
| 121 | + static void ReadPackageJSON(const v8::FunctionCallbackInfo<v8::Value>& args); |
| 122 | + static void GetNearestParentPackageJSON( |
| 123 | + const v8::FunctionCallbackInfo<v8::Value>& args); |
0 commit comments