In this post, I'm going to give a brief intro to package managers, dependencies, and semantic versioning.
Any given development project will likely have numerous dependencies. "Dependency" is just a word to denote a framework or a library that someone else has written to make your life easier. Thanks, dependency authors! Dependencies allow us to write less code and spend less time figuring out logic from scratch. Sometimes you will hear dependencies referred to as packages.
A given dependency itself could have a bunch of its own dependencies. For example, say I have a project with ExpressJS as its only first-level dependency. The
package-lock.json file, which keeps track of the dependencies of a given package, is 375 lines long. My
node_modules file, which is where all those sublevel dependencies are installed, has 49 modules added to it. This is just on account of installing one dependency.
Imagine if you had to install Express, plus all of its dependencies, and then all the dependencies of those dependencies... No thanks. Dependency hell is what that is!
Enter package managers.
Package managers are tools (written and maintained by developers) that automate the task of installing and updating the dependencies of our project.
When we use a package manager (like npm or yarn) to install a package in our NodeJS project, the given package is added to the
dependencies of our
package.json file -- and all of that dependency's dependencies are also installed. You can find all of secondary dependencies in your
node_modules folder, as well as in the
yarn.lock file, depending on which package manager you're using.
If we're using Github to work on a team project, conventionally, we keep the
node_modules directory in our
.gitignore file. This means that anyone who wants to work on the project must run
npm install or
yarn after cloning from Github to install the relevant dependencies.
Here, some potential problems come into play with versioning. Any given package has a version number that looks something like this: 1.2.3. Each part of that number represents the major, minor, and patch version of a package, respectively.
Semantic versioning is the name of an agreed-upon system that helps developers decide what kind of new version they'll be implementing with a given change: i.e. will it be a major, minor, or patch release? (Semver.org has some detailed info on how developers should distinguish between the versions, and a thorough explanation of semantic versioning theory.)
Additionally: in your
package.json file, the version number by a given dependency can be preceded by a carat (
^) or a tilde (
~1.2.3 means to install only the newest patch version of a package, so up to
^1.2.3 means to install the newest minor or patch version, so up to
1.9.9. A normal install will automatically add a carat to this version. You can remove this carat to indicate that the install should exclusively download the curently listed version.
So ideally, developers working on a project will be using the same version of a package, because, depending on whether it's a major, minor, or patch update, certain parts of the dependencies could behave in new ways that might break some code.
For a while, npm was the de facto package manager for NodeJS projects, and it's still many developers' go-to as well as the default for Node. However, prior to 2016, users were having issues maintaining consistent semantic versioning across teams.
In 2016, Facebook released yarn, which introduced a
yarn.lock file. This promised to solve the issue of different developers installing different versions of a package in the same project, leading to bugs. npm soon followed with its own lock file,
(There is still some controversy and confusion around how lock files do and should work, but that's beyond the scope of this article. This article is a good start for learning more.)
Leading up to 2016, npm dealt with a few major issues, and if you had asked me in 2016 which package manager I preferred, I would have probably said yarn. Since then, however, it seems like npm has made major upgrades to catch up to yarn and make up for the issues it created in the past.
node_modules file it needs to be in. Check out this blog for more info about how that works.