Question:
How to import JavaScript files in NodeJS using file paths from project root? (instead of relative file paths)
In other words, my team is trying to transition from Syntax Style A to Syntax Style B (shown below):
Syntax Style A
const source = require('../../../../../../source.js');
Syntax Style B
const source = require('src/source.js'); // "src" is a direct subfolder of the project root
I have reviewed a lot of posts on this topic, and none of them can satisfy my project's requirements...
Project Requirements:
- Requirement #1: No external packages (such as Babel.js or Webpack), since disk space is limited. Also, we cannot install anything with "npm install".
- Requirement #2: A JavaScript file should be able to import another JavaScript file using "project root" file paths, not relative file paths. (This will avoid long relative paths such as "../../../../../../../script.js", which can become unmanageable.)
- Requirement #3: Right-clicking the imported class anywhere in the source code should bring up a context menu, with an option to "Go to Declaration" (which takes us to the imported file directly). Also, moving a JavaScript file to a different folder in the IDE should automatically update all references. We can use any IDE.
- Requirement #4: To have a consistent way of importing scripts, we will be using NodeJS's "require" keyword to import (instead of JavaScript's "import" keyword).
Setup:
Below is my setup. Package.json was generated by WebStorm, and I haven't changed it.
Screenshot_of_Project_Structure
Project_Root
├─-─ src
│ └── a1
│ └── a2
│ └── a3
│ └── Worker.js
├──- subFolder1
│ └── SubWorker.js
├─ main.js
└─ package.json
main.js
const Worker = require('./src/a1/a2/a3/Worker.js');
Worker.doWork();
Worker.js
// If I replace the following with Project Root path, such as:
// const SubWorker = require('src/subFolder1/SubWorker.js');
// The script will fail with "Error: Cannot find module './src/subFolder1/SubWorker.js'."
const SubWorker = require('../../../subFolder1/SubWorker.js');
module.exports =
class Worker {
static doWork() {
console.log("doing work");
SubWorker.doMoreWork();
}
}
SubWorker.js
module.exports =
class SubWorker {
static doMoreWork() {
console.log("doing more work");
}
};
Attempt #1: path.resolve
I tried the "path.resolve" solution, as suggested by this post:
NodeJS - convert relative path to absolute
- Program failed with: ⛔Error: Cannot find module './src/subFolder1/SubWorker.js'.
- Error was reproducible in both WebStorm 2022.3.2 and VS Code 1.76.2
Attempt #2: app-module-path
- Importing using relative paths in Node.js with ES Modules
- Using
app-module-path
solves all three requirements, but the program will not run (which is an implied requirement): ⛔Error: Cannot find module 'src/subFolder1/SubWorker.js' - Error was reproducible in both WebStorm 2022.3.2 and VS Code 1.76.2
- Using
Attempt #3: dynamic import()
- Import ES6 Modules with absolute paths in NodeJS without using Babel/Webpack
- The top answer introduced two approaches.
- The first approach moves the relative paths into package.json, so Requirement #2 is still violated.
- The second approach uses dynamic imports. This approach failed the same way as Attempt #1 in WebStorm 2022.3.2 and VS Code 1.76.2. My code is shown below:
Worker.js
const rootPath = 'src/subFolder1';
const SubWorker = require(`${rootPath}/SubWorker.js`);
Attempt #4: subpath imports
- Is there a way to configure node.js to use absolute paths for imports?
- This post is using "import" instead of "require' (violates Requirement #4)
Expected Outcome:
Since NodeJs is one of the most important backend languages, I was expecting excellent IDE support for imports... Referencing a source file from Project Root should be a simple operation that is handled by the IDE (I shouldn't need to use Babel.js or Webpack). Am I doing something wrong here?
I don't know what I am doing wrong, since I have already followed standard practices:
- I used latest versions of the most popular NodeJS IDEs (WebStorm 2022.3.2 and VS Code 1.76.2)
- I used WebStorm's "Create a new NodeJS project" wizard to create the project
- I used the latest NodeJS (v18.15.0). (on Windows 10, v21H2)
Thanks!
Related Posts:
The Stack Overflow posts below are relevant, but do not address the specific issue in this post. (Please kindly search by the title on Stack Overflow, since the spam filter limited the number of links in this post, thanks!)
- Title: NodeJS - Relative File Paths
- Failed the same way as my Attempt #1 above
- Title: Project root based relative paths for NodeJS modules
- Violated Requirement #4 (the desired solution should use "require" instead of "import")
- Title: is it possible to get rid of the relative paths on imports?
- The top answer uses Babel.js, which violates Requirement #1
- Title: How to import a JavaScript file to another JavaScript file
- Does not address the question of relative path vs "project root" path
- Title: How to use absolute/dynamic paths in NodeJs
- Violated Requirement #4 (the desired solution should use "require" instead of "import")
- Title: how to use absolute paths instead of relative paths in React or Next.js?
- We are not using React or Next.js here.
- Title: JavaScript Import file by absolute path
- Violated Requirement #4 (the desired solution should use "require" instead of "import")
- Title: javascript file with absolute file path
- The script here was launched from the client-side web browser. This post deals with nodeJS scripts that are launched from the server-side backend.