简体   繁体   中英

Node.js require a file relative to the root of the package

In Node.js, is there any way to require file from the same package without using relative paths? For example, here's a snippet of code from ESLint .

const rule = require("../../../lib/rules/accessor-pairs"),
    { RuleTester } = require("../../../lib/rule-tester");

The fact that we have to walk all the way up the tree ../../../ to get to the root is not only annoying. It's also brittle, because I can't move the code without updating all of dependency references.

Yet somehow Node.js developers seem to have lived with it the past 10 years. I can't find anything in the docs or Stack Overflow that solves this problem other than a third-party dependency called require-self . Nor have I been able to find a definitive statement that using relative paths is the only non-hacky way for a file to require another file in the same module .

If there's a way to specify a path relative to the package root in ECMAScript Modules (ESM) but not CommonJS (CJS), or vice versa, I would like to know that as well.

To be clear, I don't think there is a solution to the problem. If there is great. Otherwise, I'm looking for confirmation with an authoritative reference.

Not necessarily the same package - if you are writing libraries this won't be useful, but if you are writing the "final application" - the thing that actually gets run:

One option:

If the NODE_PATH environment variable is set to a colon-delimited list of absolute paths, then Node.js will search those paths for modules if they are not found elsewhere.

So you can do any of:

1.

export NODE_PATH=.
node app.js
NODE_PATH=. node app.js
// app.js (or whatever your entry point is) before *any* require() calls
process.env.NODE_PATH = __dirname;
require('module').Module._initPaths();

Or, another way:

The Module object representing the entry script loaded when the Node.js process launched.

https://nodejs.org/api/modules.html#modules_require_main

So you can just do:

const rule = require.main.require("./lib/rules/accessor-pairs")

anytime you want it to be relative to the root (assuming that is how you have your project structured).

You can use the package name itself as a "symlink" to the package root.


Example - foo package imports bar script relative to the foo package root.

package.json

{
    "dependencies": {
        "foo": "file:./foo"
    }
}

index.js

const foo = require('foo');
console.log(foo.bar);  // prints "hello"

foo/index.js

const bar = require('foo/bar');  // import relative to the package root

module.exports = {
    bar: bar
}

foo/bar.js

module.exports = 'hello';

If you use vscode then you're in luck -.,,, jsconfig,json in project root handles this masterfully for commonjs, es6, amd, umd, etc

The jsconfig.json file specifies the root files and the options for the features provided by the JavaScript language service.


jsconfig.json

{
  "compilerOptions": {
    "module": "commonjs",
    "baseUrl": ".",
    "paths": {
      "@rules/*": ["path/to/lib/rules/"]
    }
  }
}

and then to use the alias:

const rule = require('@rules/accessor-pairs'),
    { RuleTester } = require('@rules/rule-tester');

Read more: https://code.visualstudio.com/docs/languages/jsconfig

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM