Avoid using relative paths on require() - node.js

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/

Related

How to use absolute import paths when writing tests for a specific module

I am working on a NodeJS (v. 8.12.0, EcmaScript 6) project, whose project structure is similar to:
project_root/
src/
utils/
protocol_messages/
helpers.js
tests/
unit/
utils/
protocol_messages/
helpers.js
I am writing tests using Mocha as a test framework.
Question
In the helpers.js under tests/unit/utils/protocol_messages/, what's the proper way of importing the module-under-test?
To elaborate:
I want to avoid the relative path in: require('../../../../../src/utils/protocol_messages/helpers').
It works, but it's ugly, and if the project structure changes, I would have to rewrite the test imports, as well.
(I am new to Javascript so I might be doing several things wrong.)
Update
Solutions provided in this question:
require.main.require: in a comment to this answer, "This solution will not work if code covered with unit tests like Mocha test".
Extracting my utils to a node module doesn't make sense for me, since the code is very application specific.
Having an extra node_modules under my src/ project root of a NodeJS project doesn't seem to make sense.
Using a Javascript transpiler when I am using only features available in NodeJS and writing CommonJS projects seems a bit of an overkill.
If I am mistaken on any of the above points, please point it out, as I am at a loss. It seems to me like NodeJS doesn't not provide a native way to import CommonJS modules with absolute paths.
You can use wavy npm package.
This module lets you turn things like require('../../../../foo') into something like
require('~/foo'). The way it works is that on postinstall it creates a symlink in app/node_modules/~ to point to app/
Assume you need a config.js file present at your project's root in a file which is present at /routes/api/users/profile.js, you do not want to import it as ../../../config.js
Create a directory structure in your project's root directory as described below:
/Modules
index.js
package.json
Modules/index.js
module.exports.config = require('../config.js')
Modules/package.js
{
"name": "modules",
"main": "index.js",
"version": "1.0.0",
"dependencies": {}
}
Now run
npm install ./Modules
/routes/api/users/profile.js
const { config } = require('modules')
This way autocomplete feature of your code editor will also work. No more global variables pollution, long relative imports, no dependency on environment variables and the best part is, it will work with pm2 and nodemon.

How does require work?

I have 2 files in a folder called js. I am using webpack.
js/app.js and js/login.es6.
I'm trying to include the login from my app.js:
require('login.es6') fails
require('./login.es6') works.
Any idea why?
When you write require('login.es6') node will look for a module named login.es6 in your node_modules.
When you write require('./login.es6') node understands that ./login.es6 is a relative path and will load your js/login.es6.js file.
This is needed to distinguish between modules and local files. There may be a npm module called login.es6; this way you can reference both the module and your local file in your project.
The node.js docs on require are pretty nice and gives a good overview of how modules are prioritized when loaded.
The gist is, if you don't start the string with ./, require will first look for a core module, then recursively look in the node_modules directory/-ies. So it's normal to start require calls to local files with ./.

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.

Can I put the npm node_modules directory outside of my 'webroot'

I'm new to Node but am enjoying myself so far. I was trying to move my node_modules (libraries) directory outside of the public 'webroot' and need advice and guidance.
I've setup my simple expressJS based Node project as follows:
/my_project
/config
/public
/node_modules
server.js
I was wondering if there was any way I could have the /node_modules dir outside of my webroot and not break my application. I'm just so used to keeping the bare minimum in my publicly exposed webroot and don't feel right with the libs being in there. Call me old fashioned but that's how I'm used to doing stuff in the PHP and C# world.
If I setup the project as follows:
/my_project
/config
/node_modules
/public
server.js
then it all goes wobbly and Node's require() magic breaks.
I've tried the following:
var express=require('../express'); which doesn't work either giving me the 'Cannot Find module' type error.
Is what I'm asking even possible, if so then how?
Are there any major risks with me having my libs in a webroot or have I missed something fundamental here with the way Node works.
What do you guys do, what is best practice for production apps? May I have some examples of your production practices and why.
1. Is it possible to have modules in a folder outside of the project
Yes.
2. Are there any major risks with having modules in a webroot?
Assuming that you by "webroot" mean in the root of the server or any folder outside of your project: yes. It is possible to install modules globally with npm using the g-flag: npm install -g express. This generally considered bad practice as different projects may depend on different versions of the same module. Installing locally allows different projects to have different versions.
If you're using version control and don't want to check in the external modules, a common (and standard in npm) pattern is to ignore ./node_modules and specify dependencies in a package.json file.
3. "What is best practice for production apps?"
Not a good fit for SO, but since I'm at it I'll give it a shot anyway. If you use grunt (a very popular task automation tool) you'll usually end up with a structure like this:
/my_project
/node_modules
/lib
# actual project files
/public
# files that are meant to be sent to clients
/test
package.json # specifies dependencies, main script, version etc
README.md # optional
This structure has the advantages of clearly separating core files, dependencies and any tests while keeping it all in the same folder.

Node.js: Where To Place Internal Modules In Folder Structure?

The Situation
I often see Node.js applications with the following structure:
Common pattern:
lib/ or src/ - the self-written code
index.js - main code
internal modules... (e.g. self-written for this project)
node_modules
external modules... (e.g. taken from another project)
package.json
My Problem
What I don't like about this pattern:
I don't feel comfortable about it because you have to explicitly specify the directory path of the internal modules when require()ing:
// /lib/index.js
var internalMod = require('./internal'); // `require('internal')` (without path) wouldn't work
internalMod.doSomething();
My Idea
So I think it would be a good idea also to place internal modules in an node_modules folder (somewhere in the project). So node would be able to find them, even if you don't explicitly specify the path.
For example:
src/ - the self-written code
index.js - main code
node-modules - for internals
internal modules...
node_modules - for externals
external modules... (e.g. taken from another project)
package.json
My Question
Are there any cons about my plan?
Is there another idea where to place internal modules in folder structure?
Thanks for your answer (or comment). - If anything is unclear, please comment.
Perhaps you could use npm link to pull your modules into node_modules?
See: https://docs.npmjs.com/cli/link

Resources