WebStorm custom source roots - node.js

I am using WebStorm 2017.3 for Node.JS development, and I have a question about source roots.
I use app-module-path to reduce the number of relative paths between my files in require statements, to get rid of stuff like require('../../../utils/common/stuff'). What I do is, on the first line of my app I call
require('app-module-path').addPath(__dirname);
Which makes it possible to do things like require('src/utils/common/stuff'), if the src folder is located directly under the path added to app-module-path.
However, when using these custom source roots, while the code itself works, WebStorm seems unable to resolve the required files. Let's say I have this structure:
app.js
node_modules
|- some_module
|- xyz.js
src
|- routes
|- foo.js
|- bar.js
|- utils
|- stuff.js
WebStorm can of course successfully resolve the following "normal" require statements from foo.js:
require('./bar')
require('../utils/stuff')
require('some_module/xyz')
The first two are of course relative, the last one is because node_modules is a source root (or whatever term is used).
If I now add the root path to app-module-path, all my files can successfully do:
require('src/utils/stuff')
...which I think looks much nicer than endless relative ../../../../ everywhere. However, while the code itself works fine since src/utils/stuff is found relative to the root folder, the file is not resolved by the IDE, meaning my required object/function becomes grey instead of purple/yellow, I cannot Ctrl+Click on any symbols within it or use any other IDE nice stuff, which is very annoying.
I've tried marking directories as "Resource roots", but that doesn't make any difference; files required with absolute paths still cannot be resolved relative to resource roots. Basically what I'm after is the ability to configure additional folders to behave just like node_modules, and in the Directories setting, node_modules is marked as "Excluded", so it surely must be a completely separate setting controlling which folders are used as "require root folders" or "require search paths".
I've also tried making a symlink from <root>/node_modules/src to <root>/src, and while that makes it possible to Ctrl+Click on the actual file path 'src/utils/stuff' in the require statement, it still doesn't resolve the object that was required, and it also causes WebStorm to issue a warning about the module not being listed in package.json (which, of course, is correct).
Is there any way to configure WebStorm with additional "require root folders"? Or is there a better way than app-module-path to get rid of "relative path hell" in require statements while still preserving WebStorm resolving/indexing capabilities?

Related

PhpStorm doesn't recognize package.json name of local directories

I'm using ReactNative and I have package.json in my local directories so I can have easier imports.
Example:
I have src/components folder and I want to import all components as :
import Button from 'components/Button;
and not use relative path as
import Button from '../../../components/Button;
I created package.json file in my components folder with name 'components' and now I can access Button component as needed.
But, there is problem with PhpStorm. PhpStorm doesn't recognize this as valid path. Is there any workaround for this?
This React native hack for specifying absolute paths (not officially documented anywhere, as far as I can tell) had never been supported. If you miss this feature, please follow WEB-23221 for updates. You can try creating a dummy webpack config like it's suggested in https://youtrack.jetbrains.com/issue/WEB-23221#focus=streamItem-27-2719626.0-0 and specifying a path to it in Settings | Languages & Frameworks | JavaScript | Webpack as a workaround.
Another workaround (if you aren't renaming paths, just making it shorter) is marking a parent folder of components directory as Resource root (note: not the subdirectory itself, but its parent dir!)

Why does require("the-module") from a file in another directory fail?

When I did node myfile.js I got an error that a module was not found. I checked module.paths like this:
$ node
> module.paths
The path where the module is installed showed up and I could require the module:
$ node
> require("the-module")
So I added console.log(module.paths) to myfile.js to see if module.paths was the same. It was not.
What is going on?
EDIT:
It was a bit more complicated.
The module.paths are different, but that does not seem to be the problem. The path where the-module is installed is in the list.
When I add require("the-module") in myfile.js it works as expected. However I do require("c:/path-to/other-file.js") and from there I do another require("the-module"). This require fails.
EDIT 2:
module.paths is other-file.js is different. Why? (And the path where the-module is installed is not in this list.)
You can see all the rules for how require() loads files when you don't specify a full path here.
When you specific only a filename, as in require("the-module"), node.js looks in the node_modules sub-directory below the directory that the current module you are calling require() from was loaded. It is done this way so that a module can have its own set of dependencies and can load them relative to it's own directory without regard from where it is in the file system.
So, if the module you are calling require() from was in c:\myprojects\team\module1 and from within a file in that directory, you call require("the-module"), then node.js will look in c:\myprojects\team\module1\node_modules to find the-module.js.
Similarly, any path that starts with ./ is relative to that same directory, but allows you to reference files in the same directory itself.
node.js does not dynamically add paths to a list of search paths. It sounds like you have an expectation that as you access various directories they are somehow automatically added to a search path. That's now how it works. The rules for where require() looks for relative paths are all spelled out here.
Also, keep in mind that there is not just one module variable across all of node.js. There's a different one in each file that you load in node.js so module.paths very well may be different in each one. In reality, most node.js developers never use module.paths in any way. If you just follow the rules for how relative paths work for require(), you will get what you expect and need.

require name instead of file path

I am looking at some code on github.
https://github.com/madhums/node-express-mongoose/blob/master/config/routes.js
On line 7 it says.
var home = require('home');
home.js is in another folder. I am wondering how this works, and how I can do this in my own code.
on
http://nodejs.org/api/modules.html#modules_folders_as_modules
it explains how to create a self-contained directory, but I can only find the package.json in the root folder. So how does this work?
It seems like a more clean way than having direct file references.
There are ways to refer to folders on the filesystem as packages in node, npm link for example, will pretend a folder is a module using symlinks.
The package you linked to is cheating a bit though, and I'd argue it's not clean at all when put like that. It's actually setting the NODE_PATH to include all controllers when the service is ran: https://github.com/madhums/node-express-mongoose/blob/master/package.json#L13
So all controllers files like home.js are autmatically available. The .js is always optional anyway.

Avoid using relative paths on require()

I'm new with NodeJs, my project is growing and i dont want make relative imports, i want imports like these installed from npm.
I have the following directory structure
Project
node_modules/
src/
model/
person.js
test/
model/
person.js
app.js
config.js
i'm using mongoose and i can require mongoose from any place with require('mongoose') but by example if a want require my person model from app.js i write require('./model/person') and from my test/model/person.js i need write require('../../src/model/person').
Exist some way "native" (without install more dependencies) to make this some like require('model/person') from any place of my app?
This topic is extensively discussed here. My conclusion is mostly:
The idea of putting tests in a separate directory is ineffective. Put tests right alongside the main code: app/users/user.js and app/users/user.test.js.
I create a symlink at node_modules/app that points to ../app so I can require('app/users'); from anywhere in the code base.
There is nothing which says you cannot put your own code inside node_modules. This will enable you to reference it as you want. If you have a .gitignore or equivalent preventing code inside node_modules from being committed, you can add exceptions for your own code.
node_modules
!node_modules/model/

Node.js: How do relative paths in require statements work?

I am using jasmine-node to run jasmine tests. My project has a typical structure with "spec" and "src" folders.
Inside my "HelloSpec.js" file I had:
require('../src/Hello.js');
However when I ran the tests from the project's root folder (ie, the parent folder of both "spec" and "src") with this command:
jasmine-node spec/HelloSpec.js
I got errors indicating that the required files had not actually been required. But If I changed the require statement to:
require('src/Hello.js');
everything worked fine. So it seems that the require statements were resolving the paths relative to the folder where I was executing the tests, rather than relative to their own file location. But it doesn't make sense to me that it would work like that.
How are relative paths in "require" supposed to work?
Do I need to do something to make them work the way I expected them to?
Thanks!
Usually a path from a current directory starts with a ./ which means current directory. What you have with your src/Hello.js is a path search which seems to include the project folder.
I was of the understanding that the require ./ and ../ is relative to the file that it is being required from or at least this has always worked for me. if it doesn't start with either of these then it will usually try a path search.
jasmine-node is not node which is what my experience is based on.
jasmine-node may have a diffrent path definition which is why the path search seems to work.
If its not broke don't fix it? :)
EDIT WITH CORRECT ANSWER
Problem turned out to be me being careless. I'd forgotten to do module.exports. I fixed that and now everything works the way I expected. Not sure why it was working the other way without any export or module.exports, but it was.... Anyway, if you want to edit your answer to include this comment, I'll accept it

Resources