Background
An old customer reported a bug in one of the older versions of the product, and a decision was made to fix the bug and release a patch for it. The product consisted of an API and a React client that communicated with the API. The fix was purely a back-end fix behind the API, which should not have had any effect on the React client, but when the build server started building the pull request in GitHub, it was failing to build the React client. It was throwing errors on resolving the dependencies. Upon further inspection there was couple of issues found, that raised some red flags of some developers misunderstanding on how to build an application with npm.
The red flags
The first red flag was that when I looked at the CI/CD build script I saw that it was executing an npm install
to install the npm packages used by the React client. Never use npm install
on your build servers, there is a dedicated npm command for CI/CD.
npm ci
Using npm install
on build servers may update the dependency tree which will make builds inconsistent and nondeterministic.
But this was not the only red flag, the second red flag was that when I changed the build script to run npm ci
it started failing with an error saying it can only install packages with an existing package-lock.json
. This meant that the file was missing. Next, I checked the history of the branch and found out that a developer most likely has thought that since package-lock.json
is auto generated, it can be removed, and the build server will generate it again without knowing the purpose of this file.
What is the purpose of package-lock.json
The purpose of package-lock.json
is to describe the exact dependency tree that was used by npm to install needed packages and to guarantee a single representation of a dependency tree across deployments and continuous integration. A more detailed description of the file's usage can be found in npm documentation. What this meant for the patch I was trying to build was that now it was generating a different dependency tree that had incompatible versions of dependencies registered and failing the build.
Npm install vs. Npm ci
Before explaining how I fixed the issue, even though you may have already guessed the difference between npm install
and npm ci
, it is worth explaining it. npm install
will generate a new package-lock.json
if it does not exist or it will update the dependency tree if it does not match the packages specified in the package.json
. npm ci
will install packages based on package-lock.json
file and if the file does not exist or does not match the packages specified in the package.json
it will throw an error and fail.
Note it is better to use npm ci
if you are not going to add new packages or update the package version to keep the development consistent with other team members.
Solution and conclusion
To fix the issue I went back in the history of the branch and found the latest package-lock.json
file committed. After that I checked if changes on the branch after removal of the file has added or updated any of the referenced packages. Luckily, that was not the case and I just had to commit the file into the branch again. Then, I adjust the CI/CD to run npm ci
and everything was good and green.
Comments