
To my mother for her unconditional love and support during every moment of my life.
The very first question anyone should ask before using any tool is “WHY?” Why do I need it and what’s the benefit? If you have almost no idea about webpack, then big chance you are already asking these questions, for me, the situation was that the framework I used to work with decided to switch to webpack for the assets/JavaScript management, and as result I found myself struggling to understand how webpack works and wondering how to make the switch to adjust my code accordingly, if this sounds familiar to you, this book will help.
In the following introduction, we will discuss a little bit about why webpack and why you should even care about it. If you are looking for a quick answer, it should be this: your JavaScript development will be fun and much easier! Too good to be true?
I admit, I wasn’t a fan of webpack, and the reason was that I never took the necessary steps to learn it or understand it. In fact, I was taking the wrong approach, trying to copy snippets from here and there, or looking for quick answers on the internet to find out why my JavaScript compilation failed. Mostly I was stuck for long hours searching without moving ahead to what I was supposed to be doing. During that time, I started to notice other people complaining about webpack, asking how to install this or that, and why their preferred third-party libraries weren’t working anymore, especially in the world of web frameworks. It was a shared feeling, and to be honest learning another Javascript tool wasn’t a fun option, so I kept myself stuck until I changed my mind. That’s when I decided to figure things out for myself, which has led to a long journey with webpack, but if someone had handed me a book like this one back then, without any doubt, it would have saved a lot of time, frustration, and many hours of trial and error.
JavaScript is becoming more and more complex, and if you have a big project or app that will someday grow to a certain size, webpack will eventually save your day (we will see how over the upcoming chapters). One of the main things webpack will do for you is to compile your JavaScript to one file or more. For example, you can have two final scripts if you prefer to call one JS file in one page and a second one on another page.
Compiling your JavaScript into one file will prevent multiple server hits. Let’s imagine you are using many third-party libraries like jQuery, Tinymce, Bootstrap, Loadash, and so on.
The same principle applies to your own JavaScript files. Plus, you can add a hash string to your files name to bust cache and to reduce your site/app time load. Webpack has you covered.
Is this all that webpack will do for me? If you have ever used another build tool like gulp or Grunt , these tools were already doing this and doing it really well. All your JS code, for example, was concatenated and compiled into one file with a hash string as well (for caching) and life was far easier. However, have you ever thought about global variables and collision when concatenating multiple files into one and how they can cause a problem if you don’t use classes or wrap every file’s code with an Immediately Invoked Function Expression?
Well, with webpack, all these problems are solved out of the box for you, no need to reinvent the wheel. Also, one of the features I like most about webpack is how it will manage dependencies for you, and decide which file is necessary to load before another one, etc. I was faced with this situation in one of my projects and it was a huge pain to keep track of every file I needed to load, and which one depends on the other so that I can have them set in the right order. Maybe you have a small project right now and you don’t see the benefit. But as your JavaScript keeps growing, you will see how much benefit webpack will bring you, and you will be thankful that you made the right decision from the beginning.

Source: https://webpack.js.org/
This illustration shows how each of your files (on the left side) may have one or more dependencies (your files could be of different types like png, sass, js, jpg, cjs, etc.), and how webpack can take care of them and turn all this chaos into one or more organized file(s) to serve your assets from.
Webpack can do a lot more than what I have described so far, and we will see the many things you can do with this powerful tool through concrete examples in the following chapters.

Another thing to know (as previously mentioned) is that most web frameworks have adopted webpack recently for building and compiling JavaScript; and if you are using a framework like Symfony or Rails etc, you may find that webpack is already configured and ready to use out of the box. This alone is a huge win if you had to configure it by yourself, but in order to use it, I believe that you need to learn a little bit about the configuration and how loaders and plugins work. Once you learn that, you will be able to see a very clear picture of how things will be used when dealing with your JS inside your X or Y framework . So, whether you are using webpack with a framework or not, just trust me on this, and let’s learn the fundamentals that will make you a problem solver when it comes to using webpack.

has over a decade of experience in technology and web development. He studied programming and graduated as a software developer and then later became a system administrator. With a humble beginning, he started freelancing from home – providing services to people around the world. As an entrepreneur and project engineer, his work today is mainly focused on solving problems and making products that people love and use every day.

Holding a dozen Microsoft certifications and being awarded Microsoft MVP in C# for five years in a row starting in 2007, he has recently been educating himself on open source technologies such as Linux, networking, and the open web platform.
In this very first chapter, we will start by laying the foundation for our work by installing the tools we need in order to run webpack on our local machine. Then we will talk a little bit about the default configuration that webpack has introduced with version 4, called “zero config.” Next we will write our first “hello world” example, which as you might already know, is a mandatory standard when starting to learn anything new. Finally, we will talk very briefly about the webpack bundling command that we will use in order to build our final output files.
First of all, you need to have Node JS installed on your machine because webpack relies on it. If you don’t have Node installed, you can go to https://nodejs.org/en/download/ and follow the instructions based on your operating system.
This will create a file called package.json that will save references to our installed modules.
Via npm, the -y option is to answer yes to all prompted questions; it’s not that important for us at this stage, so we will just say yes to everything.
Note that whether you are in Linux, Mac, or Windows, the command is basically the same assuming you have NPM installed already on your machine, which is mostly the case if you followed the installation of Node JS correctly. The --save-dev option is to tell NPM that we need this just for our development purposes, meaning that these packages will be installed on our local machine only.

The package json file after installing webpack and webpack-cli
Notice that webpack and webpack-cli were added with each one’s version under the devDependencies. Also notice that a new folder called node_modules was created, as well as another file called package-lock.json .
So, on one hand, in addition to the basic generated properties (that we have seen above) like the name of project, version, author, etc., package.json lists all the packages that your project directly depends on, meaning that whenever you install a new package from your terminal, that package name and version number will be added to package.json. The package-lock.json, on the other hand, is the full representation of the dependency tree of your project, including the indirect dependencies. For example, when you install webpack, other packages that it depends on will get installed as well. Package-lock.json will also contain the specific version of each module, so that if someone took your project later and ran “npm install” on their machine, they will get the exact same versions you installed. That way there will be no breakdown on the application (i.e., due to a package that got updated and has some break changes).

The file “node_modules/.bin/webpack” responsible for running webpack command
The file “webpack” above (under “node_modules/.bin”) is where the “Webpack command” comes from, so every time we need to compile our JavaScript, we'll call this file from our terminal. However, there is a better way to do this (which we will see in the next section) by making an alias command that will call that file for us instead of specifying the path to it. With that in mind, it’s time to write some basic code and start exploring the power of webpack.
Configuration
Out of the box, webpack won't require you to use a configuration file. However, it will assume the entry point of your project is src/index and will output the result in dist/main.js minified and optimized for production.
What this means is that webpack expects you to create an entry file called index.js inside an src folder, and then it will create and output the result in dist/main.js for you, without the need to create the configuration file yourself or do anything else.

Our “webpack” folder tree after adding an “src” folder and index.js file
What we did here is to tell webpack to bundle our JS. If you wonder what a node_modules/.bin/webpack is, it’s just the path to our webpack command, which is basically a JavaScript file itself. There is a better way to call it for sure, and we will see this in a few moments.

Terminal output of running “node_modules/.bin/webpack” command
WARNING in configuration.
The ‘mode’ option has not been set, so webpack will fall back to ‘production’ for this value. Set 'mode' option to 'development' or ‘production’ to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more at https://webpack.js.org/configuration/mode/

main.js: the file generated by webpack under dist folder

Our “Hello webpack world” wrapped in its own module
If you noticed, our alert is at the very bottom, but you can see that there is a bunch of code that precedes it, which you don’t have to worry about or understand because it’s specific to webpack and how it makes the modules requiring functional.
The next step is to create an HTML file and make a link to our dist/main.js to see if everything works fine.

Your first “Hello world” alert
While this is a very basic example of our first working JavaScript file bundled by webpack, it’s time to congratulate yourself! You did it, and you should be proud as you just made your first step in the webpack world. But before we move to more serious things, let’s talk a little bit about the bundling command and how we can use it in a friendlier way to tell webpack to compile our JavaScript.
So whatever you name it, you should call it with its name, but you will find that most people generally use “build” or “dev” in the webpack world.
In this chapter, we introduced the necessary commands to install webpack on our machine. We have seen the package.json file and what it basically does. Then we created our first JavaScript file and bundled it with webpack. Also, we explored the entry file and how it should be named in order for webpack zero config to work correctly. Additionally, we have learned how to run webpack command from our terminal.
We have seen how to install webpack and use it in order to bundle our index.js file. Now it’s time to see how to add more code files (like in most real-world applications) and let webpack combine them into one file. Then we will learn how to customize our own configuration instead of relying on the default configuration provided by webpack.
As we already saw, we used webpack to bundle our JavaScript. However, in our example, we used one JavaScript file only. What about multiple (two, three, or more) files?
To be able to call sayHello function in index.js, it has to be exported from greetings.js and imported into it.
Webpack understands CommonJS and ES6 modules, and we will see both, starting with CommonJS.
In our package.json file, we have specified the “build” command under “scripts” option, so whenever we call “npm run build,” it will call the webpack bundling command for us.

Calling our sayHello function from greeting.js
Then open index.html again in your browser. It’s working, exactly like before!
We won’t talk about all the possibilities when it comes to ES6 because the main focus here is webpack, but it doesn’t hurt to revise some basics from time to time.
As we have seen, this is a pure JavaScript way to have a modular code and separate your code into multiple files. But again, at the end, webpack will use its own export/require system when bundling files, which will do all the magic for you.
What if we change ‘./greeting.js’ to ‘greeting.js’ ? What will happen?
Well, if you do so, webpack will assume you are looking for a node module, and it will go and search that name in node_modules folder, not in your source code folder, so make sure to always add a relative path to where your file is located when using the “import” statement.
But feel free to specify the extension explicitly in case it makes your code more readable.
So far, we learned that webpack requires us to have an src/index.js file to produce a dist/main.js compiled file. That’s the default webpack uses (also called “zero config”) as a ready-to-go configuration, but how we can change this if we want to? For example, we would like to change the output file “dist/main.js” to be “build/application.js” instead. Note that we want to change the folder name (“dist” to “build”) as well.
Do you have any idea what will happen? You guessed it … nothing different from the previous build! That’s because we just wrote what webpack already does for us by default: we specified an entry and ouput file name similar to what a default configuration would be.

Configuring webpack output folder and file to build/application.js
The path should be an absolute path, so make sure to change it where you want your file to be placed, but wait ... writing an absolute path like that is not efficient, as you may want to change your destination folder someday, which implies that you will be obligated to change your configuration file as well every time you do that. Fortunately there is a portable way to do it using a Node JS module called “path.”
Note that we used path.resolve(__dirname, "build") instead of our hard-coded absolute path because the “path” module will resolve the directory path for us (where our webpack.config.js is) and then will create a build folder at the same level.

Without “mode” option, the webpack output file is minified by default

The outputted code after setting mode to “development”
If you are curious to see the bundle file produced by webpack, you will find that there is some strange code on there, including some parts that are considered to be “bad practices,” such as the famous eval function! I know you might not like this but I’m here to assure you that this won’t happen in “production” mode. So during the development phase/mode, webpack doesn’t care about quality or performance etc; the goal is to deliver the result and to produce a code that just works!
Go to your browser, refresh, and see. Yes! Webpack is watching your files now, and any update you make is going to be bundled automatically for you.
In this chapter, we have seen how to write modules by creating a function in a file and calling it from another one. You can imagine yourself writing more complex code, that needs to be separated in more than 2 or 3 files, so imagine how that can be benefit to you, contrary to writing all your JavaScript in one big file that can be hard to maintain in the long run. We also created a custom configuration file for webpack, and then we changed the output file name and the output destination folder as well. We have set the “mode” option to “development,” which unlike the “production” mode results in non-minified code. And finally we used the option “watch” which surveys our code and bundles it whenever a change occurs.
Loaders and plugins are the heart of webpack. They make up the engine that empowers webpack to do the “magical” things for you, like reading and transforming files before passing them to webpack or influencing the output of your bundle by extending the compiler capability, etc. In this chapter, we will be exploring some of the most commonly used loaders and plugins. We will go through examples of how to transpile files from one format to another. We will see how to debug our JavaScript efficiently and how to handle images and optimize them as well as our bundle for fast loading. By the end of this chapter, you will have the necessary understanding of how to use both loaders and plugins in the simplest possible way.
Loaders, on one hand, tell webpack how to interpret, translate, and make transformations to your source code (for example, from CoffeeScript to vanilla JavaScript, or SASS to CSS). They are like tasks if you are familiar with any other build tool, and basically they preprocess files whenever you import them.
Plugins, on the other hand, can do anything that loaders cannot do. Webpack considers them the backbone of its core. And you will see that they are object-like, they can take arguments, and they can be instantiated as well in order to perform many things or adding functionalities to the compilation such as optimizing your bundle.
In this chapter, we will explore both loaders and plugins, so don’t worry too much about the definition. We will get familiar with these two notions when we see the examples. What you have to know, though, is that there are tons of loaders and plugins available (official and third-party ones), and our goal is not to cover them all. Instead we will be focusing on the understanding of how you can apply them and use them in your project, so that in the future if you need to have some additional functionality in your bundling process, you will be able to go and search by yourself, then apply that specific loader or plugin.
1 - installing the loader/plugin (using npm install)
2 - requiring it (usually we require plugins but not loaders)
3 - using it (documentation is our valuable friend here)
Again, don’t worry if this seems too general for now. Once we start to go through the examples, you will absorb the principle more clearly and get the full picture. So with that in mind, let’s start exploring our first loader.
Let’s assume we want to write ES6 (ECMAScript 6) in our code (which is still not 100% supported yet by all the browsers, especially the old ones, at least at the moment I am writing this). While webpack is able to recognize and translate the “import/export” to its own syntax, it won’t do anything for your (other) JavaScript code if you write it in the ES6 style. One of the solutions is to use Babel JS, which is a transpiler that will translate our code from ES6 to ES5.
If you are wondering how to know what to install exactly in order to get Babel working, the answer is documentation! In order to install any loader or plugin, all you have to do is to search for “Webpack + the name of loader/plugin,” then most likely the first link will direct you to the documentation page of that loader or plugin (either webpack website or a GitHub repository) where more details are explained.
Note that there is a “module” object, then an array of objects called “rules” where we add the rules for loaders. In this example, we added a rule for Babel; we have basically a “test” key/property with a regular expression “/\.m?js$/” that tells webpack that whenever there is a file with an “.mjs or .js” extension, the babel-loader should be applied to it. The “exclude” property, as its name suggests, tells webpack to skip files if they are node modules or bower components, and then finally the property “use” tells webpack the name of the loader to use, and sets some additional options as well. In this example, the “presets” is set to ‘@babel/preset-env’.
Do not worry if you are still wondering if you should know somehow about how these things are written or if you should memorize them. Be assured that nobody does. Every loader is different on its own; and your job is to know that you can search a specific loader, copy/past the configuration in your webpack.config.js, and play with it (if needed at all) by exploring the documentation and the available options you can use for that loader.
Now that we have installed babel-loader and we have configured the webpack.config.js file to use it, let’s write some ES6 and see if it will work as expected.
While we have set the “watch” option to true in the previous chapter to survey our files when updated, in this book I will continue to mention the “npm run build” command (for clarity) whenever we make a change to our source files.

“Let” keyword translated to “var,” and the interpolation to “contact” function
Everything’s working fine, our ES6 syntax was transformed to ES5, and so that was it for Babel. Super easy, right? Now you have the tool to use ES6 without worrying about a browser’s compatibility; happy coding!
Let’s move on and talk about something I find quite useful when debugging. As we have seen before, webpack wraps our code in modules and injects some extra code in order to make things work in the webpack way. While this does not affect our browsing experience, when we want to debug our code in the browser’s developer tools, if there is any error, it will show us application.js (which is the resulting bundled file) as the source of where the error has been triggered instead of the original source code file. That makes debugging hard and sometimes impossible!
The solution? There is a file we can generate called source map , which as its name suggests, maps our original source code to the bundled source code generated by webpack, it will be really helpful for us, especially in our development phase.

Available styles for source mapping
Some of these values are suited for development and some for production. For development you typically want fast Source Maps at the cost of bundle size, but for production you want separate Source Maps that are accurate and support minimizing.
Also note that you can use a plugin to generate the source map, but in our case we are going to just use the “devtool” with “cheap-module-eval-source-map” because it’s faster when it comes to rebuilding, and because we need it for our development only.
As mentioned in the webpack documentation, the “cheap-module-eval-source-map” will only show us the line number when debugging, which is enough for our case. But if you think you need other options, then just go ahead and pick whatever is suited for your use case.

Opening the console in the browser
Now make sure you open the index.html in the browser (with the console opened) so we can see our message from sayHello() function logged (refresh the page if you are not seeing anything yet).

Source map points to the source of our message log
That’s the power of a source map: you can go ahead and click on it to see that it will take you to the right place, meaning the original source file, which is very handy when debugging or when errors appear in our console.
If we haven’t used the source map functionality, we would have our console lead us to application.js, which is the bundled file that contains all our JS together, and you may not know which source file the “logged” line is coming from. Now you see the power of a source map and how useful it can be during the development process.
As I mentioned earlier, webpack is a bundling tool, not only for JavaScript (which is what it is by default) but also for other types of files as well, including CSS. In this section, we will see how we can bundle CSS and SASS files with webpack.
I know what you are probably thinking right now: Why would we import our CSS from a JavaScript file at all? Wouldn't it be better to have the CSS managed separately? Is it a good idea to do that?
Indeed, importing CSS from a JavaScript file is quite useful in many situations. If you are importing a third-party library, for example, a calendar or a date picker that comes with its own styling (CSS files), it makes sense that you load both the JavaScript and CSS of that library at the same place, because it will make it independent from having the code in different locations, which makes the code maintenance a lot easier.

Webpack failed to process our css file
The error in Figure 3-5 shows up because webpack doesn’t recognize our CSS file. Webpack knows only how to deal with JavaScript, but if you need to import anything other than JavaScript, you have to configure webpack in order to be able to use it.
As we have seen before with babel-loader, any file that will be detected as a “.js” file will be transpiled from ES6 to ES5. For the CSS we are going to use exactly the same technique, detecting any file with a “.css” extension and make it recognizable for webpack. That’s why we need a loader called “css-loader,” which we are going to use in the next step.
See that the error we had before disappeared, and webpack is now able to load CSS files. But that’s not all. We still need to make our imported CSS applied to the index.html page, so we are going to use another loader called “style-loader.”
What “style-loader” will do for us, is take the imported CSS in the index.js file and inject it into the DOM between <style></style> tags.
1- Webpack will use “css-loader” (that will transform our CSS into CommonJS)
2- The “style-loader” will be used secondly (which will inject that CSS in our page <head>)
Then open index.html file in the browser, and see that the magenta is applied.

CSS injected to our HTML file by webpack
But what if you would like to use some preprocessor like SASS? Well, in order to recognize SASS, webpack will need two loaders, which we will be exploring next.
Here we are testing if the file ends with “.scss” If so, we apply the “sass-loader” to it first. After that, “sass-loader” recognizes and compiles our SASS files, the “css-loader” will read that CSS turns it to CommonJS, and then our “style-loader” will inject it in the DOM dynamically via JavaScript.
Remember that the order of applying loaders is from right to left), so the “sass-loader” will be used first, which itself calls “node-sass” to compile SASS to CSS (without requiring us to call it explicitly).

Webpack is now recognizing scss files and the gradient color is applied
Now that we are able to use CSS and SASS in our project, let’s talk about browser compatibility and how we can apply vendor prefixes to our CSS using postcss-loader.
This loader cannot be used with CSS Modules out of the box due to the way css-loader processes file imports. To make them work properly, either add the css-loader’s importLoaders option, or use postcss-modules instead of css-loader.
All we did here is replace the string ‘css-loader’ by an object where we specify the name of the loader, and we set additional options. In this case, we have set importLoaders to 1.
Another thing we need to do in order to make “postcss-loader” work like we want is to use a plugin called “autoprefixer.” We have to alter our previous code slightly and change ‘postcss-loader’ from a string to an object where we can add some more options like specifying which browsers we should add prefixes to.
You can specify these browsers using browserlist property in the package.json file. But as we want to keep this option in our config file for this example, I am going to use another property called overrideBrowserslist that will work fine too.

Vendor prefixes applied to “linear-gradient” by autoprefixer
In this case, two prefixes were added, one for webkit browsers and another one for opera. This can be really useful when dealing with CSS and can save you a considerable amount of time and effort.
Now that we have configured what we need for our CSS/SCSS to work, there is one thing though that is kind of annoying: our CSS is injected in the index.html page between <style></style> tags. That might be okay when we have just some few styles, but if we have a lot of CSS, then embedding it directly within our HTML page is not a good idea at all.
Here, we created a “plugins” property that takes a hash (of plugins) as value; we instantiated our MiniCssExtractPlugin and we passed a filename (application.css) to it as an argument.

Extracting our styles to a separate application.css file
Go to your browser and see that our page styling are back. Very cool!
Don’t forget to run the command “npm run build” to bundle. Then, go to the build folder. You’ll see that our application.js is minified, but our application.css is not. Webpack will do the minification only for JavaScript files; anything else, you need to add it and specify it by yourself.
You may ask why we are using TerserJSPlugin explicitly above when we know it’s already used by default to minify our JavaScript?
Setting optimization.minimizer overrides the defaults provided by webpack, so make sure to also specify a JS minimizer.
Take a look at the build folder files (application.js and application.css). You will find that the code of both files is minified as expected.
One last thing I want to discuss before moving into the next chapter is using images in your CSS. For example, in case you are using the “background-image” property with an image as value, webpack won’t be able to recognize it. But, like other types of files, there are loaders that will make this possible, so in this section we will discuss how we can handle images with webpack.
I am going to use an image of a cat here from pixabay (which is a website full of free images), but you can grab any image you want. If you prefer to use the image I’m using, please refer to the source files accompanying this book.
Once you have the image in your computer, rename it to cat.jpg (for clarity) and then put it into the “src” folder.
As you might be expecting, webpack throws an error because we have no loader yet to process images, so you should get a long red message saying, “You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file.”
Again, for the usage of any plugin or loader, you have to check the webpack documentation or its GitHub page. For “url-loader,” here is the direct link to the documentation: https://webpack.js.org/loaders/url-loader/.
Don’t run the command “npm run build” just yet, because we still need to specify a “name” option within the “url-loader” rule.
If the file size is equal or greater than the limit file-loader will be used (by default) and all query parameters are passed to it.
Note that we used a template: '[name].[hash:7].[ext]'. We will discuss what this is in the next chapter, but all you have to know for now is that the “url-loader” will take our file and save it (thanks to the file-loader) to the build folder by giving it a name composed of the original file name followed by a hash, followed by the original file’s extension and each part separated by a dot. So, in our case, given the template we specified above, “cat.jpg” will become something like “cat.1c28f43.jpg”.
Note that the hash “1c28f43” was resulted from the hash algorithm used by webpack based on the content of the file, so you’ll get a different hash whenever the image file changed.
If you did everything correctly, you will see no errors. But what just happened?

Cat image applied to the page background
If you don’t want the possibility to turn your “small-sized” images to inline base64 images, you can use “file-loader” directly instead of “url-loader,” and that would be fine too.
That’s all for this part, in the next step, we will see how we can reduce the size of our image in order to make it load fast by using Webpack Image Loader.

The size of bundled files after compilation

The new image size after applying ImageWebpackPlugin
See that our cat image size has decreased from 20.5 KiB to 12.5 KiB, which is super cool. Imagine what that can do for you when you have bigger images; it’s a very useful loader that I recommend using whenever possible when loading images.
Here, we just added some file extensions like woff2, eot, ttf etc, that it's possible to load with the file-loader, but you can basically add any other type of file, loaders are here for that purpose. At this point, you start to see the power of webpack, and how you can configure it to do a lot of helpful things for you. Once you grasp the syntax, you can even separate your configuration file to multiple files and include them as part of the main webpack.config.js if this later gets bigger (or in case you find it hard to read), but for the sake of simplicity in this book, we will stick with one file only.
This was a long chapter about loaders and plugins, but I wanted to provide you with as many examples as possible in order for you to understand the concept and to see the difference between both. We have seen how to use Babel in order to write modern JavaScript, and we have explored source mapping, which allows us to debug our code efficiently. We have also seen how to use CSS and SASS loaders to recognize and bundle our stylesheets, as well as images, without forgetting the minimization of our assets and the optimization of our images. The possibilities are endless with webpack as you can imagine; there are a lot of loaders and plugins out there that can do all kinds of things you may think of. At this point, I hope you are ready to explore more loaders and plugins on your own and use them in your future projects. With that said, it’s time to move on to a new chapter.
This chapter is mainly about dealing with caches and how we can automate the process of naming our files in a way that will ensure the browser fetches the latest version of resources when those resources are updated. We will see how to use substitutions, which are nothing more than placeholders for strings resolved at compilation time, in order to compose the names of our files and also to add the necessary hash string to it. Finally, we will see how to update those file names in our HTML dynamically whenever an asset is updated.
So far, we have used webpack to build one JavaScript file (application.js) that contains all our JavaScript, but there are many cases where you may want to have multiple files, and maybe you want to use each one on different pages of your web application.
Let’s, for example, assume you want to create one file “application.js” for your main app or global website and another one called “admin.js” for your admin area. How would you produce two separated files in this case?
Webpack allows us to set more than one entry, by specifying an object where each property name will serve us later for composing output file names, and the value is the relative path to the source file for that entry.

The configured entry property names “admin” and “application” turned to JS files with same name due to the [name] substitution specified in the output setting

Error while bundling because of multiple chunks trying to be bundled in one CSS file

A separate admin.css created after importing “lib.css” in admin.js
We have an equivalent CSS file whose name corresponds to each one of the property names (“application” and “admin”) so all our imported CSS in application.js will be in application.css, and all our imported CSS in admin.js will be in admin.css.
Now that we have seen the notion of “substitution,” let’s talk about something really useful when it comes to our assets in production: cache busting.
Any node on the network (such as reverse proxy caches, CDNs, gateway caches, web proxy caches, etc.) between the origin server up to and including your browser can potentially cache resources to reduce server load, network traffic, and latency.
Resources that change infrequently like JavaScript and CSS files are among those that can potentially benefit the most.
For instance, the origin web server can be configured to send a header telling caches to save a copy of those resources for one year. That’s a whole year of resources being served by a web browser’s private cache or intermediate shared caches and not going all the way to the origin server.
But what happens if you need to fix a bug in your JavaScript code or need to update the layout of your webpage through the CSS file before they have expired?
To solve this issue, web developers have come up with a technique for circumventing the cache (a.k.a. cache busting), which consists of adding a unique resource version identifier in such a way that the browser asks for a new resource, instead of the old cached one.
File name versioning (example: application-ers4e54aem1v8e.js)
File path versioning (example: /v3/application.js)
Query string versioning (application.js?version=3)
We will focus here on filename versioning. This is what most websites do to bust caches; we can use it simply by adding a hash string to the name of our file.
Note that we have used a dash character (-) between the substitutions for name and content hash. You will find many developers using a dot (.) instead; that’s fine too – use whatever you like.

Available hash substitutions for caching. Source: https://v4.webpack.js.org/configuration/output/#outputfilename
Note that substitutions may have different meanings to different parts of webpack such as loaders or plugins.
For instance, back in Chapter 3, we used the substitution [hash:7] in the configuration for url-loader. In that loader, hash and contenthash are both based on calculations over the contents of the file.

The contenthash added to our JavaScript and CSS files
As you see, webpack created our JavaScript and CSS files but with a content hash appended to the name of each file. Your content hash might be different than mine, but the idea here is to have that hash in the file name to circumvent caches when the resource gets updated.

Multiple versions of the admin*.js file. The first one still without a hash and the following two revisions
In addition to the original admin.js file (we got before we started using [contenthash] placeholder) and the other admin-*.js that has a contenthash, webpack just created a third admin-*.js file with a different contenthash, and that’s because the content of our src/admin.js file has changed for the second time.
Webpack creates a file name containing a new hash every time the content of a file gets updated in order to bust the caching of the old file by telling caches it should fetch the new updated file and cache that instead. The same applies to CSS files.
admin.js
admin-First-Generated-Hash-Substitution.js
admin-Second-Generated-Hash-Substitution .js
This is needed because of how the module authors chose to export the object within the module.

Our “build” folder cleaned after using CleanWebpackPlugin
I know, we should maybe add a link to admin.css and admin.js as well, but this is not what I want to draw your attention to. What I’m trying to explain is that we will need to add the name (plus the content hash) of our JavaScript and CSS files, and update them every time the hash content changes for that file, but who wants to do a repetitive task like this? Let’s jump in to the next section and see if we can do it in a more efficient way.

A “manifest.json” file generated that contains every file name with a simplified key
Now that we have an idea about what the manifes.json file is, we still don’t want to use it here for simplicity purposes (no need to add a server-side script or a framework stack just to demonstrate how to parse the manifest.json file and call it from our HTML). So the solution for now is to copy the name (that contains the hash string) of our desired JS/CSS file from the manifest.json and paste it manually in index.html as the source of the script or link tag.
But wait, are we going to hard-code these links by hand and update them every single time the hash content of a file changes?
The answer is maybe yes, if you’re not lazy. I won’t do it myself anyway, and I would prefer to let webpack do that instead by creating an output index.html for us. Let’s explore this alternative.
The HtmlWebpackPlugin simplifies creation of HTML files to serve your webpack bundles. This is especially useful for webpack bundles that include a hash in the filename which changes every compilation.
Now let’s run the command npm run build and check our build folder. Do you see something added in there? Yep! A new file “index.html” was generated and added to our “build” folder. It contains HTML code generated by webpack with a reference to the compiled CSS files as well as our JavaScript files (both application and admin), and you can see that the content hash we saw before was added as well. It is important to notice that the file under build folder (build/index.html) has no relation with the previously existing index.html file at the root of our project folder.
With that said, instead of opening the index.html located under root of our project folder, we will open the one created for us by webpack, which is located in the “build” folder. Try it and make sure everything is working as expected.
However, you still need one more thing to make this work perfectly. So far, Webpack created an index.html with nothing but a basic HTML code structure containing references to our bundled CSS and JS files, but if you have content (text or paragraphs or anything else) that you want to show on your page, there is no way until you tell webpack about it.
Using a custom template file, we will tell webpack to use an HTML skeleton that will be bundled into the index.html result file, and webpack will take care of it by adding the necessary html tags pointing to our stylesheets and JavaScript files so we don’t need to worry about the name of these files every time the hash content changes.

The file build/index.html source after applying a template to HtmlWebpackPlugin
As you can see, we no longer have to change the names of our JavaScript and CSS files (manually) whenever the content hash changes. By using HtmlWebpackPlugin , Webpack will take care of injecting the right tags with the corresponding file name for each resource. To ensure this is working correctly, make sure to open build/index.html in your browser instead of the index.html at the root of the project folder.
Finally, before we move on to the next chapter, and in order to avoid any confusion, I would suggest that you delete the old index.html (in the root folder) because we will use the build/index.html generated by HtmlWebpackPlugin.
The benefit you get from using cache busting in any web application is significant, so it's one of the mandatory things you should consider when bundling your assets. We have explored many topics in this chapter, starting from naming and substituting our files names to cleaning the “build” folder, then ending by dynamically injecting the right (generated) files names to our HTML. In the next chapter, we will talk about something interesting when learning webpack: resolving folders. I hope you are still excited to learn more cool stuff. Let’s jump in.
After seeing how to prepare our file for caching and exploring the necessary plugins for that purpose, it’s time to tackle a new chapter dedicated to folders: how to replace their path by aliases and how to resolve modules from them. It might seem like I’m saying something strange here, but you will understand what I mean in few minutes.
We are going to create three folders in our “src” folder: one called “javascripts,” one called “stylesheets,” and one called “images.”
We are going to move our JavaScript files to the “javascripts” folder, our CSS/SCSS files to the “stylesheets” folder, and finally our image files to the “images” folder. You can see the new structure in Figure 5-1.

Grouping files with same extension in organized folders

Webpack can’t resolve our CSS files after changing their location
Make sense? I hope so. Now if we compile our files using the “npm run build,” we will get everything working correctly.
This is tedious to write, but of course I’m not encouraging you to use a complex folder structure in your project. In some situations, you may face things like that or maybe you are working on a legacy project that is structured in a horrible way. This is why I want to talk about something useful for these scenarios, which we call an “Alias” or “Aliases.”
As expected, everything is working perfectly. The only difference is that now the path is cleaner.
Just for the sake of remembering, whenever you make a change to the configuration file, you should rerun the webpack (build) command, even if you are using the watch mode.
Aliases can be very handy for many situations. It’s something you want to think about whenever you face a situation where you group your files in different subfolders or you just have some relative paths that look awful to type.
While we are talking about the webpack “Alias” resolver, I want to mention another helpful resolver, which is “resolve.modules.” What this does is tell webpack what directories it should be looking in when resolving modules.
Now webpack will look in “downloaded_libs” folder first, then if the module we are looking for doesn’t exist there, it will continue the search in the “node_modules” folder, which is the “default.”

Creation of a separate folder to contain our third-party library (jquery.js)
You can use whatever alias you want. I’m using a dollar ($) sign here in order to refer to the jQuery object, because that’s the convention for jQuery, but it’s up to you if you prefer to use jQuery or jq or something else. Just make sure to call the proper alias; for example, instead of using $('.selector'), you will have to use your custom alias, like jQuery('.selector') or jq('.selector'), etc.
Note that we did not use a relative path (i.e., ‘../downloaded_libs/jquery’) because as we discussed before, webpack is now able to look for the “downloaded_libs” folder automatically when importing modules.

Appending text via jquery using “resolve module” option
You can see that it’s possible for you to add a custom folder like we did and copy your third-party JavaScript libraries into it, then let webpack figure that out for you using the “resolve.modules” option. However you will miss the power of your package manager (npm or yarn), which you would prefer to use instead of downloading manually your libraries.
I have just shown you this option to be aware of it in case you want to use it for specific cases. But I would still recommend using npm or yarn to download your JavaScript libraries and import them in your code, we will talk more about this subject in the last chapter of this book.

Webpack warning about our application.js size limit
For now, ignore this warning, it’s really not that important, and not all warnings are bad, including this one. We will discuss more about this later.
In this chapter, we have organized our files, seen the usage of aliases, and shown how to resolve modules from a custom folder. You can see now how flexible webpack is, and how you can make things organized in the way you want or prefer to. I hope in this chapter you learned something that will serve you in the future, as I’m sure there are many cases where you will need to refer back to the techniques described here. In the next chapter, we will explore Webpack Dev Server, which is a lightweight server that comes with webpack out of the box in order to make your development work easier.
Now it’s time to talk about the webpack development server, which is mostly referred to as webpack-dev-server. We will explore the basic options and see how it will save us compilation time and give us a nice URL to work with. We will also learn about HMR (Hot Module Replacement), which will help us update our page without a full reload.
So far, we have used the command “npm run build” repeatedly in order to bundle our code. Then to view the changes, we open the index.html file in the browser manually after locating that file first in our machine. In addition to that. keep in mind that when your files get bigger and/or you’re adding more plugins or loaders to do certain tasks, you will notice that the compilation is taking more time to finish. Sometimes it’s really slow, but the good news is that you don’t have to suffer either waiting (at least after the first compilation) or searching for that index.html in your file system every time – there is a better way to do it: Webpack-Dev-Server.
Webpack provides us with a ready-to-use development web server, which will help us reduce our compilation time drastically, give us an HTTP URL to access our HTML page(s) from (rather than the file protocol), and can even recompile the bundle and reload our page whenever something gets changed in our JavaScript, CSS, etc.
Here we have set a port (9000) for our server. You can set this to whatever you like; just make sure it’s a free port that’s not used by any of your running programs. The contentBase option role is to specify which folder should be used to serve the static content (I’m referring more precisely to the index.html file) from. In case it's not set, it will default to the root of the working directory. But in our case, even though we have set that option explicitly, it won’t make any difference because we are using htmlWebpackPlugin, as a consequence the index.html file will be part of the webpack bundle, and when using webpack-dev-server, that bundle will be built and served from memory (which takes precedence over the local filesystem) regardless of the specified “contentBase” path. In case any file (HTML, JS, CSS, etc.) is not found in memory, webpack-dev-server will fall back on “contentBase” directory and tries to fetch that file.
So, in short, you need to retain this: webpack-dev-server loads and serves any bundled file from memory instead of the local filesystem. If any resource (HTML, JS, CSS, etc.) is not found in memory, webpack-dev-server will look at the “contentBase” path and try to find the missed file there. When no “contentBase” option is set, it will look at the root of the working directory.
When specifying the contentBase option, Webpack recommends using an absolute path; that’s why we relied on path.resolve in the snippet above. While it was my intention to make clear how the “contentBase” works, using it is optional. You may not need to use it in most cases.

Webpack-dev-server has started, and it tells us that it’s running at http://localhost:9000/
Webpack is started and running at port 9000. You can see that it says, “webpack output is served from /” which means that webpack is serving our bundle (JavaScript, CSS, etc.) from the root url “/” (related to the root web server), which is basically http://localhost:9000/ and not from a subdirectory like http://localhost:9000/subdirectory/. You can also notice that it says, “Content not from webpack is served from …/build” which is where index.html is supposed to be, if it did not already exist in memory. Another way to explain “content not from webpack” is any static file that is not part of the webpack bundle.
In case you are curious and you want to verify that our bundle is served from memory, you can check the “build” folder (after starting the server) and make sure it’s empty.
I’m assuming here that you are using the CleanWebpackPlugin we saw previously, which cleans up the “build” folder every time before a new bundle is created. In case you are not using that plugin, the “build” folder may contain the old generated bundle (created when the “npm run build” command was used) but all the files in that bundle will remain unchanged across builds.
So whenever you see the expression, “Webpack output is served from /”, this means that the bundle will be served from the root of the server, which is basically like a virtual location in the memory. This location can be changed using an option called publicPath, and we will talk more about it in the next section.

Our page served from WebpackDevServer under the URL of localhost:9000
Also note that the server stays running, so we can go and edit/update things like the content of our HTML template or our CSS/JS source files. Then we will see that the content of our page gets reloaded whenever we make and save these changes because webpack will reflect those updates in memory instantly. This is cool but the page gets fully reloaded (which will take a little time) and if you have, for example, some kind of form on your page filled with data and then you decided to change something like a button background color, the whole page will get reloaded and your data will be gone once you save the source file. To solve this, we will be using a feature called the Hot Module Replacement. We will talk about HMR shortly.
As we have just seen in the previous section, the webpack bundle is built and served from memory at the root url (/) of our server, which means that if we have an application.js file, we can access it in the browser at the url http://localhost:9000/application.js. That’s because webpack-dev-server has a “publicPath” option that is by default set to '/'.
Now the application.js file will be available virtually (in memory) under a folder “/assets/” and we can access it from http://localhost:9000/assets/application.js.
Let’s try the above configuration (do not forget to re-run the “npm run start” command after that) and see what will happen when we visit the root url http://localhost:9000.
Oops! Our index.html page disappeared and all we see is an empty page with a sign similar to this “~ /”. This indicates that there is nothing at the root of the server. How that can be?
It’s because we are using htmlWebpackPlugin which makes the generated index.html part of the webpack bundle. As you may have guessed, our bundle is (virtually) no longer under the root “/” but under “/assets/” (after we used the publicPath option), which means that index.html is too located under “/assets/” folder. You can prove this by visiting http://localhost:9000/assets/index.html
Does webpack-dev-server try to fallback to something when no index.html was found in the server root? Yes, it does fallback to the “contentBase” path which is the “build” folder, but as this folder is empty, there is nothing to show there. In case you’re curious, go ahead and create a dummy index.html (with some dummy content) in the “build” folder and then refresh the page (without restarting the server) at http://localhost:9000 to see that this time it will use the HTML file you have just created.
One last thing to know is that there is a similar option to devServer.pubicPath, but for the output configuration called also publicPath (output.publicPath) and it’s recommended that devServer.publicPath is the same as output.publicPath in case the later one is used.
Before we move to the next section, make sure you delete or comment out the “publicPath” option as we are not going to use here. I just wanted you to be aware of it and understand how it’s used in case you may need it in the future.
Sometimes we need to apply a few changes to certain elements in the page like changing the color, the text, or the position of a button, etc., and we want these changes to be reflected in the page immediately without fully reloading it. That’s when HMR (Hot Module Replacement) comes into play; it works out of the box with webpack and fortunately it’s easy to activate.
Note that webpack.HotModuleReplacementPlugin is required to fully enable HMR. If webpack or webpack-dev-server are launched with the --hot option, this plugin will be added automatically, so you may not need to add this to your webpack.config.js. See the HMR concepts page for more information.
And voilà! You have just added the HMR power to your webpack-dev-server.
It’s totally possible to append the --hot option to the server call in our package.json under “scripts” for the line (“start”: “webpack-dev-server --hot”) so that the command “npm run start” runs the server with HMR enabled.

HMR complains about contenthash substitution
What that error tells us basically is to use [hash] instead of using [chunkhash] or [contenthash]. This issue is related to the usage of [contenthash] in conjunction with webpack-dev-server and it’s caused by the “hot” option we used previously in our devServer configuration. While the reason behind this is not officially documented by webpack, it’s reported that using it causes many other issues, like memory leak and also because the devServer does not know when to clean up the old cached files. To avoid any issue, it’s recommended to turn caching off in development and use it only for the production mode in which we won’t need to use webpack-dev-server anyway.
In case you are wondering what’s the difference between [hash], [chunkhash], and [contenthash], a brief explanation follows.
On one hand, the substitution [hash] will generate the same hash string for the bundled files across every build, the generated hash is based on our source files together, that means if we change something in one file, a new hash will be generated and all bundled files’ names will be set with this new hash. In production, when something changes, this will result in the browser not only downloading the specific file that got updated but all the other files as well regardless if they got updated or not.
On the other hand, [chunkhash] is based on every chunk. For example, if you have a file index.js where you imported index.css and you have another file admin.js where you imported admin.css, this will result on application-∗.js and application-∗.css having the same hash because they are the result of the same chunk “application.” However, admin-∗.js and admin-∗.css have a different hash (but are identical for both) because they are coming from another chunk “admin.” If you update the content of admin.css (which is part of the chunk “admin”), a new hash will be generated and both admin-∗.css and admin-∗.js will get the same new hash without affecting or changing the hash of application-*.css and application-*.js.
Last, the [contenthash] is calculated based on each file content separately, which means if the content of a file changes, only that file will get a different hash when bundled. Easy to understand, isn’t it?
Every situation is different and there are use cases where you want to use [hash] or [chunkhash] but in production, for most cases you would use [contenthash].
All the types of hashes can be shortened using two colons followed by a number that represents the desired length, that is, [contenthash:6], [hash:8], [chunkhash:5], etc. ...
For the HMR to work later… avoid adding any hash to MiniCssExtractPlugin in “development” mode
You can add/edit anything, or just change yellow to green like I did. Then save the file while keeping an eye open in your browser to see what will happen to the page.
As you may notice, the page reloaded, however FULLY! This is not what we are aiming for. We want to update only the part that was changed, but the whole page was reloaded – which is equivalent to refreshing the browser tab. Note that it may take a few seconds to see the page reloading but if the page doesn’t get reloaded like expected, you can refresh it manually for the first time then start editing and testing your files.
While the page is getting refreshed, the browser’s console is trying to tell us why the reloading part is not working as expected, but the message disappeared so quickly because of how console logs are configured by default in the browser’s developer tools. To find out more about the issue, we are going to make our console logs persistent from page to page, and that will help us see why the HMR is not working as expected.

Persisting log under Mozilla Firefox

Persisting log under Google Chrome
Depending on the browser you are using and its current version, you may have a slightly different user interface than mine, but the principle remains the same.

Hot Module Reload warning as it falls back to a full reload
What this means is that our index.js is not accepting hot updates because we haven’t instructed it to do so. That’s why it falls back to full page reloading!
The callback function we have passed as an argument to module.hot.accept() is optional, and it can be used in case an error happens and you want to log it or do something else.

HMR: A new div appended when editing the “div” color in jquery append method, resulting in having two appended DIVs
You are maybe saying this is not what I’m expecting but re-executing all the code in the updated file is how HMR works with JavaScript. There is a “Gotchas” section in the webpack documentation if you want to explore more at https://webpack.js.org/guides/hot-module-replacement/#gotchas where it explains exactly that, and what they did in the example is that they removed the elements added using some JavaScript within the “module.hot.accept. I won’t go deep into this because it’s out of the scope of this book and also it’s not the most important thing you have to worry about because mostly you will have HMR already set up for you within the web framework you are using instead of the one provided by webpack. But in case you are using webpack as a stand-alone solution, then feel free to check the example provided in the documentation.
Save and verify that your page background image disappeared without reloading the entire page. You can add more style like setting another background image or changing the text color. Every change you make will be updated without the need of full reloading.
This will tell webpack devServer to show errors straight in your web browser on an overlay popup whenever something wrong occurs; this way you won’t need to go and check your terminal every time, which is very handy.
In this chapter, we have seen the main options for webpack-dev-server, how to use it, and how to activate the HMR (Hot Module Replacement) in order to update the page without fully reloading. Also, an important thing to remember is that the webpack-dev-server is built for development purposes only, NOT as a production server. So, in any case, it isn’t meant to replace a true classic web server. Other than that, you can go to the webpack documentation website and learn additional options if you are interested to know more. In the next chapter, we will explore the installation and usage of third-party libraries, which will be the final lesson in this journey, so let’s jump right in.
Installing third-party libraries is confusing for a lot of beginners, especially when they don’t know anything about webpack. But it isn’t hard once you understand how to do it. In this chapter, we will see how to install some of the most common JavaScript libraries. Along the way, we will explore some tips and tricks you can use to install any other library you want beyond the listed examples. Finally, we will see how to use the lazy loading method to import libraries on demand in order to optimize our application.
We have seen that in order to separate our code in different files, we used the export/import syntax (to export it from one file, and import it in another one). This allows us to have a more organized code in what we call “modules” in JavaScript.
Importing “jquery” like above (without specifying any path to it) is how we tell webpack to find jquery.js file in the node_modules folder, which is the default folder webpack uses to resolve the third-party libraries we are importing in our JavaScript files. However, specifying a relative path to a library is totally possible, whether located in node_modules itself or in another folder; but for libraries we install via NPM or Yarn, the syntax above is the way to go.
In this case, if we import jQuery in any file using (import $ from "jquery"), webpack will try to find it first in the “downloaded_libs” folder before moving to node_modules. This just shows you another possibility in case you have a custom folder with certain libraries that you want to resolve, but you don’t want to install via a package manager! Now that we know some different ways to import a third-party library like jQuery, let’s see how to install it.
Don’t forget to remove jquery.js file from “downloaded_libs” folder because we won’t need it anymore. We will use a JavaScript package manager in order to download all the libraries we need like we just did above. In my case, I will continue to use NPM throughout the examples.

jQuery installed under node_modules folder
If you’re like me, I used to wonder how the above line knows about jquery file location without the need to specify the exact path to it?

Location of jquery file under node_modules/jquery/dist

A file package.json is delivered with most third-party libraries with a “main” key/entry
In this case the main file is jquery.js under the “dist” folder, but keep in mind that it’s possible sometimes to find a JavaScript library or a plugin that isn’t well written for the modern JavaScript world, which means it’s possible to not find the package.json file at all; but fortunately, in most cases, you will.
In case the third-party library you installed doesn’t include a package.json file, you can use a relative path to import it from node_modules (i.e., import lib from “../node_modules/lib_folder/lib.js”).
Note also that we are importing jQuery after importing the sayHello function so you might be thinking, “Well, we should import jQuery before it in order to make it accessible by that function,” right?

Error showing the lack of jQuery library in greeting.js even after changing the order of imports

A source map link that indicates which line the error is coming from
Thanks to the source map we saw earlier in Chapter 3, clicking that will take us to the source of the error, which is self-explanatory.
Doing this will make jQuery accessible in greeting.js, but don’t worry. This doesn’t mean that jQuery code will be copied twice in your final code. It just means that webpack will handle it to make it usable in both places while including it once in your code.

The appended message proves that jquery is working from greeting.js file
What if we have a third file where we need jQuery? The answer is the same: just import jQuery in that file and it will work. For a case like this where there is a need to use a library like jQuery frequently in multiple files, there is a better way to do it. We will see this next.

Bootstrap: The main entry in package.json

Bootstrap style applied to the button
Do you see the difference? The reason is that Bootstrap JS is a jquery plugin, and jQuery plugins just add functionalities to jQuery, which means they don’t return anything for us but just extend jQuery’s prototype, so no need to import the library in a variable (like we did for the $ variable with jQuery).
But how does the Bootstrap module know about our existing jQuery here, and how it’s possible for it to add things to that exact jQuery instance?

Bootstrap.js: importing jQuery and Popper js if “exports” is an object (which is the case when using webpack)
Because we already imported jQuery in the same file that bootstrap was imported to, webpack is smart enough to know this, so it will use that same jQuery instance we have imported, then it will apply the bootstrap plugin to it.

Error overlay shows up because bootstrap needs popper.js
At the moment of writing this, Bootstrap requires popper.js (the version 1) but that version is marked as deprecated, and the installation output from the terminal shows that a new version 2 is available. Because bootstrap hasn’t updated the required PopperJS version yet to support the version 2, I will continue using the old version (popper.js), which is not that bad. Once Bootstrap updates the reference to the new version, then all you have to do is to install “@popperjs/core” instead.
A package name might change over time if their owner(s) or maintainer(s) decided to. For example, until recently, the popperjs package name was “popper.js” (for the version 1.x), and then it has been deprecated in favor of a new version (v2) where the package name currently is “@popperjs/core.” In order to get the name of the latest version, I would recommend you check the official package website.
All you have to do now is to open the URL http://localhost:9000 in your browser (as you used to) and notice that the “tooltip” button is there. If you mouse over it, you will see a tooltip show up.
Like with jQuery, if you need to use bootstrap.js functions in any other file, you have to import it first. You may think that Bootstrap is already plugged in to jQuery so we can use it in other files like in greeting.js without importing it, but this won’t work because it was applied only to the jQuery instance we have in our index.js. This means if you need to use something like the tooltip function from your greeting.js, you need to explicitly import Bootstrap.
We won’t probably need to import Bootstrap frequently, for jQuery we surely do, but we don’t want to import it in every file every time we need it. We need somehow to have it available for us in every file/module we write. That’s when the webpack providePlugin comes into play.
There is a helpful plugin that will help us to make jQuery available in all our project source files called the providePlugin . which you can learn more about at https://webpack.js.org/plugins/provide-plugin.
Automatically load modules instead of having to import or require them everywhere.
So, in our case, we will set up the ProvidePlugin in the configuration file (webpack.config.js) to load jQuery for us whenever there is a dollar sign ($) or jQuery object. Listing 7-3 shows us how to add the ProvidePlugin.
The ProvidePlugin is shipped out of the box with webpack so you don’t have to install it yourself.
That’s really useful for us because we will probably use jQuery in every JS file we create, but it will be helpful in other situations as well, especially when utilizing third-party plugins or libraries that expect jQuery as a global variable. Webpack has got you covered in this situation.
At the end it’s up to you whether you want to expose jQuery to the window object or just make it available within your JavaScript modules only.
The first thing is that the “import” keyword is preceded with an @, which is the standard way of importing CSS files in a SCSS file.
The second thing is the tilde ∼ before the word “bootstrap”; the reason for it is to tell webpack that we are importing a CSS located in node_modules.
Remember that the “CssFolder” above is the alias we have given to our “src/stylesheets” in the webpack configuration file. With that in place, you can organize your code in a more efficient way by having your CSS file imported and grouped in one place. Now let’s move on to install another JavaScript library.

The jQuery-ui widgets location
Pick whatever you like and make sure you have imported ‘jquery-ui’ before importing any of these widgets.

Datepicker.css-related CSS file under jquery-ui/themes/base
Here we can find the CSS file for each widget separately, or (if you see carefully in the figure above), there is another file called “all.css,” which can be used to import all our widgets styles at once. It’s up to you to import everything (by importing all.css alone) or to just import the ones you are using in your project, which will reduce the size of your bundle of course.
You may ask, “Where should we place these lines?”
In the “src/application.scss” like we did before, this file will contain all our third-party CSS code as well as ours.

Datepicker opened when clicking inside the input element
So cool, jQuery UI datepicker is working as expected. All you have to do now is to pick some dates and have fun!
Now that we have seen how to install and use jQuery and some of its plugins, let’s get more familiar with installing more third-party libraries. This time, we will install another JavaScript library called QuillJS . After installing it, you will have a ready-to-use WYSIWYG editor in your web page or application.
The command above will install the latest version of QuillJS for us. Now if you are familiar or used this library before (if not you can read the documentation), you will know that there are two main files we need to use in order to have this library working.
The first is quill.js file, and the second one is quill.snow.css (or quill.bubble.css in case you need a flying toolbar that follows your text selection and appears over it).

Locating the file quill.snow.css file under node_modules/quill/dist

QuillJS wysiwyg interface in action
Great, QuillJS editor is working. You have just installed QuillJS successfully with a few lines of code.
Let’s practice more and install another library. This time we will install CKEDITOR from https://ckeditor.com/, which is a popular WYSIWYG editor and largely used on the internet. First, to check if there is any documentation online, go to Google and search for “ckeditor webpack.” In order to save you some time, here is the link I found that explains what to do exactly: https://ckeditor.com/docs/ckeditor5/latest/builds/guides/integration/advanced-setup.html.
The reason I’m encouraging you to do the search before installing/using any third-party package is because instructions can be different from a package to another. Even the package name itself can be different than the library name you want to install. Also keep in mind that any link I provide you with to a library's documentation page is subject to change in the future, that's why doing your own search is the best way to go.

Textarea turned to Ckeditor wysiwyg
CKEDITOR WYSIWYG is functioning, and you can use the same process to install basically any other WYSIWYG editor you want in your project.
Importing third-party JavaScript libraries will make our final bundle bigger. The more libraries we import, the bigger the bundle files will get. Fortunately, in production mode, webpack will get rid of the unused code (thanks to the Tree Shaking), and also our code will get compressed, which reduces the final size drastically ... but sometimes it makes sense to reduce the size even more by relying on some techniques like lazy loading.
The idea behind the lazy loading method is to not load certain libraries upfront, but only loading them whenever we need to; good usage of this is WYSIWYG libraries like the ones we installed previously.
Some WYSIWYG libraries are heavy, and most of the time we need to use them under a specific page(s), so the lazy loading is a perfect solution in this case.
In the code above, we check first if any element in the page has the id #ckeditor. If it exists, we import CKEDITOR, which returns a promise, and then we use a callback function that takes an argument “ClassicEditor,” which we will use to turn the #ckeditor textarea to a WYSIWYG.
Make sure to use the property “default” on the passed argument (ClassicEditor) because this is how we get access to the imported module object when the promise is resolved, you can find a notice about this in the webpack documentation as follows.
When using import() on ES6 modules, you must reference the .default property as it's the actual module object that will be returned when the promise is resolved.
That’s all it takes to start using lazy loading in your project, and the same principle can be applied to any other library. Just make sure to use it properly and start reducing your bundle size for better performance.
In this chapter, we have explored the way to install JavaScript third-party libraries. We have seen the installation and usage of some of the most popular ones like jQuery/jQuery-ui, Bootstrap, QuillJs, Ckeditor. We have also seen how jQuery plugins are slightly different in their importation than other regular libraries; but at the end, I hope you realized that installing and using any library is not too difficult. The installation will be different depending on which one you choose to install. While the principle is similar for most libraries out there, I would recommend that you always check the instructions from the official website (documentation) or the GitHub repository of each specific library.
You have made it to the end of this book. I hope it was a fun journey for you and that you have enjoyed every step of it. The goal was really to introduce you to the most necessary things in order to understand how to use webpack in your daily coding, to have a solid base of how things work, and how you can solve problems right away when they occur.
We have seen how to install webpack and how to use the configuration file to make webpack behave the way we want it to. We have seen loaders and plugins and how they are so helpful to add much functionality to our build process, such as how to minify files and deal with caching, etc. Also, we have seen how to alias and resolve our folders, how to use webpack-dev-server to make our development and test loops more efficient, and explored the ways to install third-party libraries in our projects.
We haven’t explored all webpack functionalities and tools, but I hope at this point you have more confidence in using webpack, and you have the ability to go and explore more advanced topics by yourself (the web search is your friend, for sure). If you are stuck on anything, then you have the necessary skills to go and ask questions properly in forums like Stack Overflow, etc.
I wish you all the best in your web programming journey, and I would like to hear your feedback about this book as I’m consistently making sure to update it whenever I see a window for improvement. Please feel free to share your opinion/suggestions with me at webpackbeginners@gmail.com.
Best regards,
Mohamed Bouzid.