This content originally appeared on Bits and Pieces - Medium and was authored by Fernando Doglio
Your comprehensive guide to the five dependency types.
Regardless of whether you’re a back-end developer working with Node.js or a front-end developer using Node.js only as a tool for your packaging and bundling needs, you’ve surely come across the concept of dependencies.
But why are there 5types of them (yeap, that’s not a typo, there are 5 types of dependencies), and what use case do they work for? These are the questions we’re going to be answering today, so sit back, and relax, ’cause this is going to be interesting…
Normal (runtime) dependencies
Let’s start with the easy one, shall we?
Normal dependencies are the ones you see listed in the "dependencies" key of your package.json file. Most of the time, they only specify a name (for its key) and a version (the value), and then NPM (or any other package manager) takes care of grabbing them from the global registry (at npmjs.org).
However, that’s not all there is to them. Instead of the exact version number of your dependency, you can specify:
- An approximate version. You can work with normal numeric comparison operators to specify versions greater than one specific number (i.e >1.2.0 ), any version lower or equal to another number (i.e <=1.2.0 ), and you can also play around with any of their combinations (i.e >= , > , <) . You can also specify an equivalent version to another, by using the ~ operator before the version number (i.e "lodash":"~1.2.2 which would download anything between 1.2.2 and 1.3.0 or in other words, only patches). And we can also specify a “compatible” version with another number, which takes advantage of semver to understand compatibility (i.e "lodash":"^1.2.0" which would download anything that is not including a breaking change or missing any features).
- A URL. That’s right, you can even do away with the version and directly link to a specific URL, effectively downloading that module from somewhere else (such as Github or a direct download of a tarball file).
- A local file. Yeap, you can even link directly to one of your local files. This comes in very handy if you’re developing a module and want to test it on a project, before releasing it on NPM. Through the local file option, you can link to your local module’s folder. You can use both full and partial paths, as long as you prefix them with file:// .
When will you use normal deps?
Normal dependencies will contain anything that your project requires to work in production and that will not be provided by another module.
That might sound easy, but if, for instance, your project is actually a module itself, then you need to take a closer look at what that means. If your module is meant to be used with other projects, such as React or Babel, your dependencies shouldn’t include them, since they are expected to be already present, however, they’re still needed (we’ll see where those come in in a second).
So, remember, if it’s absolutely required for your project to work and you can’t rely on another library to include it, then it’s got to go inside your dependencies list.
Peer dependencies
Peer dependencies are a special breed of dependencies, in the sense that they’re meant to specify those packages your project requires or rather, it’s compatible with. However, you might not be specifically requiring them in your code.
Wait, a dependency you don’t require? I know, it sounds weird, but think about a Babel plugin, it requires Babel in the sense that if it’s not there, it won’t be able to work, however, it might not be explicitly requiring Babel for anything.
Now, you could potentially be adding Babel to your list of normal dependencies, however, when you install your plugin, it will also try to install Babel. And if you’re using NPM for example, it’ll install it as a local dependency of your plugin, meaning: it’ll duplicate the already existing installation of Babel for the host project inside your plugin’s folder.
When will you use Peer dependencies?
You can read more about Peer dependencies here, however, you need to understand that you’ll only use them when you need to specify a weak relationship with another project.
Understanding Peer Dependencies in JavaScript
In other words:
- When you need it, but don’t directly and explicitly consume it. Then it’s a peer dependency.
- When you need it, but it’s should already be installed by another project. Then it’s a peer dependency.
Examples of when you want to use peerDependencies are:
- Babel plugins. You want to declare things such as babel itself as a peer dependency.
- Express middleware packages: This is just one example of an NPM module that would require the use of peer dependencies. You’d want to declare express as a dependency, just not a hard one, otherwise, every middleware would install the entire framework each time.
- If you’re building a Micro Frontend, trying to decide which dependencies are external (so they don’t get bundled) and which ones aren’t. Peer dependencies might be a good way to handle this.
- Bit components. If you’re authoring and publishing front-end components, such as when you’re sharing your React components on Bit (Github), you need to set the react library as a peer dependency. That will make sure the correct library is available in the hosting project without installing it as a direct dependency of it.
For example, take a look at this React component I published a while ago: it’s a simple selectable button ( you click on it and it remains selected until it is clicked again).
If you install it, you’d get the full code which contains its package.json file listing all peer dependencies:
Notice how the package has no direct dependency, even though it needs React to function.
That also helps in keeping our component size as small as possible (1KB) — nothing redundant gets added.
Dev Dependencies
The name says it all, doesn’t it? I mean it should but when have names actually help us, developers, in our daily work? I know right.
Development dependencies are meant to contain those modules you’re using only during the development stage of your project.
But there are others, yes, like linting tools, documentation and the like.
The point here is, if you can deploy to production without using that package, then it’s a dev dependency.
The way they work, is that development dependencies only get installed when you run npm install or npm link from the root folder of your project.
Think about it, in that particular case, then it makes sense for them to be installed, since you’re developing your own project. But if you’re installing your project inside another one, then that process would ignore your dev dependencies.
When will you be using dev dependencies?
Any dependency that is not required for a production deployment, will most likely be considered a dev dependency.
The thing is, this works great for all modules except your host project. All dependencies installed inside it will skip their dev dependencies during the installation process, but anytime you deploy and re-run npm install on the host project, it’ll install all of its dev dependencies.
So consider using dev dependencies only on packages and modules that will be used by other projects.
Bundled Dependencies
These are meant for when you’re packaging your project into a single file. This is done through the npm pack command, which turns your folder into a tarball.
Now, if you do that and add the names of some of your dependencies to an array called bundledDependencies (fun-fact: if you use bundleDependencies it’ll work too), then the tarball will also contain those dependencies inside it.
{
...
"dependencies": {
"lodash": "1.0.2",
"request": "4.0.1"
},
"bundledDependencies": ["lodash"]
...
}
Look at that fraction of a package.json file, with that setup, when you run the npm pack command, you’ll get a tarball file, also containing the lodash package inside.
This comes in very handy when having to distribute your packages in a single-file format (remember that you can also specify their URL or local path as a normal dependency).
Optional dependencies
Finally, this type of dependency is just like the normal ones, they behave and can be configured in the exact same way. The only difference? NPM won’t exit out with an error if it can’t install them.
Normally, when you run npm install and the process can’t install a dependency for any reason (be it due to network failure, can’t find the file, the version or anything else), then it’ll error out and cancel the installation process.
Optional dependencies will instead, allow NPM to keep going. Of course, you are responsible for writing code that is capable of handling these missing dependencies, like:
When will you be using optional dependencies?
The obvious use case for this type of dependency is when you rely on an unreliable source. I know, why would you do that? Good question. Beats me, but you can definitely do it, the only issue is that you need to make sure your code can handle the missing dep.
But the other interesting use case, is to install truly optional dependencies. What I mean by this, is that sometimes you might have some system-specific dependencies, for things like CI-platform compatibility. In those scenarios, you might want to have these dependencies installed when you use the platform, but otherwise, you want to ignore them.
For those situations, you can use a normal npm install when you’re using the full set of deps, and then use npm install --no-optional when you want to avoid them. That way you skip these optional ones and only focus on the mandatory deps.
Everyone who’s ever used NPM at one point or another, has heard of normal and dev dependencies. The other 3 however, can be considered like the less popular brothers.
Although some of these do focus on very specific scenarios, they can be very handy when you run into them.
Did you know you had so many options? Leave a comment below if you’ve used some of the less common ones and tell us how you used them!
Learn More
- A Better Way to Share Code Between Your Node.js Projects
- 11 Great Tools for a Monorepo in 2021
- The Singleton Pattern In TypeScript
JavaScript Dependencies: Everything You Ever Wanted to Know But Were Afraid to Ask was originally published in Bits and Pieces on Medium, where people are continuing the conversation by highlighting and responding to this story.
This content originally appeared on Bits and Pieces - Medium and was authored by Fernando Doglio
Fernando Doglio | Sciencx (2021-02-10T21:44:06+00:00) JavaScript Dependencies: Everything You Ever Wanted to Know But Were Afraid to Ask. Retrieved from https://www.scien.cx/2021/02/10/javascript-dependencies-everything-you-ever-wanted-to-know-but-were-afraid-to-ask/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.