Fixing and Testing NPM Dependencies Locally without Pain
npmsoftware developmentopen sourcetestinggithubcliThe problem with an external dependency from npm
Imagine you are working on a project and you have a problem with a dependency. It could be slow, or has lack of functionality. What would your approach be to make these changes?
I don't think contributing directly on GitHub is fast enough. You'll try to fix it locally first. If it's urgent, you can vendor the dependency and contribute later. After the release you can get it from the registry again.
Let's go back to the "fix it locally" approach, and I'll tell you a story of me suffering. I was working on a feature for an open-source library for aws lambda, I needed to make changes for one of the packages in a monorepo that is a dependency for others. This is how my workflow looked like:
- Make changes to the dependency code
- Build the dependency
- Create a package with
npm pack
- Move the resulted package archive somewhere
- Run
npm install <path/to/somewhere/tarball.tgz>
in the project - Look at the result
It was a nightmare. Imagine you forgot to add something, so you have to go again. The worst feedback loop ever.
The solution was always there
At that time I didn't know about this simple command npm link
.
Recently, I was building an app that uses my open source react component library, spartak-ui
(GitHub), as a dependency. However, it didn't have the component I needed. Sounds familiar: I have a dependency that I need to change. Even though I own the dependency code and can publish it on npm
quickly, rushing without proper testing isn't a good idea.
But look at how my recent workflow looks like:
- Make changes to the dependency (add the component code)
- Build the dependency (library re-builds with the
--watch
option) - Look at the result (
vite
refreshes the page with the app)
Amazing, right? Below is how to set it up, which is also pretty easy.
Setting up the faster workflow
In the dependency's root directory run the command:
npm link
In the project's root directory uninstall the npm-installed version of the dependency.
npm uninstall <dependency-package-name>
And link the local dependency to your project:
npm link <dependency-package-name>
That's it! Make changes and enjoy the faster feedback loop.
How npm link works
The dependency won't be added to the package.json
, but it will be available in your project. npm link
creates a symlink, not an actual installation. This means the local version of the dependency is linked directly to your project, allowing changes in real-time without modifying the actual node_modules
structure or creating a versioned package.
Clean up after the work
When you're done coding and testing, don't forget to unlink the local dependency.
npm unlink <dependency-package-name>
How to consume the fixed dependency
If you’ve made a hotfix for the dependency and don’t have time to wait for the maintainer to merge your pull request, release, and publish it on npm, you can vendor the dependency in your project by using npm pack
(npm docs) and install it from the generated archive.
If the change in the code is something useful to others, please go and contribute!
Once the change is released and published to the npm registry, you can reinstall it back by simply running npm install <dependency-package-name>
.
Last words
If you’re building and maintaining a library or have an urge to fix something in an external dependency, I highly recommend integrating npm link
into your development process for faster feedback loop and easier testing.
Documentation about npm link
for the reference: npm docs.
Thanks for reading!