How to publish yarn workspace with root package.json dependencies? - node.js

I'm trying to publish one (yarn) workspace from a monorepo to npm repository, and include root project's dependencies in the published package. The setup is as follows:
package.json (contains shared dependencies, eg. single version of React to be used by all workspaces)
library/ (this is the one I want to publish, for consumption outside of this monorepo, the published package.json should contain the root dependencies as well as library local)
library/package.json (contains library specific dependencies)
app1/ (application that uses library)
app1/package.json (contains app local dependencies, and depends on library)
app2/ (application that uses library)
app2/package.json (contains app local dependencies, and depends on library)
So what I want to do, is to cd library and yarn publish. What I expect to happen is that the published package will work exactly the same way it works for my monorepo local apps. The problem is that yarn doesn't merge-in the dependencies from the monorepo's root package.json, and the published package's package.json only contains library local dependencies, from library/package.json. So when anyone installs this published library package, it will be broken because it imports modules from packages (dependencies) not listed in library/package.json.
Do I really need to write a custom publishing shell script that merges the root package.json's dependencies into library/package.json before running yarn publish?

The only type of dependencies that you can reliably put in a workspace root are dev dependencies.
Each package should declare it's dependencies in it's package.json file respectively.
What yarn does during installation is that it now looks at all the dependencies in all your workspace packages to create a single lock file and it won't put redundant dependencies in the package node_modules folder.
How you publish your workspace is up to you. I typically write a small Node.js script to run the publish command line for each package. Depending on what you put in your workspace you might want to version and/or publish your packages independently, this will give you that flexibility.

Related

Why yarn install downloads node_modules for dependency?

I have a node projection which has a dependency let's say depA. After I run yarn install on my project, it downloads all dependencies for depA in node_modules/depA/node_modules which makes the node_modules directory very big. It doesn't download this folder for other dependencies. Is there anything I should look at why it happens on depA?
Its how dependencies get installed in node.js, a folder with name node_modules is created and then all dependency mentioned in your package.json is fetched from npm server and downloaded.
Now comes the twist, say in your package.json has dependency depA only. but library depA internally is dependent on depSubA, depSubB then these 2 will also get downloaded so that depA can work.
In the previous version of npm (before 5 I guess), there used to be subfolders inside node_modules which had their independent dependencies creating chances of duplicities and huge folder, the latest version now shares these common dependencies.
check for more details https://docs.npmjs.com/configuring-npm/folders.html

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.

Lerna. Install dependencies to root project

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.

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.

Build and deploy framework for NodeJS

I've been looking around for a Java maven equivalency for NodeJS but can't really seem to find one so I'm posting this question to see whether there're a combination of tools/framework I can use to build and deploy Node. The specific tasks I'm looking for is:
Being able to grab dependent modules for a checked out code NodeJS project (for ex. Express or stuff like that)
Set up a private repository for NodeJS modules for in-house projects
Package with dependencies and make releases of Node projects to a repository (sorta like war)
Deploy a release to a remote box and fire up Node
Any help would be greatly appreciated!!!
Npm does most of that for you.
Dependency handling:
Create a package.json for your project (see required contents or use npm init)
Commit it along your project files, this will be your dependency tracking
npm install will sort out and download all dependencies
Deploying:
Upload/push your files to the server
Either send the node_modules folder along or run npm install on the server
To use your private libraries you'll need to either upload the modules folder or publish them (see below)
Private/local libraries:
Create the library anywhere you want (e.g. ~/Projects/mylib)
go to the mylib folder and run npm link
go to the project's folder and run npm install mylib
Now your local library is symlinked into your project's node_modules
To set up a private repository for your modules, follow these instructions

Resources