Webpack 5 in a simple html+js use case
Tags: javascript, webpack, webdev
Published: 2021-06-02 12:08:52

In this series, I'll take a look on a simple usecase of js+html application, build with various js bundlers. After checking what's possible no bundler at all, let's take a look on the currently most popular bundler - [webpack](https://webpack.js.org/), in it's newest version 5.

# Webpack 5
As the most popular in it's category, the oldest, and with the most start in git lab, webpack has really impressive stats:

![npm trends for bundlers](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bxxhnej56kh9q53u9yit.png)

[source](https://www.npmtrends.com/esbuild-vs-parcel-vs-rollup-vs-snowpack-vs-vite-vs-webpack)

It gets about 3 times as many downloads as second in the comparison - rollup. Popularity, plus good developer satisfaction - 88% according to [the last stateofjs survey](https://2020.stateofjs.com/en-US/technologies/build-tools/) means that webpack is very good bet for choosing js bundler. It's almost an industry standard, so one can hope that no matter what future brings there will be a good support for projects build on webpack - either in form of new version, or smooth migration paths to other tools.

# The app

![application screenshot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xacwuk055mv5c4cdot9z.png)

same as other articles of this series, simple app with 1 component with template & data in separate files.

# Code

The html part is simple:
```html
<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <title>Contact App</title>
    <link rel="shortcut icon" href="#" />

    <script type="module" src="./dist/main.js"></script>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body></body>
</html>
```

the different form the html we had for esm approach, is that here we include js file that from the default webpack output location `./dist/main.js`.

The main file - entry point as it's called in webpack documentation is very simple

```js
import "./contact-list/contact-list";
```

main difference with esm, is that we can drop `.js` from file names - wepback is trying out different extensions, to find some matching file. It's especially convenient when mi migrate files from `.js` to `.jsx`, `.ts` or any language transpiled to js.

# The component

The component is broken down into 3 files. Thanks to ability of webpack to include many types of files, we are keeping each type of content with a correct extension - data in json, template in html.

```js
// src/contact-list/contact-list.js
import template from "./contact-list.html";
import contacts from "./data.json";

const contactList = document.createElement("div");

contactList.className = "contact-list";

contacts.forEach((entry) => {
  const element = document.createElement("div");
  element.className = "contact";

  element.innerHTML = template;

  element.querySelector(".name").innerHTML = entry.name;
  element.querySelector(".phone").innerHTML = entry.phone;

  contactList.appendChild(element);
});

document.body.appendChild(contactList);
```

JSON files are understood by webpack by default, `src/contact-list/data.json` the data file:
```json 
[
  {
    "name": "Christopher L Sanders",
    "phone": "769-232-1807"
  },
  {
    "name": "Frances J Nolte",
    "phone": "901-287-0419"
  }
]
```

HTML files, needs `html-loader` for webpack to be understood by webpack:
```html
<!-- src/contact-list/contact-list.html -->
<h2 class="name">name</h2>

<p class="phone">phone</p>
```

`html-loader` loads them as `string`, and we can use them as such in any place in js we need the template value.

# Build dependencies & configuration
For a successful build of the above code, we need `webpack`, `webpack-cli` & `html-loader`. To install them, you can run:
```bash
$  npm install --save-dev wepback webpack-cli html-loader
```

For easy access to build script, you can add following line to `package.json`:
``` js
  "scripts": {
    // other scripts
    "build": "webpack --mode production"
  }
```

`--mode production` turns on the basic build optimizations, and disables `--mode`-missing warnings from the build. 

Because of including HTML file & it's loader, we cannot limit us to default webpack configuration. We need a minimalistic config:
```js
// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.html$/i,
        loader: "html-loader",
      },
    ],
  },
};
```

where we tell wepback, to use `html-loader` for each file with path that ends in `.html`.

# Build
If all the files & installations are correct, we should be able to run the build and get the correct output to `dist`. The build should go more or less as:
```bash
$ npm run build

> webpack-5@1.0.0 build
> webpack --mode production

asset main.js 501 bytes [compared for emit] [minimized] (name: main)
orphan modules 749 bytes [orphan] 3 modules
./src/index.js + 3 modules 787 bytes [built] [code generated]
webpack 5.38.1 compiled successfully in 272 ms
```

# Links
* [webpack video course](https://bit.ly/WebpackCourse)

# Complete code & application example

If you want to see the application in action in the browser you can see it here:
https://marcin-wosinek.github.io/js-html-comparison-webpack-5/

and for the working code example you can go here:
https://github.com/marcin-wosinek/js-html-comparison-webpack-5

You can see other articles in this section, to see how the same application can be build with some of js bundlers.