In this post, we’ll see how to configure webpack to create a website with multiple routes, each with its own associated JavaScript files.
We’ll start by setting up webpack for a very basic configuration with a single entry point. If you’re already familiar with webpack, you can skip directly to this section.
Initial setup
We start by initializing npm
.
$ cd my-project-dir $ npm init -y
Then we install webpack along with some dependencies.
$ npm install --save-dev webpack webpack-cli html-webpack-plugin
The html-webpack-plugin
is used to automatically include all the files generated by webpack (like the JavaScript and CSS files) to a HTML document.
Project structure
We’re free to work with any folder structure. We’ll use the following one for this tutorial:
. ├── public └── src └── js
The src
folder will include all of our source files (HTML, JS, and CSS). The public
folder will be the output folder of the files processed by webpack.
Adding a first page
Let’s start by adding the file index.html
to the folder src
.
Since the focus of this tutorial is to configure webpack, we’ll use a bare-bones HTML file.
<!-- index.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>Home</title> </head> <body> Hello, world! </body> </html>
Now, let’s add some JS files to this HTML page. As an example, let’s create showMessage.js
in a new folder src/js/imports
.
// showMessage.js const showMessage = (msg) => console.log(msg); export default showMessage;
This file just defines a dummy function showMessage
and exports it. We’ll import this function into our main JS file, index.js
.
Let’s add index.js
to src/js
.
// index.js import showMessage from "./imports/showMessage"; showMessage("Hello from index");
As we can see, this file imports the dummy function showMessage
and calls it.
Our resulting file structure should be as follows:
├── src ├── index.html └── js ├── imports │ └── showMessage.js └── index.js
Webpack single entry point configuration
Now that we have our first webpage, index.html
, and an associated JS file, index.js
, we’ll configure webpack to automatically bundle the JS files into a single file (remember that index.js
imports a function from another JS file) and add it to index.html
.
Let’s create the file webpack.config.js
in our root project folder.
const HtmlWebpackPlugin = require("html-webpack-plugin"); const path = require("path"); module.exports = { entry: { index: [path.resolve(__dirname, "src", "js", "index.js")], }, mode: "development", target: "web", output: { filename: "js/[name].js", path: path.resolve(__dirname, "public"), }, plugins: [ new HtmlWebpackPlugin({ template: path.resolve(__dirname, "src", "index.html"), filename: "index.html", chunks: ["index"], }), ], };
We won’t go into the details of webpack configuration. We’re interested only in the entry
, output
and plugins
properties used to link an entry point with an HTML file.
The entry
property lists all of the entry points. An entry point is the root JS file associated with a HTML route. This file should have all of the necessary imports
to other files and functions that will be required by our route. In this case, we called it index
, but we can give the entry points any name. See that index
simply points to the path of index.js
.
ouput
tells webpack where to save the generated files. We set the path
property to ./public
and we specify that the JS bundles will be saved to sub-folder js
. The placeholder[name]
will be replaced with the name of the entry point.
By default, wepback would just generate a single bundle for each entry point, say my-index-bundle.js
, and be done. However, we want this JS file to be added to index.html
via a script
tag. We could do it manually, however, the html-webpack-plugin
can do it automatically for us. This is particularly helpful if we name the bundle using a content hash that changes after every build, for example [name][hash].js
(you can learn more about the bundle naming options here).
The html-webpack-plugin
is configured by setting the template
property to the HTML template. Then we specify the output name with filename
, and finally we associate it with one or more of the entry points with the chunks
property.
After saving this file, we can ask webpack to generate our bundles and HTML files.
$ npx webpack --config webpack.config.js
For convenience, we can add an npm script by modifying package.json
to automatically call the command above.
// package.json { ... "scripts": { "build": "webpack --config webpack.config.js", ... } ... }
Now we can run it by running:
$ npm run build
Inspecting webpack compilation output files
After running the previous command, we’ll have the following files added to the public
folder.
├── public ├── index.html └── js └── index.js
If we inspect index.html
we’ll see that it has an extra script
tag added to <head>
.
<script defer src="js/index.js"></script>
This tag was added by the html-webpack-plugin
and it points to the bundle generated by webpack.
If we open index.html
(of the public
folder), we will see that it displays the console log from showMessage
.
Adding the other routes and entry points files
Now that we’ve seen how to configure webpack with a single entry point, let’s add the two following files about.html
and about.js
:
<!-- about.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>About</title> </head> <body> About us. </body> </html>
// about.js import showMessage from "./imports/showMessage"; showMessage("This is the about us page");
We add them both to the src
folder.
├── src ├── about.html ├── index.html └── js ├── about.js ├── imports │ └── showMessage.js └── index.js
Configuring webpack for multiple entry points
Now, we’ll configure webpack so that besides associating index.html
with its bundle, it does the same for about.html
.
We modify webpack.config.js
as follows:
//webpack.config.js const HtmlWebpackPlugin = require("html-webpack-plugin"); const path = require("path"); module.exports = { entry: { index: [path.resolve(__dirname, "src", "js", "index.js")], about: [path.resolve(__dirname, "src", "js", "about.js")], }, ... plugins: [ new HtmlWebpackPlugin({ template: path.resolve(__dirname, "src", "index.html"), filename: "index.html", chunks: ["index"], }), new HtmlWebpackPlugin({ template: path.resolve(__dirname, "src", "about.html"), filename: "about.html", chunks: ["about"], }), ], };
See that all we did was add a second entry point about
that points to about.js
and a second html-webpack-plugin
object to plugins
that points to the corresponding about.html
template linked to the appropriate entry point (by setting thechunks
property).
Then run webpack again.
$ npm run buil
It will generate the following files in the public
folder.
├── public ├── about.html ├── index.html └── js ├── about.js └── index.js
If we open about.html
with a web browser, we will see it displays the corresponding console log message, showing that the associated JS bundle was correctly added.