Lerna. Install dependencies to root project - node.js

I have standard Lerna repository like this:
my-repo
- package.json
- packages
- api
- package.json
- web-app
- package.json
If I need same dependency in both packages (for example lodash), then people in tutorials suggest to install it to both sub modules and then bootstrap project with with lerna bootstrap --hoist flag.
Because of --hoist flag lodash dependency will be loaded only to root level node_modules but both sub-modules will contain it as dependency in their appropriate package.json
But Node’s package resolution algorithm searches up the file tree looking for node_modules folder.
So my question is why I can't just install common dependencies to root level project? Then lodash will be located under root's node_modules. And sub-modules (packages) will find it because Node will search up for node_module until the root of the file system is reached.
At least it will help me to avoid using uncommon lerna bootstrap --hoist, as well as lodash dependency will be present only once at the top level package.json (and not twice: in package.json of both submodules)

So my question is why I can't just install common dependencies to root
level project?
You can, and you're right, node's resolution algorithm will find the shared dependency fine.
The downside of doing this is that you lose flexibility, and you would need to deploy or work with the whole mono-repo which might be fine for you. A more traditional approach is to keep production dependencies in the sub packages so that you can publish the packages and use them individually without depending on the root of the monorepo, but again, this might not be important for you.

If your packages are npm packages that you intend to reuse by publishing to some npm registry, then you should give them proper package.json dependencies.
A package should always list what it requires to operate. E.g. if your "api" package requires lodash at runtime, then it MUST have lodash in its dependencies. Otherwise an app could install it without lodash; then it would fail to run.
In your lerna repo, your "root" package.json is not connected to any npm package, and is not published, so it doesn't affect your "real" npm packages: "api" and "web-app".
Finally, if you don't intend to publish your packages as npm packages, then do whatever you want. Lerna is probably overkill in that case. Even the package.json is overkill, because it's just being used for its scripts.

Related

Install the dev dependencies of my dependencies

I have a monorepo where I have a /packages folder with many packages.
I can use npm i ./packages or npm i if they are already specified using using the file pointer.
Looks something like this:
"dependencies": {
"#reggi/command": "file:packages/command",
"#reggi/dep-merge": "file:packages/dep-merge",
"#reggi/dep-merge-cli": "file:packages/dep-merge-cli",
"#reggi/dep-pointer": "file:packages/dep-pointer"
}
The issue is that if I install these packages I don't get dev dependencies.
What I really want is to also install the devDependencies of these dependencies.
lerna a popular tool that has pioneered the usage of monorepos, suggests that you should add all the devDependencies for these packages in the root package. The issue with this is that it eliminates the ability for two packages to depend on different versions of a given dev dependency.
What I have done is created a script that merges all the devDependencies into dependencies at preinstall then undoes the changes. This works but can be kind of wonky at times, especially when explaining all this to shrinkwrap.
It would be nice if I could just npm i --allDevDepsFromDeps and it would install all of my dependencies dev dependencies.
Is there any other solution I am missing?
I don't see what you're trying to achieve there, aren't the devDepencies used for ... development?
If you want different version for different package just don't put them in the root but in each package.
The issue is that if I install these packages I don't get dev dependencies.
You should consider those packages as 'production'/'bundled' packages, you don't need dev dependencies in this case.
For example, when you are working on #pkg/A, it will have its own devDep but then if you work on #pkg/B that depends on #pkg/A, the #pkg/A should be the production/bundled version (without devDeps).
Maybe you should have a look at bundledDependencies or peerDependencies, that might help you.

Is it possible to avoid local node_modules in js projects?

I am exploring nodejs and js frameworks. I noticed that when I create a project, for example with vue
vue init webpack my-project
I get a HUGE directory named node_modules containing a lot of things not related to my project. Newbie in this field my only wish is to gitignore this folder or better, put it somewhere else.
Is it common to have local modules to a project? Is there a way to install all these dependencies globally or in a dedicated environment (e.g Python virtualenv)?
The directory does contain libraries that are required by your project - and their dependencies. From my experience, the dependencies of the libraries I'm using are about 3/4 of the folder size.
You can install a library globally using the -g switch of npm, I'm not sure if vue has similar option. But this is not recommended - the point of installing libraries with your project is that the project will remember which libraries belong to it, those are saved in package.json.
You could copy the node_modules directory to the root of your hard-drive and merge it with other node_modules directories, but you're risking that you'll mix different library versions that way, so this is not recommended.
Unless you're running low on free space, just leave it be. Remember to add the node_modules to .gitignore if you're using git.
In short, node_modules is a place where all your project dependencies are stored. And allows you to use these dependencies in the code if you want to and allows for the modules itself to have it own dependencies if any.
And it is very common or rather always the case when a local node_modules folder is created.
You can install dependencies globally by doing npm install -g module_name command via your CLI. But these may cause the issue if the global paths are not configured properly.Also, it is not advisable to keep all the required dependencies by an application in global context.
If you do not want some dependencies to be part of your production environment you can install them as dev dependencies via npm install--save-dev module_name command. These(normal & dev dependencies) will be installed when a developer clones your project and run npm install locally to run the project and run tests. But to ignore these from being installed on production you can execute npm install --production command, this will make sure that only dependencies required for your code to run will be installed in the node_modules folder.

ReactNative: is it possible to avoid storing all dependencies in node_modules subfolder

I'm quite new to ReactNative so sorry if it's obvious, but..
Each RN project init-ed via CLI has a large number of node modules stored in project_root/node_modules. Not that I would mind, but if you have several projects it seems redundant and takes up time/space to move it to the source versioning system.
Wouldn't it be possible to retrieve all these same modules from the general node_modules on the machine instead ?
You never want to store dependencies nested in node_modules in your source control... it defeats the whole purpose of versioning and dependencies in general. Your package.json file will specify the versions so when you run npm install it knows exactly which dependencies to grab.
As an alternative, Yarn is an up and rising package client that Facebook developed that does a much better job of caching your packages locally so that way if multiple projects reuse the same depencencies, it will still satisfy the need to keep them in node_modules but doesn't need to perform http requests for each one.
Yarn doesn't replace NPM as a package registry, just a better client to download, maintain, and cache those packages.
Yarn also adds a yarn.lock file (similar to Ruby's Gemfile.lock) that allows you to lock in the specific versions used in your app, regardles of the package.json. This file can be stored in version control, which is probably what you were wanting to achieve by saving the node_modules in version control.
Some good reads...
Yarn vs NPM
Scotch.io Yarn Tutorial
Why I'm working on Yarn (Yehuda Katz)
I would echo Brad's answer: Don't put node_modules in version control. npm install will install the correct versions from the package.json. Just put package.json in version control, not node_modules.
However, if you still want to save disk space, you can install some of your dependencies in a general node_modules folder by using the link option:
npm config set link true -g
You can read more about link here: https://docs.npmjs.com/misc/config#link.
Note that you must not include node_modules in your version control when using this option since npm will put symlinks to the globally installed packages in node_modules. The global install location varies from machine to machine, so if node_modules is in version control, it may link to non-existent locations.

What are the main uses for the NPM package.json file?

I read from here that the dependencies in the package.json file allow people to install the dependencies if they install your project through npm-
Finally, the dependencies field is used to list all the dependencies
of your project that are available on npm. When someone installs your
project through npm, all the dependencies listed will be installed as
well. Additionally, if someone runs npm install in the root directory
of your project, it will install all the dependencies to
./node_modules.
Where will all the dependencies be installed to if someone doesn't run npm install in the root directory of your project?
Also, what if they choose to clone this project through Github instead? It would be ready to go anyway, right? Then at that point what is the purpose of the package.json file besides giving the user meta data about the project?
Where will all the dependencies be installed to if someone doesn't run npm install in the root directory of your project?
If by that you mean 'where will they be installed if you run the command in a different directory', NPM will search upwards through the parent directories until it finds package.json, and then install the dependencies in a node_modules folder next to that file. I.E. they'll always end up in the project root.
Also, what if they choose to clone this project through Github instead? It would be ready to go anyway, right? Then at that point what is the purpose of the package.json file besides giving the user meta data about the project?
This isn't the case! Node projects just about always have a .gitignore file which explicitly excludes node_modules from being committed to version control, and expect you to run npm install after downloading the source.
There's very few good reasons to have your dependencies in your GitHub repository - as long as a project adheres to Semantic Versioning (the vast majority of packages do), npm install will never cause incompatible versions to be downloaded, and if you absolutely need to lock down the versions of your dependencies, you can just use npm shrinkwrap.
EDIT: As Matt's comment very helpfully pointed out, there's several features of NPM that go beyond simple metadata - the one I probably get the most use out of is Scripts, which allow you to create project-specific aliases for command-line operations.
An example of where this has come in handy for me is running the Webpack development server - it's installed locally to my project in the devDependencies (which you can do using the --save-dev option when installing a package), so if I was doing it manually, I would have to type something along the lines of:
"./node_modules/.bin/webpack-dev-server" --inline --hot
Which quite frankly, would be a bit of a pain. Instead, I can just add this to my package.json (note that node_modules/.bin is automatically added to the system path when using an NPM script, so you don't need to type that every time):
"scripts": {
"dev": "webpack-dev-server --inline --hot"
}
And then all I have to run is:
npm run dev
Beyond this simple use-case, there's also several 'special' script names which are automatically called upon certain events - for example, prepublish is run before publishing a package to the registry.
Each Node.js project must contain at least one package.json file, usually located in the root directory of your project. This file identifies the project and lists the packages your project depends on, making your build reproducible.
You can create a package.json file by using a text editor, but the quickest way is to run the npm init command and pass it the -y flag
npm init -y

Many unknown modules in node_modules folder

I am new to nodejs. And I found that there are many unknown modules in node_modules folder after I installed three modules (express, jade, gulp) in my local project.
Unknown module examples in the node_modules:
vary
statuses
send
promise
From the tutorials I see from others, after they installed gulp, there will be only one "gulp" folder in their node_modules folder, but this is not my case. Why? Thank you.
The node package manager (npm) updated recently, as part of that update, all modules are installed in the top level node_modules folder. This includes modules that your dependencies need to install. In the past these modules would be nested inside another node_modules folder in express (for example).
This is why the tutorials you read say different, likely they were written before this update.
It is mentioned in the npm changelog here
Your dependencies will now be installed maximally flat. Insofar as is
possible, all of your dependencies, and their dependencies, and THEIR
dependencies will be installed in your project's node_modules folder
with no nesting. You'll only see modules nested underneath one another
when two (or more) modules have conflicting dependencies.
#3697 This will hopefully eliminate most cases where windows users ended up with paths that were too long for Explorer and other standard
tools to deal with.
#6912 (#4761 #4037) This also means that your installs will be deduped from the start.
#5827 This deduping even extends to git deps.
#6936 (#5698) Various commands are dedupe aware now. This has some implications for the behavior of other commands:
npm uninstall removes any dependencies of the module that you
specified that aren't required by any other module. Previously, it
would only remove those that happened to be installed under it,
resulting in left over cruft if you'd ever deduped. npm ls now shows
you your dependency tree organized around what requires what, rather
than where those modules are on disk.
#6937 npm dedupe now flattens the tree in addition to deduping. And bundling of dependencies when packing or publishing changes too:
#2442 bundledDependencies no longer requires that you specify deduped sub deps. npm can now see that a dependency is required by something
bundled and automatically include it. To put that another way,
bundledDependencies should ONLY include things that you included in
dependencies, optionalDependencies or devDependencies.
#5437 When bundling a dependency that's both a devDependency and the child of a regular dependency, npm bundles the child dependency. As a
demonstration of our confidence in our own work, npm's own
dependencies are now flattened, deduped, and bundled in the npm#3
style. This means that npm#3 can't be packed or published by npm#2,
which is something to be aware of if you're hacking on npm.

Resources