From 5b8cf21f07988dddde72b6516ad5b8d3ae221ab5 Mon Sep 17 00:00:00 2001 From: Antoine du HAMEL Date: Wed, 11 Mar 2020 23:44:31 +0100 Subject: [PATCH 1/5] modules: deprecate module.parent This feature does not work when a module is imported using ECMAScript modules specification, therefore it is deprecated. Fixes: https://github.com/nodejs/modules/issues/469 --- doc/api/deprecations.md | 40 +++++++++++++++++++ doc/api/modules.md | 13 ++++-- lib/internal/modules/cjs/loader.js | 20 ++++++++-- test/common/index.js | 4 +- test/common/require-as.js | 2 +- test/js-native-api/test_instance_data/test.js | 2 +- test/node-api/test_instance_data/test.js | 2 +- test/parallel/test-cli-eval.js | 2 +- .../test-module-parent-deprecation.js | 12 ++++++ 9 files changed, 85 insertions(+), 12 deletions(-) create mode 100644 test/parallel/test-module-parent-deprecation.js diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md index cdfe2a63b03089..3e06c9f6f18398 100644 --- a/doc/api/deprecations.md +++ b/doc/api/deprecations.md @@ -2697,6 +2697,46 @@ The `repl` module exports a `_builtinLibs` property that contains an array with native modules. It was incomplete so far and instead it's better to rely upon `require('module').builtinModules`. + +### DEP0143: `module.parent` + +A CJS module can access the first module that required it using `module.parent`. +This feature does not work when a module is imported using ECMAScript modules +specification, therefore it is deprecated. + +Some modules use it to check if they are the entry point of the current process. +Instead, it is recommended to compare `require.main` and `module`: + +```js +if (require.main === module) { + // CLI code runs here +} +``` + +When looking for the CJS modules that have required the current one, +`module.children` can be used: + +```js +const moduleParents = []; +function findCurrentModuleParents(moduleParent = require.main) { + if (moduleParent === undefined) { + // If the entry point is not CJS (E.G.: REPL or ESM), this function is no op + return; + } + const { children } = moduleParent; + if (children.includes(module)) { + moduleParents.push(moduleParent); + } + children.forEach(findCurrentModuleParents); +} +findCurrentModuleParents(); +``` + [`--pending-deprecation`]: cli.html#cli_pending_deprecation [`--throw-deprecation`]: cli.html#cli_throw_deprecation [`Buffer.allocUnsafeSlow(size)`]: buffer.html#buffer_class_method_buffer_allocunsafeslow_size diff --git a/doc/api/modules.md b/doc/api/modules.md index afbc849180b414..04a3dfdb5e0d90 100644 --- a/doc/api/modules.md +++ b/doc/api/modules.md @@ -690,7 +690,6 @@ Module { id: '.', path: '/absolute/path/to', exports: {}, - parent: null, filename: '/absolute/path/to/entry.js', loaded: false, children: [], @@ -894,11 +893,17 @@ loading. ### `module.parent` -* {module} +> Stability: 0 - Deprecated: Please use [`require.main`][] and +> [`module.children`][] instead. + +* {module | null | undefined} -The module that first required this one. +The module that first required this one, or `null` if the current module is the +entry point of the current process, or `undefined` if the module was loaded by +something that is not a CJS module (E.G.: REPL or `import`). Read only. ### `module.path` -A CJS module can access the first module that required it using `module.parent`. -This feature does not work when a module is imported using ECMAScript modules -specification, therefore it is deprecated. + +Type: Documentation-only (supports [`--pending-deprecation`][]) + +A CommonJS module can access the first module that required it using +`module.parent`. This feature is deprecated because it does not work +consistently in the presence of ECMAScript modules and because it gives an +inaccurate representation of the CommonJS module graph. Some modules use it to check if they are the entry point of the current process. Instead, it is recommended to compare `require.main` and `module`: ```js if (require.main === module) { - // CLI code runs here + // Code section that will run only if current file is the entry point. } ``` diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js index 8345d7f21ead47..14b1201936ca58 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -234,25 +234,16 @@ ObjectDefineProperty(Module, 'wrapper', { } }); -let warned = false; +function getModuleParent() { + return moduleParentCache.get(this); +} ObjectDefineProperty(Module.prototype, 'parent', { - get: function() { - const parent = moduleParentCache.get(this); - if ( - !process.noDeprecation && - !warned && - (parent == null || pendingDeprecation) - ) { - warned = true; - process.emitWarning( - 'module.parent is deprecated due to accuracy issues. Please use ' + - 'require.main === module to check for CLI usage instead.', - 'DeprecationWarning', - 'DEP0143' - ); - } - return parent; - } + get: pendingDeprecation ? deprecate( + getModuleParent, + 'module.parent is deprecated due to accuracy issues. Please use ' + + 'require.main to find program entry point instead.', + 'DEP0143' + ) : getModuleParent }); const debug = require('internal/util/debuglog').debuglog('module'); diff --git a/test/parallel/test-module-parent-deprecation.js b/test/parallel/test-module-parent-deprecation.js index 8e1c03401ce531..439e86bc96810a 100644 --- a/test/parallel/test-module-parent-deprecation.js +++ b/test/parallel/test-module-parent-deprecation.js @@ -1,3 +1,5 @@ +// Flags: --pending-deprecation + 'use strict'; const common = require('../common'); const assert = require('assert'); @@ -5,7 +7,7 @@ const assert = require('assert'); common.expectWarning( 'DeprecationWarning', 'module.parent is deprecated due to accuracy issues. Please use ' + - 'require.main === module to check for CLI usage instead.', + 'require.main to find program entry point instead.', 'DEP0143' ); From 0192aae837837a3059233c95c45cc1a5c05d513f Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Mon, 6 Apr 2020 14:39:39 +0200 Subject: [PATCH 5/5] nit: s/CJS/CommonJS/ --- doc/api/deprecations.md | 2 +- doc/api/modules.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md index 75679ab3263f5f..fc14a9dc427f34 100644 --- a/doc/api/deprecations.md +++ b/doc/api/deprecations.md @@ -2722,7 +2722,7 @@ if (require.main === module) { } ``` -When looking for the CJS modules that have required the current one, +When looking for the CommonJS modules that have required the current one, `require.cache` and `module.children` can be used: ```js diff --git a/doc/api/modules.md b/doc/api/modules.md index 04a3dfdb5e0d90..c5eddf2cee80b6 100644 --- a/doc/api/modules.md +++ b/doc/api/modules.md @@ -903,7 +903,7 @@ deprecated: REPLACEME The module that first required this one, or `null` if the current module is the entry point of the current process, or `undefined` if the module was loaded by -something that is not a CJS module (E.G.: REPL or `import`). Read only. +something that is not a CommonJS module (E.G.: REPL or `import`). Read only. ### `module.path`