Check out a free preview of the full Creating an Open Source JavaScript Library on Github course

The "Peer Dependencies" Lesson is part of the full, Creating an Open Source JavaScript Library on Github course featured in this preview video. Here's what you'd learn in this lesson:

In response to an audience question, Kent spends a few minutes talking about peer dependencies. When a library uses peer dependencies, it will specify a range of compatible versions. If one of those versions is already available, it will be used instead of a new version getting imported.


Transcript from the "Peer Dependencies" Lesson

>> [MUSIC]

>> Speaker 1: I'm gonna to stop for questions, cuz that is it for the browser build portion. If anybody wants me to go deeper into Webpack I can. Or if you feel comfortable with your abilities with Google, that's cool too. Yeah?
>> Speaker 2: So there was a dependency to unique-random-array before.

That's just injected then into the core directly?
>> Speaker 1: Yeah.
>> Speaker 2: Okay.
>> Speaker 1: Yeah, so, and actually, I'm glad that you brought that up. So if we think about the two weights that we're distributing in this now, in one way we say okay, we're distributing this to the npm registry, but we're not sending all of our dependencies up to the registry.

We're just telling the registry hey, I depend on these things, and relying on the registry to install those things when somebody installs our module. The cool thing about that with npm3 is if somebody else is using unique-random-array, then they can use the same one. And so there's not code duplication and stuff.

With the browser build, though, people probably don't wanna have to have a bunch of script tags for all these different dependencies that you have. They just say, I just want you and your functionality. There is a drawback though, that what if I have multiple copies of that thing?

Now I've got a lot of code in here that's duplicate. So that's not a big deal with unique-random-array. GZipping will probably take care of most of the problem anyway, cuz it'll see that as kinda duplicate code and compress it really well. But the story's a little bit different if you're running an Angular library, or a React library.

You don't want to bundle Angular and React with your library, but you do depend on those things, right? So I'm glad that you brought this up, cuz I wasn't gonna cover it and now I am. So please be patient with me if I mess something up. But the way that you solve this problem with something that's bigger, and the same thing kind of applies with CommonJS as well.

If you have one version of React and then there's some other library that is saying I depend on this other version, then what you can wind up with is people install two different versions of React, and they have two versions of React in their app. So the better way to do this for your library is change your dependencies to the ones that you care about, this duplication stuff.

You'd say peerDependencies. And so now what this means is you'd tell the npm registry, hey, if somebody installs me, they need to have this other thing installed themselves. And I'll just use the one that they have installed. And if they don't have that installed, then you need to give them a warning.

If they're using npm2, that'll actually fail, and that's really annoying. And so now it's just a warning. And so with this though, you want to basically accomplish the same thing with Webpack. You want to have a mechanism for people to say here's my version of Angular, or here's my version of React.

And so what we're gonna do, is I'm gonna take this, and I'm just doing this from memory so I think this'll work. It's externals.
>> Speaker 1: And okay, I'm not gonna do this from memory, we're gonna look at the Webpack documentation really quick. Yeah, it's on the root level of the object, and it's an array of modules that you don't want to have bundled, basically.

So then if I run npm run build and I pop open this and look at the umd. Now, based off of the environment, it's going to go get that dependency. So in the case of amd, it's going to say define, here are my dependencies, and then call the factory function.

And then this factory function now accepts an external module. And then anywhere in your library where you're using that external module, well see, now it's using webpack_requires_ {1} right there. So _uniqueRandomArray is coming from the Webpack external module. And then the same thing for CommonJS, it'll just say require.

So that's where it would be in the CommonJS land. And for globals it's a little bit different. Here it's just saying okay, I'm assuming that's what it'll be called. It's not always called what it's called on npm, right? And so with this API, you can kinda configure what it would be called given different environments, so it's totally possible to do that.

It's recommended for Angular or React or Ember or whatever framework, jQuery plugins and stuff.
>> Speaker 2: And then you can do some magic with the version number to give it a range or something like that, or a minimum version, or not?
>> Speaker 1: So, yeah, good question. With the umd stuff, there's no way to say, I require this version.

That would be something you would document. You could, at runtime, check the version and say, hey, I don't work with Angular2, I only work with Angular1. People using an Angular1 library with Angular2, they should probably know that. But yeah, so you could do something at runtime. There's no magic way to enforce that with umd, though, not anything like any solution that I'm aware of.

Yeah, so generally most people these days building serious applications are using a bundler and using npm. And so they'll get the help from peerDependencies to know what versions you work with and stuff. But a good rule of thumb is if you are gonna use peerDependencies, try to make the version range as loose as possible.

Because otherwise people will get warnings in their console, even when they do have something installed that's just a different version. And so you'd want to make it use the ^, and maybe if there's a beta version coming along then you'd say ^2.0.0-beta, and you could do the caret on that one, and so on and so forth.

You might go kind of way out there and just do *. Probably not advisable to do that, because then people would assume that your library works with all versions of this thing when in fact it doesn't. So yeah, but the general rule of thumb is be as loose as you can with your peer dependencies so you don't get people upset at you.

I've got a question from Mayenck. And the question is Babel and Webpack are the most commonly used approaches or are there some alternatives? How does it compare to Browserify? Great question, so Webpack is just the tool that I prefer to use most. It requires a lot less work on my end as far as installing things and configuring things.

And like actually this could even be simplified a little bit further, but I feel like it's a little more straightforward. Yeah I pretty much just prefer Webpack. If you're looking at the trajectory of the projects, Webpack is already well beyond two times its downloads this year than it was last year.

And so it's on a trajectory of being four times more downloaded than last year. Whereas Browserify is kind of flatlined and maybe even started going down. Now that's just their trends. If you look at the actual number of downloads, Browserify is still way more than Webpack. But I'm interested mostly in the trend, not in the history of legacy applications still using older things.

But that's kinda like a holy war of [LAUGH] bundlers, and we're not gonna get into that. This works and it works great. Another thing to consider also, is with such a small library like this one, there's a big chunk of code here that's not library code. Once it's minified it's not enormous.

Most of it is actually the 100 Names. But if performance is a concern for you on a really small library for some reason, or bundle sizes is a concern for you, you might look into something called Rollup. Which it's really kind of an interesting idea. But instead of changing out all the require statements for a special runtime require, it actually takes the code itself and puts it together in a single function.

Okay I'm requiring this JSON file, I'm gonna take this object and just poof, it's in that file now. And I'm gonna take unique-random-array and poof that's in the file, poof it's in the file. So you basically only have one file with pretty much one function that holds all of the content for your library.

So there's potentially performance improvements there. And certainly there are fewer bytes needed for that approach as well. Something to consider, but it's not what we're gonna get too far into today. And Mike is correct, Browserify does not do code splitting, but code splitting doesn't really matter in the context of a library anyway.

So, Browserify would be a totally legit option for something like this, if you wanted to look into that.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now