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
Related
When I'm executing pure node.js scripts I can change the path where it searches for node_modules as the following:
export NODE_PATH="/home/user/node_modules"
node "/home/user/different/path/file.js"
This way, I can make scripts located inside /home/user/different/path/ see the node_modules folder located in /home/user/ when they are executed.
So far everything is fine, the problem starts with .mjs files. If I try running:
export NODE_PATH="/home/user/node_modules"
node "/home/user/different/path/file.mjs"
I'll receive the error Error [ERR_MODULE_NOT_FOUND] for the modules that I use in my code. The workaround that I know for that is creating a symbolic link inside my script's folder. Something like:
ln -s "/home/user/node_modules" "/home/user/different/path/node_modules"
After doing that, if I run node "/home/user/different/path/file.mjs" it'll work as expected and I'll be able to use libraries installed on /home/user/node_modules with the import statement in my script. However, I'd like to find a solution that doesn't require me to create a symbolic link of the node_modules folder. Is there any alternative solution when I'm working with .mjs files that allows me to change its relative path?
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.
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?
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.
I want to use gulp on my windows machine and it actually works pretty fine, unless I try to use the created files (like pushing to github or deleting). Then it breaks, because the filepaths are too long and it seems to be a fairly common problem. https://github.com/joyent/node/issues/6960#issuecomment-45569604
I understand that the problem arises through npm's nested directories, which extend the maximal char count for Windows directories, but in my understanding there is not any solution yet.
As I see it right now I have three options:
Try to reduce the chars of npm's directories, by changing the default from 'node_modules' to 'n_m' and hope that problem ist postponed. Like suggested here:
https://github.com/joyent/node/issues/6960#issuecomment-45569604
Then it is my question, how exactly do I change the default 'node_modules' directory name?
Change my development environment to Ubuntu, which is frankly a solution I dislike, because I've never used Ubuntu.
Stop using gulp overall.
So, how do I change the default 'node_modules' directory created through npm or what solution do you actually suggest?
There is one more tricky option.
Main problem is that gulp has a lot of nested dependencies and it creates very long nested file pathes.
But if you install some of npm modules that gulp requires in your main node_modules directory gulp will not download them as nested.
Currently you have something similar to (this may be not real path you have but idea is the same):
\node_modules\gulp\node_modules\lodash.bind\node_modules\lodash._createwrapper...
If you will add "lodash.bind" module to your project's package.json as dependency it will be installed in one level with gulp and not as gulp's dependency
\node_modules\gulp
\node_modules\lodash.bind\node_modules\lodash._createwrapper
And this will shorter all urls. You will need to fix only one or two with the longest pathes and it will work.
In my project it was enough to add this dependencies: “lodash.createcallback” and “lodash.bind” to package.json to fix everything.
Take in mind that befor doing this you probably would need to clear current node_modules folder. If you are not able to do that because off too long url you can create symbolic link to temporary short file path and delete it.