This course has been updated! We now recommend you take the Introduction to Node.js, v2 course.
Transcript from the "Importing Node Modules" Lesson
[00:00:17] We talked about a little bit. And this function takes a relative path to the module that you want to consume and synchronously loads it by returning whatever the target module exported. So we talked about exporting. So whatever you export, when you require that module, if it finds it and it's the right name, it'll require, well synchronously return whatever that module, the target module is exporting.
[00:00:44] So we're gonna do that in practice, so let's do that. So I have code.js here. I'll make a new file. I'm gonna make a folder real quick so it doesn't get all sloppy.
>> Speaker 1: Okay, so we'll make a file here, and we'll call it.
>> Speaker 1: Library, or lib.js.
[00:01:12] And we'll just call this other one app.js. Look at all this spam, look at spam just popping up. I don't wanna update, get out of here. Okay, so we'll make this one app.js.
>> Speaker 1: Oops. App.js, there we go, okay. Why is it not doing that? I'm gonna delete that one, there we go.
[00:01:37] All right, so now that we have those two files. So let's say we have a function called Name. [SOUND] It's literally not gonna do anything. It's not important that it does anything right now. Or actually, I'll just log a name so we can see something.
>> Speaker 1: Cool, right?
[00:01:55] So we got that. I'm gonna export this. And it's my sole export, so I'm not gonna put a module. I'm gonna say Name, right? And in fact, because it is my only one and I'm not using it anywhere, I could just do this. I'm not referencing it anywhere.
[00:02:07] I can just say that if I don't want it to be named. So I could say module.exports equals that function, because I'm not using this anywhere else, so why even say a new variable? So I'm doing that. And then for app I'm going to open this up side by side.
[00:02:23] We'll go to app and what I'll do is, because this is not a named export. It's just a function with no name I can call the variable whatever I want over here. So I'll just call it, lib, or Name function name function equals and I use require, remember requires a function that takes a relative path.
[00:02:46] So because these two functions are siblings are literally right next to each other, a relative path would be dot forward Slash and then the name of the file, which is lib. So a couple of things that's happening here. One, is this dot forward slash. You might be thinking, well if its irrelative I should just be able to do this.
[00:03:06] You're not going to do that. We are going to talk about why you can't do that in a minute but, you cannot do that. If you are going to be requiring about a module that you created in your app, you always have to put a dot, always have to put a dot.
[00:03:24] And what comes next is dependent on where it is. Because it's right next to it as a sibling, we can just do that. But if it was up a directory, right? We would do this. And we can keep going up, right? But because we're a sibling, all we have to do is that.
[00:03:36] But you have to put a dot if it's a module that you created in this same repo. We are gonna talk about other different types of models that you could require. There is two other different types of modules other than this one that you can require. But for the ones that you create, you have to put that dot there.
>> Speaker 2: Ones that are part of the app that you are working on.
>> Speaker 1: Part of the app that you are working on, that you made. Like you literally made this file, it's a file that you can go to. You didn't download it, it's not internal it's something that you made, a code that you made In this same repo, you have to put the dot there.
[00:04:25] So do I tilde-XP both files?
>> Speaker 1: No, right? So the sweet thing about modules is that they actually create a tree for you, right? So if you think about it, there's always gonna be one point, if you're building a standard app. Some people have advanced apps, that have three or four different apps in them, they all have different entry points.
[00:04:47] But in most cases, you're gonna build a app that has a one entry point, and that's gonna be the root of your application. And in this case, the root of our application is app.js, so what node's gonna do it's gonna start here, and very much like the browser, where it sees like script tags and link tags, and it'll start firing off requests to go get them, it's gonna do the same thing.
[00:05:03] Node's gonna see that you try to require lib. So, before I can run function on line three, it' going to go resolve this first and then it is going to put it here, right? So, that creates a tree and if name function had a require inside of it, it will resolve those dependencies.
[00:05:18] So, its a dependency tree, where it goes all the way down and resolves everything before it executes. Does that make sense to everybody? So that way you'll always have one entry point to an application. You'll almost never have two entry points. If you do, those are two different apps.
[00:05:31] Even if they use the same files, that's very complicated. It sounds crazy, but you could have two different apps that use the same files in the directory somewhere, but they're two different apps because they have two different starting points. It's very complicated. It's very advanced, mostly browser related stuff, when you do like code splitting, and libraries and stuff like that.
[00:05:51] But mostly for Node apps, probably not, so.
>> Speaker 2: This change thing for me, is it of constant there?
>> Speaker 1: We can, constant's just an ES6 thing, we can use var, it's totally fine.
>> Speaker 2: Does it really work with constant though?
>> Speaker 1: Yeah, it will work with const, for sure right, cuz Const just doesn't know about this value.
[00:06:08] Const is just saying you can't change the reference.
>> Speaker 2: Sometimes it's like the compile type the way it-
>> Speaker 1: Right. Yeah, it's fine. Const is fine because ever since node 6, they supported const and let so that's good on that side and as far as it compiling it's totally fine.
[00:06:27] This value is never going to change. It's synchronous, it's not going to look like it. Yeah, it's just it's just not going to change. So you're good. So let's run this. So that means we have to start about entry file. If we don't like friends, we just started at lib.js ran this like what do you think is going to happen if I execute this file right now what you think is going to happen?
[00:06:50] Here's the file lib.js. What if I'd is executed that far right now? Yeah, absolutely nothing is gonna happen. It's literally not doing anything. I don't get an output, nothing happens. It's like cool, you exported a module, done. And that's what [LAUGH], right? But if I ran app.js, snap, it logged the name from the function that I required from lib.js, right?
[00:07:14] And so I required lib.js, which exports a function. And then I just called that function. So now, this name function is a reference, it's a direct reference to this, all right? So let's do another example. Let me do some named exports here. We're using named exports like, let's say, value1.
[00:07:36] Users is an array of user ID's. Then, we'll call this an action.
>> Speaker 1: So now we've got that. Actually, I still don't have to change the name here. Technically, the name will still work, but it's kind of confusing now because this is no longer a function. It's like an object, right?
[00:08:02] This is an object that's going to export it, so for the sake of better code, I should just give it a different name, and I'm just gonna call it the name of the file lib. I'm just gonna call it lib. And now, this is irrelevant. So now, I can do things.
[00:08:15] I can just say, lib., and you can see, even VS code is telling me all the things I can do because it has type sense built into it. It's like, you got an action function, you got user ID's, and you got value. So if I just call action, and I ran this file, you'll see I logged out action from this, right?
[00:08:35] So I literally exported this entire object and I named it lib. And it's the same object as here. It's the exact same one. So if you use ES6 you can do some destructuring here, right? So I could just say give me the action, give me the value, give me the user IDs.
[00:08:54] And that way you can shortcut this if you want.
>> Speaker 1: All right, you might see that. So now all I have to do is just do action but it's still the same thing. This is just destructuring with ES6 and it's still gonna work the same way.
>> Speaker 1: So that's the difference between exporting like names and then requiring it, versus exporting just like a single one.
[00:09:16] So that's how they work, so you can see, if I export something, I can require. If I don't export something like,
>> Speaker 1: Private, I can't get it in here. Like I can't say, yeah, give me the private like, it's just not going to work. I mean, even if I just try to do something with this.
[00:09:42] Let's see what happens. Yeah, I spell console wrong. That will break it. There we go. Now, it says it is undefined. All right? It didn't error out, because you can, there's nothing stopping you from destructing a variable that doesn't exist. It's just, the value would be undefined. So it tried to look for something called private, on this object that was imported.
[00:10:05] There's nothing called private here, cuz I never exported it, so it's just undefined.
>> Speaker 1: Yes
>> Speaker 3: So if we import more than one module and then both of them have action, for example, what happens to it? Is there things like name spaces?
>> Speaker 1: That's gonna be a style decision, that's gonna be up to you.
[00:10:28] Like if I had another module down here and it was called action, like this, require, and it had another file called action, or whatever. Yeah, now, you've got a problem, right? Because so then it will be up to users. Okay, cool, do I want to de-structure this, or do I go back to having this say lib, and now I avoided that collision?
[00:10:47] Or are you gonna use some fancy EX stuff in here and be like, I want to actually Name that something else. Or you can use ES6 here to name it something else, if you want to. So that's a style thing, but Node's not gonna protect you from that.
[00:11:13] So it would break there and be like you can't do that, identify action's already been declared. So you couldn't do that. If I put a let here and I got rid of this, now you have a sneaky bug. Right, actually it's still gonna throw an error cuz it's not gonna find action.
[00:11:31] So it cannot find the module action. But if that did exist then, yeah, you would expect this to be here, but then this wouldn't be and then you would have problems. So, yeah, that's gonna be a style thing. And most of the time I use linters for that.
[00:11:59] That's why people use things like TypeScript and stuff like that. Cool. So one last thing I wanted to mention here is what happens if you try to require a module, if it doesn't exist, right? So you still got this error right here. So if you try to require a module, you'll get this internal/modules/, you'll see it's js, that's short for common JS, loader.
[00:12:18] This is some internal thing, this is not your code. This is some internal Node thing. And it's like, we threw an error, because we cannot find module here, that doesn't exist. Because I never created that file. So it doesn't exist. You're going to see this a lot. Yes.
>> Speaker 4: So CommonJS doesn't have a concept of import foo as bar? Like ES Modules does?
>> Speaker 1: No. [LAUGH] Yeah, that's why ES Modules is really legit. Yeah, you can't do that with commonJS, but there's nothing stopping you from. The thing about it was like, there was no name on this export.
[00:12:54] I mean, yeah, it's an object with properties on it. But there's literally nothing stopping me from calling this whatever I want. I can do that because its not named. Because technically there aren't really names, they're just objects. So, yeah, it's very loose, you can do whatever you want.
[00:13:07] But yeah, because ES modules is like strict about named exports and named imports, you have to do that. Where as CommonJS is like, I don't know, just whatever you want, so yeah, that doesn't exist.
>> Speaker 4: So, rather than require Like React uses import statements.
>> Speaker 1: Yes, that's ES modules.
>> Speaker 4: That's ES module. So you can't do it on this?
>> Speaker 1: Not by default. The others are trans-power. I will talk about that.
>> Speaker 4: Soon.
>> Speaker 1: Yep.
>> Speaker 4: Soon, though?
>> Speaker 1: Soon, yeah, soon, yeah, they're working on it soon.