module: add isPreloading indicator

Adds a `module.isPreloading` property that is `true` only during the
preload (`-r`) phase of Node.js bootstrap. This provides modules an
easy, non-hacky way of knowing if they are being loaded during preload.

Signed-off-by: James M Snell <jasnell@gmail.com>

PR-URL: https://github.com/nodejs/node/pull/36263
Reviewed-By: Gerhard Stöbich <deb2001-github@yahoo.de>
Reviewed-By: Rich Trott <rtrott@gmail.com>
This commit is contained in:
James M Snell 2020-11-25 07:54:32 -08:00
parent 709ada5c3a
commit 8ff2501a04
No known key found for this signature in database
GPG Key ID: 7341B15C070877AC
4 changed files with 32 additions and 0 deletions

View File

@ -76,6 +76,14 @@ const requireUtil = createRequireFromPath('../src/utils/');
requireUtil('./some-tool'); requireUtil('./some-tool');
``` ```
### `module.isPreloading`
<!-- YAML
added: REPLACEME
-->
* Type: {boolean} `true` if the module is running during the Node.js preload
phase.
### `module.syncBuiltinESMExports()` ### `module.syncBuiltinESMExports()`
<!-- YAML <!-- YAML
added: v12.12.0 added: v12.12.0

View File

@ -139,6 +139,7 @@ const relativeResolveCache = ObjectCreate(null);
let requireDepth = 0; let requireDepth = 0;
let statCache = null; let statCache = null;
let isPreloading = false;
function stat(filename) { function stat(filename) {
filename = path.toNamespacedPath(filename); filename = path.toNamespacedPath(filename);
@ -231,6 +232,10 @@ ObjectDefineProperty(Module, 'wrapper', {
} }
}); });
ObjectDefineProperty(Module.prototype, 'isPreloading', {
get() { return isPreloading; }
});
function getModuleParent() { function getModuleParent() {
return moduleParentCache.get(this); return moduleParentCache.get(this);
} }
@ -1243,6 +1248,8 @@ Module._preloadModules = function(requests) {
if (!ArrayIsArray(requests)) if (!ArrayIsArray(requests))
return; return;
isPreloading = true;
// Preloaded modules have a dummy parent module which is deemed to exist // Preloaded modules have a dummy parent module which is deemed to exist
// in the current working directory. This seeds the search path for // in the current working directory. This seeds the search path for
// preloaded modules. // preloaded modules.
@ -1251,11 +1258,13 @@ Module._preloadModules = function(requests) {
parent.paths = Module._nodeModulePaths(process.cwd()); parent.paths = Module._nodeModulePaths(process.cwd());
} catch (e) { } catch (e) {
if (e.code !== 'ENOENT') { if (e.code !== 'ENOENT') {
isPreloading = false;
throw e; throw e;
} }
} }
for (let n = 0; n < requests.length; n++) for (let n = 0; n < requests.length; n++)
parent.require(requests[n]); parent.require(requests[n]);
isPreloading = false;
}; };
Module.syncBuiltinESMExports = function syncBuiltinESMExports() { Module.syncBuiltinESMExports = function syncBuiltinESMExports() {

2
test/fixtures/ispreloading.js vendored Normal file
View File

@ -0,0 +1,2 @@
const assert = require('assert');
assert(module.isPreloading);

View File

@ -27,6 +27,19 @@ const fixtureE = fixtures.path('intrinsic-mutation.js');
const fixtureF = fixtures.path('print-intrinsic-mutation-name.js'); const fixtureF = fixtures.path('print-intrinsic-mutation-name.js');
const fixtureG = fixtures.path('worker-from-argv.js'); const fixtureG = fixtures.path('worker-from-argv.js');
const fixtureThrows = fixtures.path('throws_error4.js'); const fixtureThrows = fixtures.path('throws_error4.js');
const fixtureIsPreloading = fixtures.path('ispreloading.js');
// Assert that module.isPreloading is false here
assert(!module.isPreloading);
// Test that module.isPreloading is set in preloaded module
// Test preloading a single module works
childProcess.exec(
`"${nodeBinary}" ${preloadOption([fixtureIsPreloading])} "${fixtureB}"`,
function(err, stdout, stderr) {
assert.ifError(err);
assert.strictEqual(stdout, 'B\n');
});
// Test preloading a single module works // Test preloading a single module works
childProcess.exec(`"${nodeBinary}" ${preloadOption([fixtureA])} "${fixtureB}"`, childProcess.exec(`"${nodeBinary}" ${preloadOption([fixtureA])} "${fixtureB}"`,