How To Keep Track of Your Pinned NPM Packages?
How to document/comment why package.json packages are pinned to specific versions? How to enforce no one accidentally updates them?
In a huge project I work on, where we have around 100 npm packages, once in around a month or two, we try to update all our packages to their latest versions because:
- Bugs, performance, and security issues fixes are constantly shipped, and we are fond of enjoying them.
- Making sure the packages are following the latest documentation that appears on their website to prevent confusion of whoever looks at it.
- Gradual updates that takes less then a day each are much safer and faster then huge updates with many braking changes of different packages where a certain feature/bug fix is needed.
Why Would You Pin a Package?
Some packages are pinned to specific versions. Here are a few examples of why packages might be pinned:
- Bugs/problems in a certain version-
In this case we can update the package as soon as it is fixed. - Braking changes that requires considerable changes in the application-
In this case we open a ticket about the package version update and estimate how it should be done, the time it takes, and prioritize this work. But until someone gets to work on it, the package is pinned to a version before this braking change. - Sometimes we fork a package to quick fix/adjust it and pin the version to the fork’s repository commit-
In this case we open a ticket about making the adjustment in a generic way to open a pull request on the original project.
Not doing so might result in falling behind in receiving all the benefits of staying on the latest versions of this repository.
Sometimes we decide to fall behind, because solving this in “the clean way” might be hard and not of high priority for the project. - Some packages are waiting for other packages to be updated for one of the other reasons specified above.
The Problem
How can we document/comment/enforce these reasons. Simply pinning a package is not sufficient. New people or even the one who pinned a package, won’t remember why was it pinned in the first place.
In some point we were using React 15 when most of the community moved to React 16. We had more then 10 packages pinned down to support it. It was a mess until we documented it.
Possible Solutions
In short, I didn’t find a very clean way to solve it, but I did found a good one. I hope the community will come out with something better in the near future. I even suggested a way to achieve it with yarn. If you have a better one, please comment below and let us know. I might update the article with your suggestions.
Comments in package.json
This is the solution we are currently using:
As you can see, we simply add a section to package.json that documents the all the version pins. No tools are using it. These are just comments for the developers who look at the file.
It’s not perfect. Nothing prevents a developer from updating packages to versions they should not update, only to find out later that somebody already found out issues with these new versions.
Also, somebody might actually manage to update a pinned package and not update the comment section, leaving it outdated.
This is because these comments are not restricting. I actually thought of writing a script that enforces it upon packages manipulation, but for the time being these comments are enough for us.
Why don’t we use actual comments like these?:
"dependencies": {
"@rebass/grid": "^6.0.0",
"@welldone-software/why-did-you-render": "^3.0.6",
...
// older 2 versions has accidental breaking changes",
// https://github.com/kirill-konshin/next-redux- wrapper/releases/tag/2.1.0",
// update when version 3 is released"
"next-redux-wrapper" :"2.0.0",
...
},
Looks nice, but package.json
should always stay a canonical JSON that you can run JSON.parse()
on it’s content. Libraries, package managers, IDEs, and other tools are expecting it to be so and sadly, comments are not part of the JSON specification.
JSON5 could of work for this purpose but most of the tools mentioned above are not yet expecting package.json
to be in this format.
Pinning Versions Using Greenkeeper.io
This dependency management tool provides a solution but it only fits whoever uses it in the first place.
It updates your packages automatically in your CI. If a problem arises in your CI, the build would fail and you will have the option to pin down the version of the package that caused it and open a ticket about it.
If a problem arises and it doesn’t brake the CI, make it brake it by adding tests and repeat the mentioned above way to deal with it.
This is a great partial solution but it does’t cover all the cases where you want to pin a package mentioned above.
Documentation Elsewhere
Some people suggested documenting versioning in readme.md
or in the project’s wiki. I think it has no advantages over the documentation in package.json
solution I mentioned above, but I still wanted to mention this possibility.
My rfcs on Yarn
A few months ago I opened an rfcs on Yarn to add a way to comment on packages including version enforcement. I hope it would be implemented some time. Here is the specification I suggested regarding the implementation of such feature.
Thanks for reading, like, subscribe, and share the article :)