diff --git a/lib/internal/bootstrap/pre_execution.js b/lib/internal/bootstrap/pre_execution.js index 0906b35edc5ff3..a4c73cba5481b3 100644 --- a/lib/internal/bootstrap/pre_execution.js +++ b/lib/internal/bootstrap/pre_execution.js @@ -11,7 +11,8 @@ const { const { getOptionValue, - shouldNotRegisterESMLoader + noGlobalSearchPaths, + shouldNotRegisterESMLoader, } = require('internal/options'); const { reconnectZeroFillToggle } = require('internal/buffer'); @@ -420,7 +421,9 @@ function initializeWASI() { function initializeCJSLoader() { const CJSLoader = require('internal/modules/cjs/loader'); - CJSLoader.Module._initPaths(); + if (!noGlobalSearchPaths) { + CJSLoader.Module._initPaths(); + } // TODO(joyeecheung): deprecate this in favor of a proper hook? CJSLoader.Module.runMain = require('internal/modules/run_main').executeUserEntryPoint; diff --git a/lib/internal/options.js b/lib/internal/options.js index aa9c52e6988d65..cb694c7dfdd576 100644 --- a/lib/internal/options.js +++ b/lib/internal/options.js @@ -1,6 +1,10 @@ 'use strict'; -const { getOptions, shouldNotRegisterESMLoader } = internalBinding('options'); +const { + getOptions, + noGlobalSearchPaths, + shouldNotRegisterESMLoader, +} = internalBinding('options'); let warnOnAllowUnauthorized = true; @@ -57,5 +61,6 @@ module.exports = { }, getOptionValue, getAllowUnauthorized, - shouldNotRegisterESMLoader + noGlobalSearchPaths, + shouldNotRegisterESMLoader, }; diff --git a/src/env-inl.h b/src/env-inl.h index 156534bdeee8a1..7c3838dd71a625 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -886,6 +886,10 @@ inline bool Environment::hide_console_windows() const { return flags_ & EnvironmentFlags::kHideConsoleWindows; } +inline bool Environment::no_global_search_paths() const { + return flags_ & EnvironmentFlags::kNoGlobalSearchPaths; +} + bool Environment::filehandle_close_warning() const { return emit_filehandle_warning_; } diff --git a/src/env.h b/src/env.h index f7d1dace414963..f055e6b45013d9 100644 --- a/src/env.h +++ b/src/env.h @@ -1203,6 +1203,7 @@ class Environment : public MemoryRetainer { inline bool owns_inspector() const; inline bool tracks_unmanaged_fds() const; inline bool hide_console_windows() const; + inline bool no_global_search_paths() const; inline uint64_t thread_id() const; inline worker::Worker* worker_context() const; Environment* worker_parent_env() const; diff --git a/src/node.h b/src/node.h index 94b471820a0ead..1f9afa558d0c8b 100644 --- a/src/node.h +++ b/src/node.h @@ -412,7 +412,12 @@ enum Flags : uint64_t { // so that a worker thread can't load a native addon even if `execArgv` // is overwritten and `--no-addons` is not specified but was specified // for this Environment instance. - kNoNativeAddons = 1 << 6 + kNoNativeAddons = 1 << 6, + // Set this flag to disable searching modules from global paths like + // $HOME/.node_modules and $NODE_PATH. This is used by standalone apps that + // do not expect to have their behaviors changed because of globally + // installed modules. + kNoGlobalSearchPaths = 1 << 7 }; } // namespace EnvironmentFlags diff --git a/src/node_options.cc b/src/node_options.cc index 09bf88638dedda..519dd4ce01262d 100644 --- a/src/node_options.cc +++ b/src/node_options.cc @@ -1073,6 +1073,12 @@ void Initialize(Local target, Boolean::New(isolate, env->should_not_register_esm_loader())) .Check(); + target + ->Set(context, + FIXED_ONE_BYTE_STRING(env->isolate(), "noGlobalSearchPaths"), + Boolean::New(isolate, env->no_global_search_paths())) + .Check(); + Local types = Object::New(isolate); NODE_DEFINE_CONSTANT(types, kNoOp); NODE_DEFINE_CONSTANT(types, kV8Option); diff --git a/src/node_worker.cc b/src/node_worker.cc index dcc76ad88f04e2..16b7be36f28431 100644 --- a/src/node_worker.cc +++ b/src/node_worker.cc @@ -572,6 +572,8 @@ void Worker::New(const FunctionCallbackInfo& args) { worker->environment_flags_ |= EnvironmentFlags::kHideConsoleWindows; if (env->no_native_addons()) worker->environment_flags_ |= EnvironmentFlags::kNoNativeAddons; + if (env->no_global_search_paths()) + worker->environment_flags_ |= EnvironmentFlags::kNoGlobalSearchPaths; } void Worker::StartThread(const FunctionCallbackInfo& args) {