DEV Community

Marcin Wosinek
Marcin Wosinek

Posted on

Parcel 2 in a simple html+js use case

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.

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:
Alt Text

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:

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

The app

application screenshot

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:

<!-- 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>
Enter fullscreen mode Exit fullscreen mode

Main js file:

// src/index.js
import "./contact-list/contact-list";
Enter fullscreen mode Exit fullscreen mode

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:

// 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);
Enter fullscreen mode Exit fullscreen mode

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:

<!-- src/contact-list/contact-list.html -->
<h2 class="name">name</h2>

<p class="phone">phone</p>
Enter fullscreen mode Exit fullscreen mode

As in most other bundlers JSON files are understood by parcel by default. src/contact-list/data.json, the data file:

[
  {
    "name": "Christopher L Sanders",
    "phone": "769-232-1807"
  },
  {
    "name": "Frances J Nolte",
    "phone": "901-287-0419"
  }
]
Enter fullscreen mode Exit fullscreen mode

Build dependencies & configuration

For a successful build of the above code, we just need parcel package. To install it, you can run:

$  npm install -D parcel@next
Enter fullscreen mode Exit fullscreen mode

as they recommend in the doc.

For easy access to build script, you can add following line to package.json:

  "scripts": {
    // other scripts
    "build": "parcel build ./index.html --public-url ./"
  }
Enter fullscreen mode Exit fullscreen mode

./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:

$ 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
Enter fullscreen mode Exit fullscreen mode

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

Top comments (0)