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
|
||||
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`
|
||||
<!-- YAML
|
||||
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.
|
||||
.
|
||||
.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
|
||||
Process V8 profiler output generated using the V8 option
|
||||
|
@ -42,6 +42,7 @@ const {
|
||||
stripShebang
|
||||
} = require('internal/modules/cjs/helpers');
|
||||
const preserveSymlinks = !!process.binding('config').preserveSymlinks;
|
||||
const preserveSymlinksMain = !!process.binding('config').preserveSymlinksMain;
|
||||
const experimentalModules = !!process.binding('config').experimentalModules;
|
||||
|
||||
const {
|
||||
@ -239,7 +240,21 @@ Module._findPath = function(request, paths, isMain) {
|
||||
var rc = stat(basePath);
|
||||
if (!trailingSlash) {
|
||||
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);
|
||||
} else {
|
||||
filename = toRealPath(basePath);
|
||||
|
@ -7,6 +7,7 @@ const { NativeModule, internalBinding } = require('internal/bootstrap/loaders');
|
||||
const { extname } = require('path');
|
||||
const { realpathSync } = require('fs');
|
||||
const preserveSymlinks = !!process.binding('config').preserveSymlinks;
|
||||
const preserveSymlinksMain = !!process.binding('config').preserveSymlinksMain;
|
||||
const {
|
||||
ERR_MISSING_MODULE,
|
||||
ERR_MODULE_RESOLUTION_LEGACY,
|
||||
@ -71,7 +72,7 @@ function resolve(specifier, parentURL) {
|
||||
|
||||
const isMain = parentURL === undefined;
|
||||
|
||||
if (!preserveSymlinks || isMain) {
|
||||
if (isMain ? !preserveSymlinksMain : !preserveSymlinks) {
|
||||
const real = realpathSync(getPathFromURL(url), {
|
||||
[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
|
||||
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.
|
||||
// Used in node_config.cc to set a constant on process.binding('config')
|
||||
// that is used by lib/module.js
|
||||
@ -3529,6 +3534,8 @@ static void PrintHelp() {
|
||||
" --pending-deprecation emit pending deprecation warnings\n"
|
||||
#if defined(NODE_HAVE_I18N_SUPPORT)
|
||||
" --preserve-symlinks preserve symbolic links when resolving\n"
|
||||
" --preserve-symlinks-main preserve symbolic links when resolving\n"
|
||||
" the main module\n"
|
||||
#endif
|
||||
" --prof-process process v8 profiler output generated\n"
|
||||
" using --prof\n"
|
||||
@ -3579,7 +3586,6 @@ static void PrintHelp() {
|
||||
" -r, --require module to preload (option can be "
|
||||
"repeated)\n"
|
||||
" -v, --version print Node.js version\n"
|
||||
|
||||
"\n"
|
||||
"Environment variables:\n"
|
||||
"NODE_DEBUG ','-separated list of core modules\n"
|
||||
@ -3842,6 +3848,8 @@ static void ParseArgs(int* argc,
|
||||
Revert(cve);
|
||||
} else if (strcmp(arg, "--preserve-symlinks") == 0) {
|
||||
config_preserve_symlinks = true;
|
||||
} else if (strcmp(arg, "--preserve-symlinks-main") == 0) {
|
||||
config_preserve_symlinks_main = true;
|
||||
} else if (strcmp(arg, "--experimental-modules") == 0) {
|
||||
config_experimental_modules = true;
|
||||
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';
|
||||
}
|
||||
|
||||
{
|
||||
std::string text;
|
||||
config_preserve_symlinks_main =
|
||||
SafeGetenv("NODE_PRESERVE_SYMLINKS_MAIN", &text) && text[0] == '1';
|
||||
}
|
||||
|
||||
if (config_warning_file.empty())
|
||||
SafeGetenv("NODE_REDIRECT_WARNINGS", &config_warning_file);
|
||||
|
||||
|
@ -72,6 +72,8 @@ static void Initialize(Local<Object> target,
|
||||
|
||||
if (config_preserve_symlinks)
|
||||
READONLY_BOOLEAN_PROPERTY("preserveSymlinks");
|
||||
if (config_preserve_symlinks_main)
|
||||
READONLY_BOOLEAN_PROPERTY("preserveSymlinksMain");
|
||||
|
||||
if (config_experimental_modules) {
|
||||
READONLY_BOOLEAN_PROPERTY("experimentalModules");
|
||||
|
@ -173,6 +173,11 @@ extern std::string openssl_config;
|
||||
// that is used by lib/module.js
|
||||
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.
|
||||
// Used in node_config.cc to set a constant on process.binding('config')
|
||||
// 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