Core Concepts of Webpack
Front-end developers have so many tools to make sense of these days, npm, yarn, bower, grunt, gulp, the list goes on. What happened to the good old days when you could just include a <script> tag of jQuery hosted from some CDN out on the inter web, and just jump right into adding behavior to your HTML to get your app off the ground? Well, you can technically still do that, but it’s not advised if you're writing enterprise software. Today, I’m going to talk about the core concepts of Webpack, and why you should consider using it on your next project.
Ok, what’s a module bundler? Before I answer that question let me take you through a scenario of building out a simple web app that requires several other code libraries, like jQuery and Handlebars, to illustrate this point. Lets take a look at “traditional” web app written with jQuery over at todomvc.com. By the way, this is a great website if you’re wanting to test out a new Frontend framework just to see how things works.
Scroll down to the non-framework section and click on jQuery. We aren’t going to get into how this app was built, we want to look specifically at the source code. Click on Source up here at the top left to head over to their GitHub project. Lets take a look at the index.html file.
You’ll notice at the top of the HTML file they are including 3 CSS files
Some of these files come from an external library, and a couple of them are custom, specific to just this app, hence the name app.css and app.js. All of these files are called dependencies.
Building your app this way is perfectly fine, and as you can see on the todomvc.com website, the app works perfectly fine. But this process isn’t optimal for enterprise development. You’ll eventually run into issues if you develop large apps this way.
This is where webpack enters the picture. Using a tool like webpack helps you overcome issues like what I just mentioned when building large apps, and it brings with it a whole other slew of efficiencies that you’ll gain, and benefit from, like Uglifying your JS, compiling your SASS, bundling libraries that never change into separate DLL’s, dynamically linked libraries, and so on. But I’ve digress, let me get back to the original question, what is a bundle?
If we go back to the webpack docs, it gives us a hint: webpack recursively builds a dependency graph and packages them into a bundle.
Essentially, what webpack does is take an entry file, for example the app.js file of your app, it reads that file and finds all of the dependencies listed in that file. Webpack will interpret the
require statements in this main entry file, find all of the files that is imported or required, and package them up into one output file, called a bundle, that you would include in your index.html file.
Let’s convert this ToDoMVC app to use webpack and see all four of these concepts in action.
So here we are again on TodoMVC.com. We're going convert this jQuery version of the app. And so let's go grab the source code. So if you're following along at home, you can clone this repository, which I have done already here. We're looking at just the jQuery directory here. You're likely going to have to clone the root of this repository and then go straight into the jQuery directory that we're in.
But you can see here, the index and HTML file, with the three CSS files up top and the five JS files down at the bottom. Or here in my text editor were the three up top and the five at the bottom.
And so to do this webpack conversion, I've actually already made the webpack conversion. I've got it on a different branch, just so I can quickly show you how this is done. So I'm going to check out that branch. It's called the webpack conversion.
And so if we open up app.js, we basically included all of our dependencies in this one file, in this entry file app.js. And so you can see here, jQuery Handlebars which used to be declared globally in the index.html file down here is now declared specifically in this app.js file. It's no longer in the global name space. It's only available only within this app.js file.
And we're using the require syntax, which that's what webpack actually looks at. It looks at require and import statements to be able to discern what's in the dependency tree that it will create.
And so you can see we're requiring Handlebars, the minified version of it. We're requiring the base-js file. We're requiring jQuery. We're requiring the router instance from the director. And then we're also requiring those three CSS files that we had in the index.html file.
And then the one file that does all the magic is this webpack.config.js. And this is what actually holds the four concepts that I was talking about earlier, and so we talked about an entry file, we talked an output file, and then we talked about loaders, and we talked about plugins. And so essentially, what webpack will do when we actually run the webpack command, is it's going to look for our entry file, which is defined as js/app.js and it's going to output a bundle.js in our /dist directory.
And so if I come back to our code editor and go into js/app.js, you can see here are the dependencies that we've declared in this app.js file. And if I come down here and I run webpack in terminal, what it will do is it will create a /dist directory.
And so if we want to see this actually running in the browser, we can run the webpack dev server. And that'll create a server at localhost 8000 or 8080. And let's go here and see what that looks like.
And so here is our Todos app. It works just as it did before. And I can mark these as complete. I can see what's active, what's completed. I can clear completed ... check this off, clear completed. And so the app works just as it did before, except that if we look at our HTML here, the only thing that is getting included is this one bundle.js file. All the CSS, you can see we don't have a link tag up here at the top. It's all bundled within this one bundle.js file.
Before I show the different plugins, let me just kind of explain what's going on here in this webpack config file. And so we already talked about the entry file, which it looks at this app.js file within the js directory. And then it outputs a bundle.js file in the /dist directory.
Where does this index.html file come from? Well, this is where plugins come into play. And so we have a plugin down here called The HTML Webpack plugin. And essentially what this does is this creates an index.html file for you. And you can pass it options, saying which template you want to use for that index.html. If you wanted to use the default markup the plugin gives you, you could just do this and not pass it any options, and it will create a default index.html file and automatically insert the bundle that you're creating into that. But for our specific case, we actually want to use a template index.html because that has the actual templates needed to run this, to do application. And so in webpack config, we're basically saying, "Create an index.html file for us, and use this template for the index.html file."
So if we're to look at what this looks like through the console, so now I'm going to inspect this application and I go into my head tag up here. You can see there are three style tags of all of the CSS that we're importing. And so you can see the three style tags correspond to the three files that we've specified here: the base.css, index and app.css.
And so we go back to this. The app.css was very minimal, so you can see that in fact, the CSS where app.css is being injected into the page with this style tag.
So let's go back to the webpack config file. Okay, and so again, before we move on, just to review, we have the entry, which is the file that we're entering the application on to find all the dependencies. With the output, we're defining what file we want to output all the dependencies in as a bundle, so we're saying, "Bundle that JS and put it in the dist directory." In our file system, we're specifying loaders, how we want to handle files that are imported or required in our application when it matches this regular expression. We want it to go through a CSS loader, and then a style loader, and then we're specifying a plugin. We basically want to create an index.html file, and use the template index.html.
I'm going to check out the webpack Extract Text plugin branch. And so now if we look at this webpack config file again, so now we were requiring another plugin called the Extract Text plugin. And you can see that we've changed this loader a little bit, and we also added a new plugin to the plugins array called the Extract Text plugin. And we passed it a parameter: styles.css which is the file name that we want to output when the CSS is created.
And so that's the only thing that we've changed here. It's just this one plugin. And so let's go back to our editor and run webpack. And so now if we go into where dist directory here, you're going to see that it created this one file, styles.css. So it took all three of those files and basically created one styles.css file for you. And if we go into our index.html file, you can now see up here in the head tag, there is now a link tag referring to this styles.css file.
And what's neat about this is behind the scenes, this HTML webpack plugin is actually working with this Extract Text plugin and the HTML webpack plugin is inserting the link tag for us for the actual styles.
Let's take a look at what this looks like in the browser. And so it's from the Dev Server. All right. And so now, we're back in the Dev Server. Everything should work as it was before. And so here is all of our tasks. Let's mark one complete. So we have one active, one complete. And if we go into the console and open up the head tag, you can now see that it is linking to that style.css file.
We update the channel regularly with the latest client work and special event videos.