Splitting Into Files0:03
I dunno about you, but I am tired of scrolling through this single file because it makes it difficult to find the things that we need to work with. And it would help if we would get rid of all of the comments, but really we don't have a whole lot of comments. So what I want to do is start to break this file up into individual files, because to me that makes perfect sense.
to break this file up into individual files, because to me that makes perfect sense. We can create a file that contains the Game class, then we can create another file that contains the UI object and then we could leave this episode 29 file. As you know, the main application file, this makes it a whole lot easier to navigate the code, to find the things that we want to work with just like it would in any application, regardless of the language or the platform.
Extracting Game Class0:44
with just like it would in any application, regardless of the language or the platform. So the easiest thing to start with, I think is the Game class. So let's scroll forever until we find the Game class and let's just cut that out because I want to create a new file, we'll call it game.js, and we'll just drop that class in there. Now of course this is inside of a new file and we need to reference that file inside of our index.
Now of course this is inside of a new file and we need to reference that file inside of our index. So let's just do that. We will add a script element for the game file and then everything else is inside of episode 29. And even though we have drastically changed the structure of our code, it's still going to work because the game class is still defined in the global scope is still available for the code inside of our main application file to use.
Extracting UI Object1:29
is still available for the code inside of our main application file to use. The next thing is this UI object. You know where we create that? Let's just cut that out. Let's create a new file, we'll call it ui.js, and we'll paste that in. And you know, again, we need to add a reference to that file. So let's just do that by adding another script element. But once again, you know,
So let's just do that by adding another script element. But once again, you know, we have drastically changed things, but still the game classes in the global scope, the UI object is in the global scope. So everything is still going to work. In fact, if we look in the browser, yes, we can play the game, we can submit our guesses. Everything still works exactly as it did before. And this is a marked improvement.
Everything still works exactly as it did before. And this is a marked improvement because now those individual pieces are in their own files. It makes it easier to find the things that we want to work with without having to scroll for days. But this could be better because everything is still loaded into the global scope. And you know, at one point in time that was just the reality of things. Something had to be in the global scope in order to be used.
Introducing JavaScript Modules2:31
that was just the reality of things. Something had to be in the global scope in order to be used. But now that's not the case. Now we can create what are called modules and well, they are exactly what they sound like they are files first and foremost. But the code that we define inside of those files stay inside of those files. They are not in the global scope. And in fact, we can't really use anything outside
They are not in the global scope. And in fact, we can't really use anything outside of a module unless if we export things. So we create a module, we export the things that we want to work with, and that gives us complete and total control as to how our code is going to be used. So let's start by turning our JavaScript files into modules. And all we have to do is set type equal to module for the script element. So we want that on each one of these elements.
for the script element. So we want that on each one of these elements. And voila, we have three modules. We've also broken our application because you know, once again we have JavaScript code, but now that code is contained inside of modules and the objects, the variables, the classes, the functions that we define inside of those modules, stay inside of those modules unless if we explicitly export them and we can export things in two different ways.
Exporting and Importing Game3:44
of those modules unless if we explicitly export them and we can export things in two different ways. For the class Game, we are going to use what's called a default export. A default export is essentially the main thing of the module that we want to export. In this case, well, we only have one thing that we want to export, but it makes sense to make this the default so that now we are exporting the Game. We can actually import that wherever we need to use that.
that now we are exporting the Game. We can actually import that wherever we need to use that. Now, right now we only use the Game class, uh, for the submit event listener, yes, right there. But you know, we've had this game variable that it's been global. I, I want to get away from that. So we're not going to use that here. We we, we'll get to that for a moment. Instead we're going to use it inside of the UI module,
We we, we'll get to that for a moment. Instead, we're going to use it inside of the UI module, but we want to import the Game class from the game.js file. Now, whenever we import a default item, we use the import keyword followed by whatever identifier that we want to use. So one of the really cool things about a default export is that we can give it to whatever name that we want even though we have exported a class Game.
that we can give it to whatever name that we want even though we have exported a class Game. You know, right here, whenever we import it, we could call it FU or we can call it your mom, it doesn't matter. We can call it whatever we want. But for the sake of, you know, not being confusing, I'm just going to use Game. And so by exporting the Game class and importing it here, we can now use the Game constructor.
And so by exporting the Game class and importing it here, we can now use the Game constructor to create a new Game object. But now that our UI file is a module, that means that we can change the structure of the code. You know, because we have this UI constant and it is assigned an object right here, but it is the result of calling an immediately invoked function. We don't have to do that inside of a module.
of calling an immediately invoked function. We don't have to do that inside of a module because a module's code is contained inside of that code. So it has its own level of scope. So what we can do then is get rid of that immediately invoked function that makes our codes much more simple because first of all, we don't have an immediately invoked function, but also we don't have any nested indentations. So that right here, this return statements, we can say cons
but also we don't have any nested indentations. So that right here, this return statements, we can say const UI equals, and then we have our UI object, but this is something that we want to export and we could say that this is the main thing that we want to export from the file. I mean there is an argument for that, but instead I'm going to export this as a named item. Now we can export multiple named items from a module, which is something that we will look at here in a moment.
Now we can export multiple named items from a module, which is something that we will look at here in a moment. But we can export this, which means that we will need to import this inside of our main file. And we do that with slightly different syntax. In fact, it's going to look a lot like a destructuring statement, except that instead of using an equal sign, we're using from, so we import and then we specify the named items that we want to import, which in this case is just UI from ui.js.
Moving Event Setup to UI6:52
and then we specify the named items that we want to import, which in this case is just UI from UI.js. But I actually want to import more things here because I think the UI should be responsible for setting up all of the event listeners that have to do with DOM objects. So what I want to do is also export a function and we will just call it knit, so that we will call this a knit function, which will then set up all of the event listeners,
that we will call this a knit function, which will then set up all of the event listeners, which means we need to go back to our main file here and we need to grab all of the event listeners for the built in events, which it looks like it's just three of them. So we will cut them out, we will paste them inside of this knit function. But you know, this is also where we have created the game object.
But you know, this is also where we have created the game object. This is also where we define this game variable. So what we can do then is go up to the top of the file and we can create our game object here. And this is going to stay within the module. It's not going to be exported, so it's not going to be publicly available. And that's really what we want. But this is going to cause an issue.
And that's really what we want. But this is going to cause an issue because in one of our events we use the game objects right here for the SubmitGuess event. So what we could do then is provide the game with the detail of this event, which means that we need to change that. But where do we dispatch that? Right here? That's where we do that. So here's where we build the detail, we have the guests, we also want
That's where we do that. So here's where we build the detail, we have the guests, we also want to include the game and that's going to make that work. So now inside of our main file, not only do we want to import the ui, but we want to import the init function so that we can call init to set up all of the DOM event listeners. We are importing the UI so that we can use that within our own event listeners.
We are importing the UI so that we can use that within our own event listeners. And if we take a look in the browser, everything is going to work like it did before. But the great thing is now we are being selective as to what we make publicly available to the rest of the application. So modules drastically change the way that we write applications. And the great thing is that you can use modules anywhere,
that we write applications. And the great thing is that you can use modules anywhere, you can use them in the browser, and they are extremely common with build tools and frameworks like Vue, React, even Alpine. So I highly recommend that you start using modules for well everything. Not only is it a great way to organize your code, but the features that modules have are fantastic. Each module has its own level of scope so
but the features that modules have are fantastic. Each module has its own level of scope so that everything defined within a module stays inside of that module. Unless if you export it, and if you have a module that just has a main thing that you want to export, you can export it as the default of that module. But if you have other modules where you need to export multiple things, you can export them individually
But if you have other modules where you need to export multiple things, you can export them individually as named exports. I don't know why it took years to get this feature, but now that we have it, be sure to use it.
