How to make edits to npm packages and have them reflect in your project

Aug 19, 2024

The first question to answer is why I would even want to edit npm package if I’m not the creator or maintainer of it. Well, sometimes I may suspect that there is a bug and I want to find it and report for it to be fixed or I may want to experiment with the idea to extend some features in the package or add new ones.

Now of course that doesn’t necessarily mean I will be able to use these changes in production because it is quite likely that my desired updates to the package will not be accepted by whoever owns the package. But in most cases, I would be deploying things to production through Docker build pipeline and all of the packages would need to be available from npm registry.

There are ways to go around it with local package linking or with a private package registry server like verdaccio. But I would try to avoid using custom modified package versions if possible because it just introduces another point of complexity you need to think about maintaining it and making it available in your project from other means than the npm registry. Sometimes the benefits are worth the hassle and sometimes not.

But getting back to the question of editing the package and having the changes appear in your project. In the past I have done two most obvious and fast solutions to it but which as I will show next is probably not what you want to do.

Option one I have done, I would go inside my project /node_modules folder and edit the package dist files directly. Editing directly inside your projects /node_modules may work for the quick and fast test but the problem with this approach is that there is no version control and you are risking losing your edits the next time you reinstall your packages. So if you are planning to work on something longer for 5 minutes beyond a quick test it would be advisable to have both reliable persistance and version control.

Option two, which I have also done is copying the package dist code from my project’s /node_modules folder and pasting it directly inside my project and changing package import statements in my project from node package to local project module imports. But this approach is also not optimal because now I’m littering my project code with package code and doing direct import of that code instead of package import. Considering I only wanted to test some things out or maybe look for issues inside the package I don’t think it’s a good idea to have the package code to be part of the project code. Of course, I could do .gitignore but then I would lose version control on my edits which most of the time I always want, to go back and forth between my changes. Also by doing .gitignore I would still be left with import statement changes that are committed and now as git is concerned, it doesn’t exist so we are left with some changes that were ignored, and some not. Of course, it works for the time being but I could see how I could shoot myself in the foot in the future by doing this.

Also in both variations of the editing package I mentioned above, I was doing edits or copying over package dist code. Which sometimes may not differ from the source code if the package was written as ES5 module and there were no additional build steps, but in some cases the package dist code maybe already minified one big chunk of JS which would be the worst option or somewhere in the middle. That means that I probably want to work on package source code and run the build step if it exists.

Some packages in npm registry may include all of the source code inside your project’s node_modules folder along with the dist code and necessary information and scripts for building it. But some packages may exclude the source code folders and any necessary build information they may only have dist code inside. It is done for reasons to make the package smaller so it can be downloaded faster from npm.

If that is the case with the package you want to work on that means that you can’t get the necessary package files directly from your project’s node_modules folder or by running npm install <package-name> anywhere else locally. You will need to get the package source code from GitHub. Fortunately, it is just as easy as getting it from npm with git clone <page-repo-name.git> command.

I would clone the package in the parent folder of my project directory and in my projects package.json dependencies change the version of the package to the relative path to my local package on my system that I fetched with git clone. This was my package.json

{
  "name": "my-react-project",
  "dependencies": {
    "react": "^18.3.1",
    "package-to-edit": "2.0.1"
  }
}

I changed"2.0.1" to a local file "file:../package-to-edit", and the package-to-edit is the folder where the package.json files of my package-to-edit package lives in and is the project root of it.

{
  "name": "my-react-project",
  "dependencies": {
    "react": "^18.3.1",
    "package-to-edit": "file:../package-to-edit"
  }
}

"file:../package-to-edit" just says that instead of what we do normally when installing a package from npm registry, instead go to the parent folder then inside the package-to-edit folder and get the package code from there. Now the thing to remember is that this is not a link to the package from our project this just says that when installing all packages or this one in particular instead of fetching it from npm registry fetch it from that local folder so it will make a duplicate from ../package-to-edit in your project’s /node_moudules/package-to-edit folder.

Now with this setup in place, I would edit the package source files I cloned from GitHub and run the package build if such exists. Now one important part to mention is that every time you make changes to the local package and build it, for changes to be present in your project you must get the new updated package files in your project because as I mentioned previously the local package was duplicate from ../package-to-edit two your project’s /node_moudules/package-to-edit and any subsequent changes to the ../package-to-edit will not be present in your /node_modules folder. It is necessary to sync the changes and it can be done by reinstalling the specific package:

npm uninstall <package-name>
npm install <package-name>

A simple npm install may not work, because the package may be cached and npm will not try to fetch it again. npm install --force would work but that will cause all packages in your project to be downloaded again from npm and it can take a while sometimes.

This step of building the package and reinstalling it inside your project can be very annoying if you want to see changes in quick intervals. A solution to address the build part could be to write a file watcher for local package source files and run the package build step every time you edit the package source files and hit save. Package reinstallation on every edit could be avoided by using npm workspaces or npm-link command. I may write an article on how to do that in the future.