Parcel 2 in a simple html+js use case
Published: 2021-06-09 19:52:44

In this series, I'll take a look on a simple usecase of js+html application, build with various js bundlers. This time, it's time for [parcel v2](https://v2.parceljs.org/).

# Parcel
Similar to webpack & rollup, parcel is a complete, stand alone bundling solution. It has very reasonable default configuration, and it's trying to cover all uses cases - from basic js, json, css to typescript, scss or even coffee script. 

Very interesting is it's approach to installation - the main package covers the most basic cases. As our project starts using some features that lives in a separate modules, the missing modules are installed automatically. So we have best of both approaches - smaller installation without headache of adding additional modules manually.

The popularity metrics are kind of confusing. On one hand, when one checks [npm trends](https://www.npmtrends.com/parcel-vs-rollup-vs-webpack-vs-parcel-bundler):
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u48ho1a3k2d6vfx4o359.png)

Parcel is dwarfed by both webpack & rollup in npm downloads, but nicely between them in github stars. 

At the same time, according to other metric - number of students on the most popular udemy course, parcel performs pretty well:
* [webpack 12k+](https://bit.ly/2TgIDQY) 
* [parcel 3000+](https://bit.ly/3pCBq9I)

It's definitely much more popular that it seems based on npm downloads alone.

# 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 main html file, defines entry points of the application. Each value used in `<script src>` or `<link href>` will be compiled by parcel. I like this approach, and I remember how confused I was when was starting using webpack and had to set up config & repeat all files used in `index.html`. Parcel's  approach is definitively more beginner friendly, and it's important because we all are beginners in some things.

Parcel will start with any file we provide to the build script. Let's follow the convention and put:
```html
<!-- index.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="./src/index.js"></script>
    <link rel="stylesheet" href="./style.css" />
  </head>
  <body></body>
</html>
```

Main js file:

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

# The component

The component is broken down into 3 files - so code, template & data goes to best matching code type - JS, HTML & JSON.

Main component file:
```js
// src/contact-list/contact-list.js
import template from "bundle-text:./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);
```

Similar like in snowpack or vite, we have to tweak how we import the html files - in this case, by prefixing the file location with `bundle-text:`. I take two things out of it:
* I'm spoiled by very flexible import in webpack
* importing raw html templates is not as common in the broader world as in the cases I'm used to.

It could cause problems only if you change the blunder - which most likely you will not do often.

The html file we import:
```html
<!-- src/contact-list/contact-list.html -->
<h2 class="name">name</h2>

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

As in most other bundlers JSON files are understood by parcel 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"
  }
]
```

# Build dependencies & configuration
For a successful build of the above code, we just need `parcel` package. To install it, you can run:
```bash
$  npm install -D parcel@next
```

as they recommend in the doc.

For easy access to build script, you can add following line to `package.json`:
``` js
  "scripts": {
    // other scripts
    "build": "parcel build ./index.html --public-url ./"
  }
```

`./index.html` tells parcel where to start buidling our files. `--public-url ./` is needed to make the build output usable on no-top-level-folder of the domain where we deploy it. The assumption of buidling for top level folder is the same what they have in vite. I don't see any benefit of doing it this ways, besides saving 1 character in the output html. Likely it's easy to override.

If all were set up correctly, the build will pass:
```bash
$ npm run build

> parcel-2@1.0.0 build
> parcel build ./index.html --public-url ./

✨ Built in 267ms

dist/index.html            271 B    40ms
dist/index.60e80ddc.js     577 B    46ms
dist/index.43c1311e.css    288 B    48ms
```

# 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-parcel-2/dist/

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