Native esm in a simple html+js use case
Tags: javascript, webdev
Published: 2021-06-02 09:54:07

In this series, I'll take a look on a simple usecase of js+html application, build with various js bundlers. For a start, let's see what we can have without introducing any building tool.

# esModules support

As of 2021, we can see very good support of esModules across all the major browser. According to [can i use it](https://caniuse.com/es6-module) the only browser lagging behind are opera & uc browser for android. If we can afford not supporting users on those browsers, we can be tempted to use native es modules to build our application on the browser side.

# The application

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

The key features we use in this app set up are:
* single js to be included in the html
* app broken down into component(s), for better code organization
* separate file for component logic & template

There are other aspects that could be interesting to compare across builders, such as:
* importing npm modules
* compiling ts
* importing css in components
let me know if you are interested in seeing those, or any other features in various bundlers.

# Code

The html part is very straight forward:
```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>
```

the key part is to import js as a module - by adding `type="module"` to the `<script>` tag. If you fail to do it, all you will see will be error in the console:
```
Uncaught SyntaxError: import declarations may only appear at top level of a module
```

the main js file, is just one line:
```js
// ./scr/index.js
import "./contact-list/contact-list.js"; 
```

for a one-component application this is a bit over engineering, but in a more real word cases we will definitive want to break down application into multiple components. So here we make the example future proof, but preparing for more complicated set up.

# The component

The component is broken into three files. The main js file:
```js
// src/contact-list/contact-list.js
import { template } from "./contact-list.html.js";
import { contacts } from "./data.js";

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);

```

data file:
```js
// src/contact-list/data.js
export const contacts = [
  {
    name: "Christopher L Sanders",
    phone: "769-232-1807",
  },
  {
    name: "Frances J Nolte",
    phone: "901-287-0419",
  },
];
 
```

and template file:
```js
// src/contact-list/contact-list.html.js
export const template = `<h2 class="name">name</h2>

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

The main downside of using es modules alone, is that we are limited to js files only. It would be better to have data as a json file & template as html, but those cannot be imported with es module syntax. So we are force to tweak them to become js files, and we move them from main component file just to follow common pattern of keeping different aspects of a component in a separate files. We have no benefits of easy integration with tooling - prettier, linters, etc. - specific for each of the content types.

# 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-native-esm/

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

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