Skip to content

Commit 4a803cf

Browse files
committed
esm: avoid import.meta setup costs for unused properties
PR-URL: #57286 Reviewed-By: Jacob Smith <[email protected]> Reviewed-By: Edy Silva <[email protected]>
1 parent 40315d5 commit 4a803cf

File tree

3 files changed

+83
-7
lines changed

3 files changed

+83
-7
lines changed

lib/internal/modules/esm/initialize_import_meta.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ const {
55
} = primordials;
66

77
const { getOptionValue } = require('internal/options');
8-
const { fileURLToPath } = require('internal/url');
9-
const { dirname } = require('path');
8+
const {
9+
setLazyPathHelpers,
10+
} = internalBinding('modules');
11+
1012
const experimentalImportMetaResolve = getOptionValue('--experimental-import-meta-resolve');
1113

1214
/**
@@ -58,11 +60,9 @@ function initializeImportMeta(meta, context, loader) {
5860

5961
// Alphabetical
6062
if (StringPrototypeStartsWith(url, 'file:') === true) {
61-
// These only make sense for locally loaded modules,
62-
// i.e. network modules are not supported.
63-
const filePath = fileURLToPath(url);
64-
meta.dirname = dirname(filePath);
65-
meta.filename = filePath;
63+
// dirname
64+
// filename
65+
setLazyPathHelpers(meta, url);
6666
}
6767

6868
if (!loader || loader.allowImportMetaResolve) {

src/env_properties.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@
124124
V(destroyed_string, "destroyed") \
125125
V(detached_string, "detached") \
126126
V(dh_string, "DH") \
127+
V(dirname_string, "dirname") \
127128
V(divisor_length_string, "divisorLength") \
128129
V(dns_a_string, "A") \
129130
V(dns_aaaa_string, "AAAA") \
@@ -327,6 +328,7 @@
327328
"export * from 'original'; export { default } from 'original'; export " \
328329
"const __esModule = true;") \
329330
V(require_string, "require") \
331+
V(resolve_string, "resolve") \
330332
V(resource_string, "resource") \
331333
V(result_string, "result") \
332334
V(retry_string, "retry") \

src/node_modules.cc

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ using v8::NewStringType;
3030
using v8::Object;
3131
using v8::ObjectTemplate;
3232
using v8::Primitive;
33+
using v8::PropertyCallbackInfo;
3334
using v8::String;
3435
using v8::Undefined;
3536
using v8::Value;
@@ -529,6 +530,77 @@ void GetCompileCacheDir(const FunctionCallbackInfo<Value>& args) {
529530
.ToLocalChecked());
530531
}
531532

533+
static void PathHelpersLazyGetter(Local<v8::Name> name,
534+
const PropertyCallbackInfo<Value>& info) {
535+
Isolate* isolate = info.GetIsolate();
536+
// This getter has no JavaScript function representation and is not
537+
// invoked in the creation context.
538+
// When this getter is invoked in a vm context, the `Realm::GetCurrent(info)`
539+
// returns a nullptr and retrieve the creation context via `this` object and
540+
// get the creation Realm.
541+
Local<Value> receiver_val = info.This();
542+
if (!receiver_val->IsObject()) {
543+
THROW_ERR_INVALID_INVOCATION(isolate);
544+
return;
545+
}
546+
Local<Object> receiver = receiver_val.As<Object>();
547+
Local<Context> context;
548+
if (!receiver->GetCreationContext().ToLocal(&context)) {
549+
THROW_ERR_INVALID_INVOCATION(isolate);
550+
return;
551+
}
552+
Environment* env = Environment::GetCurrent(context);
553+
554+
node::Utf8Value url(isolate, info.Data());
555+
auto file_url = ada::parse(url.ToStringView());
556+
CHECK(file_url);
557+
auto file_path = url::FileURLToPath(env, *file_url);
558+
CHECK(file_path.has_value());
559+
std::string_view ret_view = file_path.value();
560+
561+
node::Utf8Value utf8name(isolate, name);
562+
auto plain_name = utf8name.ToStringView();
563+
if (plain_name == "dirname") {
564+
#ifdef _WIN32
565+
#define PATH_SEPARATOR '\\'
566+
#else
567+
#define PATH_SEPARATOR '/'
568+
#endif
569+
auto index = ret_view.rfind(PATH_SEPARATOR);
570+
CHECK(index != std::string_view::npos);
571+
ret_view.remove_suffix(ret_view.size() - index);
572+
#undef PATH_SEPARATOR
573+
}
574+
Local<Value> ret;
575+
if (!ToV8Value(context, ret_view, isolate).ToLocal(&ret)) {
576+
return;
577+
}
578+
info.GetReturnValue().Set(ret);
579+
}
580+
void InitImportMetaPathHelpers(const FunctionCallbackInfo<Value>& args) {
581+
// target, url, shouldSetDirnameAndFilename, resolve
582+
CHECK_GE(args.Length(), 2);
583+
CHECK(args[0]->IsObject());
584+
CHECK(args[1]->IsString());
585+
586+
Isolate* isolate = args.GetIsolate();
587+
Local<Context> context = isolate->GetCurrentContext();
588+
Environment* env = Environment::GetCurrent(context);
589+
590+
auto target = args[0].As<Object>();
591+
592+
// N.B.: Order is important to keep keys in alphabetical order.
593+
if (target
594+
->SetLazyDataProperty(
595+
context, env->dirname_string(), PathHelpersLazyGetter, args[1])
596+
.IsNothing() ||
597+
target
598+
->SetLazyDataProperty(
599+
context, env->filename_string(), PathHelpersLazyGetter, args[1])
600+
.IsNothing())
601+
return;
602+
}
603+
532604
void BindingData::CreatePerIsolateProperties(IsolateData* isolate_data,
533605
Local<ObjectTemplate> target) {
534606
Isolate* isolate = isolate_data->isolate();
@@ -547,6 +619,7 @@ void BindingData::CreatePerIsolateProperties(IsolateData* isolate_data,
547619
SetMethod(isolate, target, "enableCompileCache", EnableCompileCache);
548620
SetMethod(isolate, target, "getCompileCacheDir", GetCompileCacheDir);
549621
SetMethod(isolate, target, "flushCompileCache", FlushCompileCache);
622+
SetMethod(isolate, target, "setLazyPathHelpers", InitImportMetaPathHelpers);
550623
}
551624

552625
void BindingData::CreatePerContextProperties(Local<Object> target,
@@ -581,6 +654,7 @@ void BindingData::RegisterExternalReferences(
581654
registry->Register(EnableCompileCache);
582655
registry->Register(GetCompileCacheDir);
583656
registry->Register(FlushCompileCache);
657+
registry->Register(InitImportMetaPathHelpers);
584658
}
585659

586660
} // namespace modules

0 commit comments

Comments
 (0)