Using NPM & gruntjs build system - node.js

I am new to Node.js echo system and trying to set up a build system for JavaScript application development. I have some questions that I can't find answers to.
From this blog post, it is clear that you should install all the project specific node modules locally.
Now, I am installing the entire grunt module locally in my project directory. I get the following directory structure...
my_project/
lib/
utils/
underscore.js
... other project files ...
node_modules/
.bin/
grunt -> ../grunt/bin/grunt*
grunt/
node_modules/
bin/
dev/
docs/
lib/
test/
tasks/
grunt.js
package.json
... others ...
Note that there are TWO node_modules directories. One in my project and other inside the grunt module.
Q: Why are there multiple node_modules directories at different levels? Can someone explain me how the directory structure works?
Q: If I install another module, will it also have its own node_modules directory?
Q: If I go within my_project/lib/utils and then run the command npm install <some_module>, will that module be installed only for that directory or for the entire project? If the latter, then how does NPM/Node figure out the project root?
Please explain anything else I might be missing here.

Every project in the npm registry can be thought of a self-contained module (specifically, a CommonJS module) that has source code and project metadata defined in a package.json file in the root directory of that project.
When you type npm install (or just npm i) in a directory with a package.json file, npm reads the collection of dependencies defined in package.json in your project's root directory and installs those packages in the node_modules directory.
So what's with the nested node_modules directories? npm install is recursive. If project A requires B and B requires C, you'd see this directory structure:
A/
A/node_modules
A/node_modules/B
A/node_modules/B/node_modules
A/node_modules/B/node_modules/C
In your case, when you add grunt to dependencies in the my_project/package.json file, that dependency will get added to its own directory: my_project/node_modules/grunt. But grunt has a lot of dependencies, and those dependencies have dependencies. So you'll see many nested node_modules directories.
For your third question, see the algorithm section on this page: https://npmjs.org/doc/install.html -- it describes how npm install searches for dependencies.
There's also some more information about global vs local dependencies in npm here.

Related

Should node_modules be in User folder or project folders?

I am a total Javascript newbie aiming to configure my Mac nicely for development.
NPM is installed.
I notice that folder node_modules exists in my Users/MyName directory.
I think this is a result of having either installed Node/NPM or specifically run npm install airtable the other day, which I did at the time in Users/MyName.
When I npm uninstall airtable, it removes airtable and its dependency folders from nodule_modules, leaving the following: #types and package-lock.json (hidden).
If I cd to new project-specific directory Users/MyName/Projects/Code/myusername/airtable-test and run npm install airtable from there, I expected the packages may get installed in that folder. However, again, they get installed up at Users/MyName/node_modules.
In both cases, .package-lock.json (non-hidden) and package.json are in Users/MyName, which seems messy to me. (I haven't done anything non-standard in install).
Is this the way things should be?
Attempts to solve:
I seem to read, including from questions on Stackoverflow, that storing modules at Users/MyName/node_modules is effectively storing them globally, accessible to any app, and such that projects don't have to get committed to server with all dependencies in tow - the idea being that, after you deploy your app, you then run npm install whilst in its folder, prompting it to install all dependencies.
Is this right? Should I be looking at storing all dependency modules in a project folder, or above and outside of it?
(If the answer to this question is opinion-based, I wasn't aware of that).
Here is what I believe is happening. You have your package.json in folder Users/MyName and you are running npm install in Users/MyName/Projects/Code/myusername/airtable-test. But the problem is you do not have package.json file in the folder Users/MyName/Projects/Code/myusername/airtable-test. So npm goes up in the directory to find the package.json and it found it in Users/MyName so it is installing the package there.
This is happening because the way npm identifies a project is by looking for package.json. If it does not find it in current directory than it assumes that you must be inside some sub directory of the project and start searching upwards in the folder hierarchy to find the package.json.
solution
Do npm init in the folder Users/MyName/Projects/Code/myusername/airtable-test. This will initialize the folder as a npm package (by creating package.json).

Please help clarifying the structure - nodejs/npm

Currently I've installed Node.js and npm on my Windows 10 and first package called hotkeys-js. I have no idea why I have least two node_modules directories within distinct paths, i.e.:
one in
C:\Program Files\nodejs\node_modules\npm
which I do consider as parent working directory, correct if I am wrong?
second which is most questionable for me:
C:\Users\<*whateverUsernameWouldBe*>\node_modules\first_npm
also the structure within first_npm as:
|- node_modules
|- index.js
|- package.json
|- package-lock
Why do I have this separate directory at all? Is it local/global? What is the purpose of this one?
The node_modules folder under Program Files contains the npm modules installed as part of the nodejs installation package, and the npm modules you install with npm install -g whatever for common, global, use on your machine.
The node_modules folder in your project folder contains the npm modules you installed as part of your project.
Don't mess with the one under Program Files except via npm install -g and npm uninstall -g commands. At least until you get a little more proficient with this stuff.
Your life might be slightly easier if you create your own nodejs / npm projects in a folder called C:\Users\<*whateverUsernameWouldBe*>\myNodeProjects or something like that, rather than a folder called C:\Users\<*whateverUsernameWouldBe*>\node_modules. Folders named node_modules are generally maintained by npm. When you create one that isn't, you can confuse yourself. Ask me how I know this sometime.

Can I put the npm node_modules directory outside of my project

Can I put the node_modules directory outside my project just the way maven does with its dependencies?
Sort of. The node_modules directory is not actually a feature of npm but a feature of node.js.
How node.js uses node_modules.
When you require a module node.js will search for a node_modules directory from the current directory upwards. That means if it can't find one in the current directory (which may actually be a subdirectory of your project instead of your project directory) it will look for it in the parent directory then the parent's parent all the way to your root directory.
For example, you can have a project structure like this:
/node_modules <-------------------- modules available to all projects
/code
/project_A
/node_modules <------ modules available to project A
/lib
/node_modules <-- modules available to the lib directory
/project_B
/node_modules <------ modules available to project B
This way you can have some modules shared by multiple projects and some modules that are project specific and even some modules that are only available to some files in your project.
How npm handles node_modules
Note however that npm has only one interpretation of node_modules. It only manages node_modules in your project directory. Specifically the directory that contains the package.json file.
So yes, you can do it but npm won't understand what you are doing and your package.json will contain incomplete dependencies. I wouldn't recommend doing this with projects involving multiple developers because it will look more like a misconfigured development environment - basically others will think this is a bug. However I personally have used such structures for personal projects where I don't care about my package.json file.
As mention in this question Don't do it. Let NPM work the way it's designed to. However, to save space, you can delete the node_modules folder on projects that are currently dormant, and recreate it with a single shot of npm install when you switch back to them.
It is an issue if the plugin declares to install the modules in a configurable directory. Therefore I suggest to fix the documentation, it gives false hopes.
Please see npm docs, as this is the default behaviour of npm. Not a frontend-maven-plugin issue.
Yes you can, but you should try to avoid doing so.
npm install will always install the modules within node_modules folder in your parent working directory.
Whenever you install a module using npm install -g module_name, it installs modules globally outside your project directory which can be also used in other projects, normally some dev dependencies are installed globally which helps you in development purpose.
An example would be
npm install -g #angular/cli , doing this once will enable you to use ng commands to build ,test other angular projects as well.
Other than this,it would be ideal if all the node_modules which are required for your project would stay in the working directory of your project.
Installing anything globally outside your project is considered bad practice as different projects may depend on different versions of the same node_module.Installing node_modules locally within the project directory allows different projects to have different versions of same node_module.

Install Certain NPM Modules Globally?

I'm debating how I should setup certain node modules.
Lets say I have a folder called "Projects". This will hold various code projects for node that I'll create under this going forward.
Now I can install stuff like cucumber, lodash, mocha, etc...stuff that I know I'll probably use across most all my projects:
1) npm install -g
- here, any package.json can find it on my PC I think
2) npm install [whatver] in the root of my "Projects" folder so that now I have an npm_modules folder sitting at the root so any projects created's package.json will able to find those type of modules at the root of my Projects folder
- here, I'd have to npm install once at the root of my Projects folder if not already installed globally and I didn't go with option #1
3) npm install into each project under projects. But this seems like it's not efficient. If I have to make people install stuff like cucumber every time they clone down a project, that means when they run npm install, it'll have to install cucumber again and again, for each project which seems stupid to me to do something like that if it's really a global package I plan on using across many projects
-- so here for example I might have several projects I create or clone: Projects**MyProject1**, Projects**MyProject2**, and so on. Each of those projects has its own package.json of course looking for dependencies like cucumber, mocha, etc. If I do it this way I'll have to wait for npm to install those into each's own node_module folder so for example Projects\MyProject1\node_modules\cucumber, Projects\MyProject2\node_modules\cucumber and so on. Seems stupid and duplication all over to do that...?
Suggestions on which option is best and why you think that based on your experience managing projects in node?
npm install -g - here, any package.json can find it on my PC I think
This won't work because global modules cannot be picked up by require in your node scripts.
npm install [whatver] in the root of my "Projects" folder so that now I have an npm_modules folder sitting at the root so any projects created's package.json will able to find those type of modules at the root of my Projects folder
This will work for sure as long as the projects in your "Projects" folder will always be there. If you publish a project then the dependencies for that project will have to go with it.
npm install into each project under projects. But this seems like it's not efficient. If I have to make people install stuff like cucumber every time they clone down a project, that means when they run npm install, it'll have to install cucumber again and again, for each project which seems stupid to me to do something like that if it's really a global package I plan on using across many projects
Why is this stupid? As long as you do npm install cucumber --save then your dependency on cucumber will be saved to your project's package.json file. All anyone who clones your project should have to do is this:
$ git clone project.git
$ cd project && npm install
npm install without any additional arguments will install all the dependencies listed in the package.json file for the project. It only has to do this once. After that all the dependencies are downloaded and installed within the node_modules directory for your project. The only time they'd need to run npm install again from the root of the project directory would be if they deleted the node_modules folder or you made a change and added a new dependency to package.json.
Installing modules in your "Projects" directory will make them available to any scripts requireing the module from within any subdirectories. Keep in mind that if I were to clone your repository I won't have your "Projects" directory. I'll just have the directory for your project, wherever I cloned it to. I need to get those dependencies somehow and the easiest way is for me to cd into the project and run npm install where you should have a package.json file that lists all the required dependencies.
PS - npm install [module-name] --save only saves the dependency version if you already have a package.json file in the root of your project. If you don't have one yet, then initialize one first.
$ npm init

How to include other NPM modules when publishing to NPM?

I am trying to publish my first module to NPM, it renders markdown with EJS templating, it uses two other npm modules marked and ejs, I have these as dependencies in my package.json file. I have a .gitignore file that contains my node_modules directory, and also a .npmignore file that is empty.
I have successfully published to npm.
However when I try to install my module by putting it into the package.json of a test app and doing npm install -d it installs, but it does not install its dependencies, if I go into the test app root node_modules directory and then into my newly published module's installed directory, It has not installed any of its dependencies, it has not have a nested node_modules directory of its own.
There should be a way to get my module's dependencies to install with it correct, when I include express as a dependency, it installs its own node_modules folder with connect and other modules installed, I want to do the same with two other npm modules.
I know it would work if it would install its nested node_modules dependencies, when I do this it works.
$ npm install -d
$ cd node_modules/my_module
$ npm install -d
$ cd ../..
$ node app
EDIT: Here is a link to the GitHub repo for my module, and here is the package.json.
EDIT: Note, this has only happens when I had my dependencies marked and ejs already installed in my test app. When I then installed my module, it did not install marked and ejs in its own node_modules directory. However, if I remove all modules from the test app and install only my module, it will install them. Is there anyway to get it to work regardless of whether my dependencies have been installed beforehand.
It should all "just work" as is.
npm does not install any new modules, because it sees there are already appropriate modules in a node_modules directory at a higher level. Because node's require will look up into the tree, trying node_modules subdir for each directory, your module's require statements will work, without having a node_modules directory of its own.
If you'd install the module in any place which does not have the right dependencies already installed, they would be installed under the module's own node_modules directory. Alberto confirmes this.
You may want to specify a more specific version of the dependencies in package.json though. This will ensure your module gets to use the version of the dependencies you have tested it with.

Resources