Story time. So, I just inherited a chaotic work project that felt completely out of control. I had to take a moment to gather my thoughts before diving in. Time to roll up my sleeves and tackle this mess!
The Starting Mess
I inherited a project that had spiraled into a state of - well it was in some state for sure. No version control. Instead, a graveyard of duplicated files named things like old_filename.extension
and even a collection of zipped folders that served as backups whenever something got changed.
To be fair, the project worked, and that counts for something. Whoever built and maintained it—whether it was one person or multiple—was probably thrown into the deep end and made the best of their situation. I respect that "get-it-done" energy.
Step 1: Implementing Version Control
Before touching a single file, I set up version control. If I messed anything up, I needed a way to revert changes easily. My initial commit had over 100 files, many of which were redundant.
Running:
git show --pretty="" --name-status
showed me the list of files in that commit, including all the old_filename.extension
artifacts.
To keep track of my thought process and ensure that whoever inherited the project after me had some documentation, I created a decisions.md file. In it, I documented the state of the project when I found it and the cleanup I was able to do within my limited timeframe. My knowledge of Git was definitely stretched during this process, which was a bonus learning opportunity.
I introduced software best practices:
- Version control
- Reusability (DRY principle)
- Documentation
- Removing unused files and dependencies (as much as time allowed)
And then, finally, the main point of this article: Updating the npm packages.
Checking Outdated Packages
To check outdated npm packages, I ran:
npx npm-check-updates
which gave me the following output (grouped manually into minor and major versions).
Minor Versions:
package A ^1.19.0 → ^1.20.3
package B ^1.7.4 → ^1.8.0
package C ^1.4.5 → ^1.4.7
package D ^3.1.6 → ^3.1.10
package E ^1.14.0 → ^1.23.9
package F ^4.17.1 → ^4.21.2
package G ^1.17.1 → ^1.18.1
package H ^3.1.0 → ^3.1.1
package I ^0.2.0 → ^0.2.1
package J ^0.4.1 → ^0.7.0
package K ^8.5.1 → ^8.13.3
package L ^2.3.3 → ^2.3.4
package M ^3.0.2 → ^3.0.3
package N ^6.9.0 → ^6.37.5
Major Versions:
package O ^0.16.0 → ^1.0.4
package P ^10.0.0 → ^16.4.7
package Q ^2.2.4 → ^3.0.7
package R ^2.0.12 → ^3.1.9
package S ^4.5.2 → ^6.3.0
This project hadn’t taken a shower in a while. Five packages had to jump at least one major version, two had to jump more than one, and one package had to upgrade by six major versions. SIX! Some wars have lasted fewer days than that - I am looking at you, Anglo-Zanzibar War.
Oh, and Bootstrap was in the .gitignore
, so even that required a manual backup just in case my update completely wrecked the UI. You know the unthinkable happened, and the roundness of the buttons affected sales
The Update Process
I started naturally with patch updates:
npx npm-check-updates -t patch -u && npm install
Smooth. No issues. Committed the changes.
Then, minor updates:
npx npm-check-updates -t minor -u && npm install
Tested it. Everything was fine. Committed again.
Then came the major versions. At this point, Icarus was soaring with his wax wings. Instead of going one package at a time, I decided to take a shortcut and upgrade everything at once:
npx npm-check-updates -u && npm install
Why not? I had backups. I had version control. This was controlled chaos, right?
IT. DIDN’T. WORK.
Cue the surprised Pikachu meme.
Back to One-by-One
I reverted and took the slow route:
- Removed completely unused packages
- Updated packages from smallest jump to largest
- Tested thoroughly
The biggest offender? dotenv, which had to jump six major versions. Fortunately, it does exactly one thing in most projects, so I updated it with confidence:
npm install dotenv@latest
No issues.
Then came nodemon—another easy one. Also, it updated smoothly.
Now, three remaining major updates, but first—a detour into unused packages.
Tracking Down Unused Packages
To check if a package was actually in use:
npm ls <package-name>
Then, as a second check, I searched the entire codebase in VS Code.
A third approach:
npx depcheck
which gave me something like this:
Unused dependencies:
Package A
Package B
Package C
Missing dependencies:
Package J: ./index.js
Package K: ./index.js
Not 100% reliable—some "unused" packages were actually required. (RIP, pug. Uninstalling it broke everything.)
The Last Two Major Updates
Back to the 2 remaining major versions. Wait, what's that? Oh, it's just the sun being too close again—oooh, my wings are melting.
The app; crashing. Even before I attempted the major version update? Sigh!
Icarus had to deploy the parachute. I had been making commits regularly so that I could always revert. There indeed had been a breaking change when I updated the minor versions because suddenly, I was getting an error when logging out. I had to put on my git detective hat and go snooping for the point in time when it stopped working. My first guess, passport.js, when I arrived in that commit update, turned out to be correct. The bump in passport.js had broken the log-out functionality. So I checked out that commit and switched back to the older version of passport - to be handled later.
For the last time, back to the last 2 major version upgrades. One of them gave me no problems. The last one had some breaking changes, which means I had that and passport.js to take care of before I was done. But they both ended up being fixed within a day.
Wrapping Up
So that was the story of how I had to upgrade some decayed packages in an npm project. What started as a soup of outdated packages, missing version control, and abandoned dependencies ended up cleaner, more maintainable, and fully documented.
Would I do it again? Sigh! I got paid so... just kidding I ended up learning more about git and npm on this project than I ever imagined I would. No kidding - there is a senior dev I look up to who said he had never had to go down some of the git and npm rabbit holes i went down during this project. So would I do it again? Probably. But next time, I might just start with one package at a time instead of playing Icarus.
Lesson learned.
Top comments (0)