module: add --preserve-symlinks-main
Add `--preserve-symlinks-main` option which behaves like `--preserve-symlinks` but for `require.main`. PR-URL: https://github.com/nodejs/node/pull/19911 Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
parent
20509ebee6
commit
236596590c
@ -217,6 +217,29 @@ are linked from more than one location in the dependency tree (Node.js would
|
|||||||
see those as two separate modules and would attempt to load the module multiple
|
see those as two separate modules and would attempt to load the module multiple
|
||||||
times, causing an exception to be thrown).
|
times, causing an exception to be thrown).
|
||||||
|
|
||||||
|
The `--preserve-symlinks` flag does not apply to the main module, which allows
|
||||||
|
`node --preserve-symlinks node_module/.bin/<foo>` to work. To apply the same
|
||||||
|
behavior for the main module, also use `--preserve-symlinks-main`.
|
||||||
|
|
||||||
|
### `--preserve-symlinks-main`
|
||||||
|
<!-- YAML
|
||||||
|
added: REPLACEME
|
||||||
|
-->
|
||||||
|
|
||||||
|
Instructs the module loader to preserve symbolic links when resolving and
|
||||||
|
caching the main module (`require.main`).
|
||||||
|
|
||||||
|
This flag exists so that the main module can be opted-in to the same behavior
|
||||||
|
that `--preserve-symlinks` gives to all other imports; they are separate flags,
|
||||||
|
however, for backward compatibility with older Node.js versions.
|
||||||
|
|
||||||
|
Note that `--preserve-symlinks-main` does not imply `--preserve-symlinks`; it
|
||||||
|
is expected that `--preserve-symlinks-main` will be used in addition to
|
||||||
|
`--preserve-symlinks` when it is not desirable to follow symlinks before
|
||||||
|
resolving relative paths.
|
||||||
|
|
||||||
|
See `--preserve-symlinks` for more information.
|
||||||
|
|
||||||
### `--prof-process`
|
### `--prof-process`
|
||||||
<!-- YAML
|
<!-- YAML
|
||||||
added: v5.2.0
|
added: v5.2.0
|
||||||
|
@ -143,7 +143,10 @@ Among other uses, this can be used to enable FIPS-compliant crypto if Node.js is
|
|||||||
Emit pending deprecation warnings.
|
Emit pending deprecation warnings.
|
||||||
.
|
.
|
||||||
.It Fl -preserve-symlinks
|
.It Fl -preserve-symlinks
|
||||||
Instructs the module loader to preserve symbolic links when resolving and caching modules.
|
Instructs the module loader to preserve symbolic links when resolving and caching modules other than the main module.
|
||||||
|
.
|
||||||
|
.It F1 -preserve-symlinks-main
|
||||||
|
Instructs the module loader to preserve symbolic links when resolving and caching the main module.
|
||||||
.
|
.
|
||||||
.It Fl -prof-process
|
.It Fl -prof-process
|
||||||
Process V8 profiler output generated using the V8 option
|
Process V8 profiler output generated using the V8 option
|
||||||
|
@ -42,6 +42,7 @@ const {
|
|||||||
stripShebang
|
stripShebang
|
||||||
} = require('internal/modules/cjs/helpers');
|
} = require('internal/modules/cjs/helpers');
|
||||||
const preserveSymlinks = !!process.binding('config').preserveSymlinks;
|
const preserveSymlinks = !!process.binding('config').preserveSymlinks;
|
||||||
|
const preserveSymlinksMain = !!process.binding('config').preserveSymlinksMain;
|
||||||
const experimentalModules = !!process.binding('config').experimentalModules;
|
const experimentalModules = !!process.binding('config').experimentalModules;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -239,7 +240,21 @@ Module._findPath = function(request, paths, isMain) {
|
|||||||
var rc = stat(basePath);
|
var rc = stat(basePath);
|
||||||
if (!trailingSlash) {
|
if (!trailingSlash) {
|
||||||
if (rc === 0) { // File.
|
if (rc === 0) { // File.
|
||||||
if (preserveSymlinks && !isMain) {
|
if (!isMain) {
|
||||||
|
if (preserveSymlinks) {
|
||||||
|
filename = path.resolve(basePath);
|
||||||
|
} else {
|
||||||
|
filename = toRealPath(basePath);
|
||||||
|
}
|
||||||
|
} else if (preserveSymlinksMain) {
|
||||||
|
// For the main module, we use the preserveSymlinksMain flag instead
|
||||||
|
// mainly for backward compatibility, as the preserveSymlinks flag
|
||||||
|
// historically has not applied to the main module. Most likely this
|
||||||
|
// was intended to keep .bin/ binaries working, as following those
|
||||||
|
// symlinks is usually required for the imports in the corresponding
|
||||||
|
// files to resolve; that said, in some use cases following symlinks
|
||||||
|
// causes bigger problems which is why the preserveSymlinksMain option
|
||||||
|
// is needed.
|
||||||
filename = path.resolve(basePath);
|
filename = path.resolve(basePath);
|
||||||
} else {
|
} else {
|
||||||
filename = toRealPath(basePath);
|
filename = toRealPath(basePath);
|
||||||
|
@ -7,6 +7,7 @@ const { NativeModule, internalBinding } = require('internal/bootstrap/loaders');
|
|||||||
const { extname } = require('path');
|
const { extname } = require('path');
|
||||||
const { realpathSync } = require('fs');
|
const { realpathSync } = require('fs');
|
||||||
const preserveSymlinks = !!process.binding('config').preserveSymlinks;
|
const preserveSymlinks = !!process.binding('config').preserveSymlinks;
|
||||||
|
const preserveSymlinksMain = !!process.binding('config').preserveSymlinksMain;
|
||||||
const {
|
const {
|
||||||
ERR_MISSING_MODULE,
|
ERR_MISSING_MODULE,
|
||||||
ERR_MODULE_RESOLUTION_LEGACY,
|
ERR_MODULE_RESOLUTION_LEGACY,
|
||||||
@ -71,7 +72,7 @@ function resolve(specifier, parentURL) {
|
|||||||
|
|
||||||
const isMain = parentURL === undefined;
|
const isMain = parentURL === undefined;
|
||||||
|
|
||||||
if (!preserveSymlinks || isMain) {
|
if (isMain ? !preserveSymlinksMain : !preserveSymlinks) {
|
||||||
const real = realpathSync(getPathFromURL(url), {
|
const real = realpathSync(getPathFromURL(url), {
|
||||||
[internalFS.realpathCacheKey]: realpathCache
|
[internalFS.realpathCacheKey]: realpathCache
|
||||||
});
|
});
|
||||||
|
16
src/node.cc
16
src/node.cc
@ -237,6 +237,11 @@ bool trace_warnings = false;
|
|||||||
// that is used by lib/module.js
|
// that is used by lib/module.js
|
||||||
bool config_preserve_symlinks = false;
|
bool config_preserve_symlinks = false;
|
||||||
|
|
||||||
|
// Set in node.cc by ParseArgs when --preserve-symlinks-main is used.
|
||||||
|
// Used in node_config.cc to set a constant on process.binding('config')
|
||||||
|
// that is used by lib/module.js
|
||||||
|
bool config_preserve_symlinks_main = false;
|
||||||
|
|
||||||
// Set in node.cc by ParseArgs when --experimental-modules is used.
|
// Set in node.cc by ParseArgs when --experimental-modules is used.
|
||||||
// Used in node_config.cc to set a constant on process.binding('config')
|
// Used in node_config.cc to set a constant on process.binding('config')
|
||||||
// that is used by lib/module.js
|
// that is used by lib/module.js
|
||||||
@ -3529,6 +3534,8 @@ static void PrintHelp() {
|
|||||||
" --pending-deprecation emit pending deprecation warnings\n"
|
" --pending-deprecation emit pending deprecation warnings\n"
|
||||||
#if defined(NODE_HAVE_I18N_SUPPORT)
|
#if defined(NODE_HAVE_I18N_SUPPORT)
|
||||||
" --preserve-symlinks preserve symbolic links when resolving\n"
|
" --preserve-symlinks preserve symbolic links when resolving\n"
|
||||||
|
" --preserve-symlinks-main preserve symbolic links when resolving\n"
|
||||||
|
" the main module\n"
|
||||||
#endif
|
#endif
|
||||||
" --prof-process process v8 profiler output generated\n"
|
" --prof-process process v8 profiler output generated\n"
|
||||||
" using --prof\n"
|
" using --prof\n"
|
||||||
@ -3579,7 +3586,6 @@ static void PrintHelp() {
|
|||||||
" -r, --require module to preload (option can be "
|
" -r, --require module to preload (option can be "
|
||||||
"repeated)\n"
|
"repeated)\n"
|
||||||
" -v, --version print Node.js version\n"
|
" -v, --version print Node.js version\n"
|
||||||
|
|
||||||
"\n"
|
"\n"
|
||||||
"Environment variables:\n"
|
"Environment variables:\n"
|
||||||
"NODE_DEBUG ','-separated list of core modules\n"
|
"NODE_DEBUG ','-separated list of core modules\n"
|
||||||
@ -3842,6 +3848,8 @@ static void ParseArgs(int* argc,
|
|||||||
Revert(cve);
|
Revert(cve);
|
||||||
} else if (strcmp(arg, "--preserve-symlinks") == 0) {
|
} else if (strcmp(arg, "--preserve-symlinks") == 0) {
|
||||||
config_preserve_symlinks = true;
|
config_preserve_symlinks = true;
|
||||||
|
} else if (strcmp(arg, "--preserve-symlinks-main") == 0) {
|
||||||
|
config_preserve_symlinks_main = true;
|
||||||
} else if (strcmp(arg, "--experimental-modules") == 0) {
|
} else if (strcmp(arg, "--experimental-modules") == 0) {
|
||||||
config_experimental_modules = true;
|
config_experimental_modules = true;
|
||||||
new_v8_argv[new_v8_argc] = "--harmony-dynamic-import";
|
new_v8_argv[new_v8_argc] = "--harmony-dynamic-import";
|
||||||
@ -4286,6 +4294,12 @@ void Init(int* argc,
|
|||||||
SafeGetenv("NODE_PRESERVE_SYMLINKS", &text) && text[0] == '1';
|
SafeGetenv("NODE_PRESERVE_SYMLINKS", &text) && text[0] == '1';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::string text;
|
||||||
|
config_preserve_symlinks_main =
|
||||||
|
SafeGetenv("NODE_PRESERVE_SYMLINKS_MAIN", &text) && text[0] == '1';
|
||||||
|
}
|
||||||
|
|
||||||
if (config_warning_file.empty())
|
if (config_warning_file.empty())
|
||||||
SafeGetenv("NODE_REDIRECT_WARNINGS", &config_warning_file);
|
SafeGetenv("NODE_REDIRECT_WARNINGS", &config_warning_file);
|
||||||
|
|
||||||
|
@ -72,6 +72,8 @@ static void Initialize(Local<Object> target,
|
|||||||
|
|
||||||
if (config_preserve_symlinks)
|
if (config_preserve_symlinks)
|
||||||
READONLY_BOOLEAN_PROPERTY("preserveSymlinks");
|
READONLY_BOOLEAN_PROPERTY("preserveSymlinks");
|
||||||
|
if (config_preserve_symlinks_main)
|
||||||
|
READONLY_BOOLEAN_PROPERTY("preserveSymlinksMain");
|
||||||
|
|
||||||
if (config_experimental_modules) {
|
if (config_experimental_modules) {
|
||||||
READONLY_BOOLEAN_PROPERTY("experimentalModules");
|
READONLY_BOOLEAN_PROPERTY("experimentalModules");
|
||||||
|
@ -173,6 +173,11 @@ extern std::string openssl_config;
|
|||||||
// that is used by lib/module.js
|
// that is used by lib/module.js
|
||||||
extern bool config_preserve_symlinks;
|
extern bool config_preserve_symlinks;
|
||||||
|
|
||||||
|
// Set in node.cc by ParseArgs when --preserve-symlinks-main is used.
|
||||||
|
// Used in node_config.cc to set a constant on process.binding('config')
|
||||||
|
// that is used by lib/module.js
|
||||||
|
extern bool config_preserve_symlinks_main;
|
||||||
|
|
||||||
// Set in node.cc by ParseArgs when --experimental-modules is used.
|
// Set in node.cc by ParseArgs when --experimental-modules is used.
|
||||||
// Used in node_config.cc to set a constant on process.binding('config')
|
// Used in node_config.cc to set a constant on process.binding('config')
|
||||||
// that is used by lib/module.js
|
// that is used by lib/module.js
|
||||||
|
57
test/es-module/test-esm-preserve-symlinks-main.js
Normal file
57
test/es-module/test-esm-preserve-symlinks-main.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const common = require('../common');
|
||||||
|
const { spawn } = require('child_process');
|
||||||
|
const assert = require('assert');
|
||||||
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
const tmpdir = require('../common/tmpdir');
|
||||||
|
tmpdir.refresh();
|
||||||
|
const tmpDir = tmpdir.path;
|
||||||
|
|
||||||
|
fs.mkdirSync(path.join(tmpDir, 'nested'));
|
||||||
|
fs.mkdirSync(path.join(tmpDir, 'nested2'));
|
||||||
|
|
||||||
|
const entry = path.join(tmpDir, 'nested', 'entry.js');
|
||||||
|
const entry_link_absolute_path = path.join(tmpDir, 'link.js');
|
||||||
|
const submodule = path.join(tmpDir, 'nested2', 'submodule.js');
|
||||||
|
const submodule_link_absolute_path = path.join(tmpDir, 'submodule_link.js');
|
||||||
|
|
||||||
|
fs.writeFileSync(entry, `
|
||||||
|
const assert = require('assert');
|
||||||
|
|
||||||
|
// this import only resolves with --preserve-symlinks-main set
|
||||||
|
require('./submodule_link.js');
|
||||||
|
`);
|
||||||
|
fs.writeFileSync(submodule, '');
|
||||||
|
|
||||||
|
try {
|
||||||
|
fs.symlinkSync(entry, entry_link_absolute_path);
|
||||||
|
fs.symlinkSync(submodule, submodule_link_absolute_path);
|
||||||
|
} catch (err) {
|
||||||
|
if (err.code !== 'EPERM') throw err;
|
||||||
|
common.skip('insufficient privileges for symlinks');
|
||||||
|
}
|
||||||
|
|
||||||
|
function doTest(flags, done) {
|
||||||
|
// invoke the main file via a symlink. In this case --preserve-symlinks-main
|
||||||
|
// dictates that it'll resolve relative imports in the main file relative to
|
||||||
|
// the symlink, and not relative to the symlink target; the file structure set
|
||||||
|
// up above requires this to not crash when loading ./submodule_link.js
|
||||||
|
spawn(process.execPath,
|
||||||
|
flags.concat([
|
||||||
|
'--preserve-symlinks',
|
||||||
|
'--preserve-symlinks-main', entry_link_absolute_path
|
||||||
|
]),
|
||||||
|
{ stdio: 'inherit' }).on('exit', (code) => {
|
||||||
|
assert.strictEqual(code, 0);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// first test the commonjs module loader
|
||||||
|
doTest([], () => {
|
||||||
|
// now test the new loader
|
||||||
|
doTest(['--experimental-modules'], () => {});
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user