Check out a free preview of the full API Design in Node.js (using Express & Mongo) course:
The "CommonJS" Lesson is part of the full, API Design in Node.js (using Express & Mongo) course featured in this preview video. Here's what you'd learn in this lesson:

Node uses CommonJS as it’s module loader. Scott explains how to use the require() method to load built-in modules, Node modules, and user-created modules. He also talks about the differences between using exports and module.exports when creating a module.

Get Unlimited Access Now

Transcript from the "CommonJS" Lesson

[00:00:04]
>> Speaker 1: So Node uses CommonJS for its module loader. Anybody here knows what CommonJS is?
>> Speaker 2: Module loader?
>> Speaker 1: [LAUGH] How'd you know? [LAUGH] Yeah, it's a module loader. That's exactly what it is. It's kind of funny, because when I first heard of CommonJS, and I looked at the syntax, I was like it uses require.

[00:00:24] Wait, isn't that RequireJs? No, it's not. RequireJs is actually AMD. But CommonJS is what the Node folks decided to use as their module loader because they had to. Because if you think about it, when you run JavaScripts on the client, how do we tell other JavaScript about other JavaScript?

[00:00:42] How do we associate JavaScript's files together in the client? Script tags, right? So you have a html file, you have script tags. There's no html file, there's no DOM on Node. So there needs to be way of associating these JavaScript files together, these modules, so they needed a module loader, so they chose CommonJS.

[00:01:01] Which in my opinion was a really good choice. There are some differences between CommonJS and AMD. And now the new ES2015 module, which is completely different than all of them. But CommonJs was the one that they chose a couple years ago, when they made Node, and it's a really good choice.

[00:01:17] So using require ( ) we get access to built in and third party npm modules and of course the modules that we make. So here's a little code snippet of how that actually works. So if we were inside of a Node file, and I'll show you in a minute, just do it from the terminal, this is how we would get access to a build in Node module.

[00:01:37] We would just say, var, whatever you want to call it, = and you use the require function, and pass in the name of that module. In this specific example, the path module is a module that's built into Node. And if we get a little more fine detail, we know that this is either a built in to Node module or a module that we downloaded.

[00:01:57] And that is because we didn't have to prefix it with a ./ and if you don't prefix your names in the require, what happens is Node is automatically gonna assume that it's either a built in Node module or it's belonging in the Node module's folder. If you put a ./ in front of it, it's going to like, this is a module that you made somewhere in this directory let me go find it.

[00:02:19] And I'll show you what that looks like in a minute. So this is an example of a built in Node module that we did not have to download, it's already baked into Node, path. Here's an example of one that we downloaded, so this is like we npm installed lodash, which is an alternative to underscore.

[00:02:34] If you've ever used Underscore.js, it's the same thing. All right, this is how we require it, it's the same thing. We just require the name of the package, which is lodash. And we don't have to put a ./ in front of it because it's installed in a Node module's folder.

[00:02:48] So we don't have to do that. Anything that's in a Node module's folder, you don't have to put a ./ in front of it. But for this one, which is the module that we created in a separate file, we have to put the ./ in front of it.

[00:03:01] Otherwise, Node is gonna assume that it's in the Node module's folder, or that it's baked in internally, which is not the case. Just won't be able to find it if we didn't do this. And the path that you place in here is relative to the file that you're acquiring from.

[00:03:19]
>> Speaker 1: Also note that I didn't have to put .js, I didn't have to put an extension name on any of these files. It just assumes that it's JavaScript by default. So you don't have to put .js, it just knows. I mean, what else would it be? It might be JSON or something else, but by default it's gonna be js, so you don't have to put the extension.

[00:03:35] If you do put the extension, it's not gonna break. But you don't have to. Any questions on that stuff?
>> Speaker 1: Okay, so above are some examples, how to access Node modules using CommonJS. So this is how we would access them. Here are some examples of how we would expose them, if we were to create them.

[00:03:58] So these are two different files, but here's the one file. So we would use the, oops, should be exports not export, forgot about the s there. So we would use the exports keyword here, which would allow us to expose. Yes?
>> Speaker 2: There's this question on how does Node know where the Node module's folder is?

[00:04:20]
>> Speaker 1: The Node module's folder will always be on the root of the application next to npm. And if it's not there, it'll recursively look for it.
>> Speaker 2: And I guess follow up to that is, yeah, how does Node know where the project root is?
>> Speaker 1: How does the Node know where the, good question.

[00:04:42] So I'll get to that I have an example for that, yeah.
>> Speaker 1: So yeah, we'll use the exports which just came out of nowhere. So in Node there does exist this type of thing like globals, kind of like in the client where you have everything attached to the window or everything's on top of global space.

[00:05:03] There does exist some concept of that Node and that's because, in Node, actually what's happening is when you make a file in Node, it actually wraps in an iffy. So it doesn't matter what file you do, this is what Node does when it executes your file. So your actual code would be in between here and then what Node does is it gives you some globals something like module.

[00:05:30] It also gives you exports, gives you dirname, which is the directory name that it's in, all that stuff like that. So now you have access to those variables inside your code which will be in here. So every file is wrapped in one of these, it's held enclosure. So if you want to to see what that looks like, it's literally in the Node source code you can go check it out it's exactly how it is.

[00:05:55] There's a couple of other things in here. Yeah, there's a few other things in here. So that's how we get access to exports and module.exports and dirname and all that global stuff because it's attached that way. So, using the exports keyword, we're able to export individual things, just attach it to the exports object and then now we can require it.

[00:06:16] Should be exports, not export. And then, alternatively, we can also do module.exports which is just like, I'm just gonna expose this one module here. Exports is an object that we can attach different pieces of our code to. Module.exports is the entire object, and we're defining it differently. So it's kind of the same thing, whereas exports we're like, let's put a setup function here and enable function here, a ready function here.

[00:06:46] That's the same thing if we said module.exports, which is an object and then putting all these methods on it. So you can use whichever syntax you want, they're both trying to do the same thing.
>> Speaker 1: Any questions on that?
>> Speaker 1: Okay, so using exports objects on a module, we can expose our code to be require later.

[00:07:17]
>> Speaker 2: Did pop a question here? Do you think Node will support ES6 style modules in addition or replacing CommonJS style modules.
>> Speaker 1: That's a good question. I don't know, well I mean they're using V8 internally. So when V8 keeps getting updated, so it's actually a really debatable question because Node and io.js is this big divergence between Node and a different version of Node.

[00:07:42] A group of people Node and made something called io.js because they were tired of Node not being updated readily and not keeping up with security updates with V8. So io.js made it their practice to keep everything new and start implementing ES2015 features. Then now, there's news of io.js being merged back into Node, some of those features are coming along.

[00:08:03] Actually in Node version 12, if you use strict, you actually get some ES2015 features, but not all of them. So, because of that, I would say that yeah, they probably will support the ES2015 modules because they're already showing support for the ES2015 features that exist today. So when that's gonna happen?

[00:08:21] Not sure. They might have a roadmap for it, but yeah, they definitely will get there if they continue to rely on V8.
>> Speaker 2: A couple more popping in here. What are the pros and cons of module.exports versus exports?
>> Speaker 1: Yep, so module.exports, once you do that you cannot export anything else.

[00:08:41] So once you do a module that exports, you cannot in that same file do exports.this, that's it. Module.exports is the only thing that's going to be exported. Using exports just means that you're, when you require in the next file, let's say we exported a lot of stuff on this module, then this variable in my module will always be an object because exports is an object.

[00:09:08] So we said exports.setup, exports.enable, exports.ready, and then we just require this file config.js this my module would be an object that has a .setup property, .enable property, .ready property. Whereas if we use like module.exports we can set this file to be whatever we want. So we don't have to put an object here we can just say, well let's just put the number 3, and then when we require it this value will be 3.

[00:09:36] So using exports, there'll always be an export when you require it. Using module.exports, it'll be whatever you export on module.exports.
>> Speaker 2: Can you assign a single value to module.exports?
>> Speaker 1: Yep, you can put any value you want. Except you can't say, module.exports = exports. Or you can't say module.exports = module.

[00:10:13] Well, I guess you could. You would probably have some side effects. But, yeah, you could put whatever you want there.