Check out a free preview of the full Introduction to Node.js course:
The "Creating Node Modules" Lesson is part of the full, Introduction to Node.js course featured in this preview video. Here's what you'd learn in this lesson:

Scott demonstrates a pattern for Commonjs exports while explaining the difference between default and named exports, coaches on the importance of explicit exports, and advises against using the exports global.

Get Unlimited Access Now

Transcript from the "Creating Node Modules" Lesson

[00:00:00]
>> Scott Moss: Now we're gonna talk about creating modules. It's just regular code, you just have to export it. So I talked again about how every piece of code you write is already a module, and I logged it out. Like I said, all your Node.js code, they're already modules. It's literally already a module, you don't have to do anything.

[00:00:16] The only thing you've gotta think about is all right, if I have all this code, what do I wanna share? How do I wanna share it? You don't decide who gets it, you don't know who is gonna require you, but you can decide what you export and like I only want this, I got all this this ones the only want that's important.

[00:00:33] And that's for sharing, but then you get into testing and most time, you got to export everything for testing. And it get's really crazy, but yeah it's up to you, as the author of that module to decide, what is gonna be available for other modules? And yeah, it's basically what I said here.

[00:00:49] So you do this with the module global object provided you by Nodejs runtime. So if we walk through that a little bit, that's basically like this, if I had a function called add that took in num1, or num and num2, and I wanted this to be available, what I would do is I would use the module global right here.

[00:01:08] And then there's a method on there called exports. And you can just set it equal to an object like this if you want. Or you could set it equal to any value, really. So if I said module.exports add, now whenever somebody requires code.js the value that requires going to return is gonna be whatever I exported here.

[00:01:28] So that means the value of whatever requires return in this case is will be a function called add, right? I can return whatever I want here. I can say return add, and then I got some other thing here, that's a function. And then I got some value, that's a 1.

[00:01:44] All that's gonna be returned, right? So if I were to require this in another file, I would have some module.add, .thing, and .value. I would have all three of those, all right, cuz that's where I exported it. And then if I don't want to export something, like notPublic, I just don't export it.

[00:02:05] It's sitting here, but I didn't export it. So nobody can require it. Nobody can import this, it's just here to help me write this code in this file but nobody else can ever know about this. It's a secret. It's private. So that's how you make things private. You have to be explicit about what you export.

[00:02:22] That's it. That's basically it. There are other ways to export in Commonjs. You might have noticed that there's a global export object. Don't use that. Just use module.exports. Just do not use the exports thing. There was like a huge war on the Internet about, I don't know, 2015 about this.

[00:02:45] Just don't use exports. Just use module.exports. It's way more explicit. It's a lot easier and there are different patterns you could use to expose modules. The one that I'm showing you now, I think is called the revealing module pattern, which is basically my pattern of choice, because what it allows me to do, so I can create my functions with all my code above.

[00:03:08] And then I can export it at the bottom. This allows me to do two things. It allows me to separate my code from the exporting, and it allows me to reference other code by its name. Whereas if you did it the other way, like for instance if I didn't do it this way and I was just like I'm just gonna embed all of this in here like this.

[00:03:27] What if I want to reference thing inside of the add function? How do I do that because it's part of this object? I don't really have a reference to it. Whereas if I declared it all in the variables above at the top, then now I can just, they can all reference each other, I can call add in here if I want to, cuz it's just code, and then it's still export at the bottom.

[00:03:44] So that's the pattern that I choose, when you use something like ES6, it's a little different, ES6 like solves all this, and I'm not really gonna talk about it. But yeah ES6 is a little different, but for CommonJS, this is the pattern that I choose, but there's other patterns.

[00:03:57] You might see people do things different ways depending on how much code is in their file, what's being exported, all those different things. But my recommendation is always export an object if you are exporting more than one thing and put all the values as the keys. If you're just exporting one thing then just export the one thing, like that, without an object.

[00:04:18] That's it. So it's a named export versus a default export. This is what's called a default export. By default, you'll always get this value, cuz that's what's exported. Named exports are things that you wrap in an object with properties cuz the properties are the names so they're named.

[00:04:34] So many use names, for one, just export it by itself.
>> Speaker 2: If you add new properties on there and you just want to say make everything available and not explicitly call it out in that line six, is there a way to just say default out all the different methods or properties in this?

[00:04:54]
>> Scott Moss: No, there is no default way, you have to be explicit about exporting. There is no implicit way of, export everything here. You could write a system that does that. There's nothing stopping me from making an object up here, like my own thing, myModules. I mean, I would never do this, but myModules.

[00:05:20]
>> Scott Moss: And making them an object and putting all these on objects and it's looking over them and just everything here gets exported. There's nothing stopping you from doing that, but it just makes it really hard to look at. I wanna be able to just look at this code and be like, here's the logic.

[00:05:36] Here's the exports. Versus like here's the logic. Here's the logic to export it. And then here's the exports. So I think it's really cool to be explicit about exporting. And then once you get into build tools like Webpack, where they did like static analysis on some things. Being explicit about where you export is actually very helpful for performance reasons like tree shaking and stuff like that that helps reduce your bundle size.

[00:05:57] So you kinda really wanna be explicit about what you export because there's a lot of advanced tools that look at what you export at build time to follow the dependency tree to figure out what to bundle in your app and what not to bundle. So the explicitness is very good.

[00:06:10] And it's just really good as a developer to understand what dependencies are public and what are private. So I would definitely try to keep that as simple as possible and explicit as possible when it comes to exporting. Yes?
>> Speaker 3: Is it possible to have multiple module that exports statements?

[00:06:28]
>> Scott Moss: Good question. No, do not do that, cuz you would just overwrite the one before it. So if you did module.exports here, and these are module.exports here, the second one's gonna win, right? Cuz so don't do that. So module.exports, whatever you got export just put it all here.

[00:06:45] Don't write another one cuz you will have side effects. You'll be like well, I thought I was exporting this but in fact I was exporting something else so.
>> Speaker 4: You could do module.exports.add equals, right?
>> Scott Moss: Yes, you could that. You could do, for instance if you already have, if you already declared module.exports, like in this case and I wanted to add another property to it.

[00:07:09] exports.more, then, yeah I could do that. Cuz I just already have an exports object that I created up here, and I'm just adding properties to it.