This video is available to students only

An Introduction to the 3 Types of Dependencies in React Libraries

Introduction to project dependencies, devDependencies, and peerDependencies.

The end goal of writing a library is having an application consume our code. In other words, our library would become a dependency of a project. In the same way as projects can depend on our library, our library can also have its own dependencies.

There are three types of dependencies:

  1. Dependencies we rely on (dependencies)

  2. Dependencies we only need for development (devDependencies)

  3. Dependencies we expect our users to provide (peerDependencies)

How package.json defines dependencies#

Our package.json file defines the three types of dependencies. Each dependency has a name to a corresponding version. We can use every type of dependency, or none of them at all. There is no rule on the number of dependencies in a project. Though keep in mind adding a dependency to our library comes at a cost. Every dependency added may make our library grow in size, and adds additional security concerns. Let's take a look at an example package.json:

When defining dependencies we want to stick to a version, or a range of versions we know will work with our library. Packages in npm (Node Package Manager) use semantic versioning. The semantic versioning standard communicates changes on a project. Version numbers are immutable, or cannot change once they're published. Semantic Versioning is defined as numbers separated by periods: MAJOR.MINOR.PATCH. When the major number is incremented there is a high probability of a breaking change in the code. For example, upgrading Webpack 4.0.0 to 5.0.0 is a major jump in features and deprecations; the code using Webpack will likely break when upgrading versions. Minor numbers are incremental updates. These could be new features, but breaking changes are minimal. Lastly, patch numbers communicate bug fixes and security patches. There should be no breaking changes.

Initial ReleaseInitial1.0.0
Backwards compatible bug fixPatch1.0.1
Backwards compatible new featureMinor1.1.0
Breaking change that is not backwards compatibleMajor2.0.0

Now that versioning is cleared up, what is up with those symbols in package.json of the last example? npm has additional utilities to make handling dependencies easier. For example, the caret ^ tells npm to use version 5.0.0 except if a newer minor or patch version exists. If version 5.0.1 had been published when we run yarn, then version 5.0.1 would be installed instead of 5.0.0. These utility symbols are useful to reduce micromanaging dependencies, and allow security fixes to be installed automatically. A full list of symbols can be found here.

^1.X.XWill allow updating the package to the latest MINOR or PATCH version.
>, <, =, >= or <= for comparisons, or - to specify an inclusive range1.0.0-2.5.1Will allow specifying ranges of versions (eg. any version between 1.0.0 and 2.5.1)
~1.X.0Tilde will allow any MINOR version greater than what's specified
||1.0.0 || >3.0.0Will allow for combining multiple version ranges (eg. version 1.0.0 or any version greater than 3.0.0)

Keep semantic versioning in mind when managing dependencies and publishing your packages.

When specifying peer dependencies, including a range in the semantic version can reduce warning messages users get when installing our library. We may know our library works on a certain major version of a dependency, but specifying an exact version X.0.0 in our peer dependencies will throw warning messages when a user tries to install a security fix X.0.X.

Be careful allowing ranges with major versions! Always test before publishing.


This page is a preview of Creating React Libraries from Scratch

Start a new discussion. All notification go to the author.