If you're developing a library and an app in a monorepo, the npm link
is your friend. It allows you to use the library the same way you're using a library you're downloading from npm. But it's more flexible: changes to the library immediately show in the app.
TL;DR
If you're in a hurry, skip to the "wrapping it up" section or scan this picture. Image published by BeyondJava (entire sketch) / Peggy_Marco (images of the persons) on BeyondJava / Pixabay under a Pixaybay license.
Digression: anatomy of an npm package
Technically speaking, an npm package is simply a folder someone uploaded to npm. This folder must contain a package.json
to be helpful. Despite bearing the same name, this file differs slightly from the package.json
you use in app development. In particular, it must define an entry point. Usually, that's the main
entry:
More modern libraries may use module
instead of main.
Using module
activates the ESM module system, producing more compact binaries.
The second file you need is the JavaScript file itself.
That's it. Most npm packages contain many files, but at the heart of it, an npm package is simply a folder consisting of at least two files.
Publishing the library locally
Most frameworks offer a standard way to create and publish npm packages. In the case of Angular, that's using ng-packagr. When writing this article, I quickly checked React and Vue.js. To my surprise, neither framework seems to offer a standard way, but there are enough tutorials to figure it out quickly. So, I'll skip this.
Let's assume you've compiled your library into a folder called dist/my-favorite-library.
Theoretically, you could upload the library to the global npm repository by running npm publish
from the dist
folder. But if you're like me, you prefer to test it locally, even if it's merely a smoke test. Or maybe you're using a monorepo and don't intend to publish the library. So, let's publish the library locally. It's simple:
Note that the name of the folder becomes the name of the library.
Using the local library
Before compiling the app using the library, you need the counterpart of npm install my-favorite-library.
That's npm link
, plus the name of the library:
Now, the library behaves precisely the way it behaves if installed via npm install my-favorite-library.
Only you've never uploaded it to npm. That's ideal for testing libraries locally and suitable for using private libraries in a corporate network without a custom npm repository.
It's even better than npm publish && npm install.
Each time you build your library, npm link
automatically updates the local node_modules
folder.
How does it work?
If you've read until this point, you're probably a JavaScript developer, and you are familiar with the two classes of node_modules
folders:
- The local
node_modules
folder belongs to your application. Every application has its copy of thenode_modules
folder, each populated with different libraries. - The global
node_modules
folder contains infrastructure like the Angular, React, and Vue CLI tools. These commands and libraries are available everywhere, even outside JavaScript projects. This allows you to use commands likeng new
orcreate-react-app.
npm link
is another global node_modules
folder usage. After running npm link
without parameters, the global node_modules
folder contains a symbolic link to the current working directory. The package name is the name of the parent folder.
npm link my-favorite-library
adds another symbolic link to the local node_modules
folder.
In other words, the global node_modules
folder plays a similar role as the npm repository. However, the symbolic links add a live-update feature. Each time you compile your library, it updates the dist folder. The two symbolic links reflect this update to your library.
Disable caching!
If you're using a contemporary version of Angular, you might notice this doesn't work. That's because Angular assumes the node_modules
folder hardly ever changes, so it uses caching to speed up compilation. You must deactivate caching, or you'll want to delete the .angular
folder each time you build your library.
Wrapping it up
npm link
is a straightforward way to use a library within a monorepo, or to test a library locally before publishing it to the global npm repository or your corporate npm repository, Nexus or Artifactory.