DEV Community

Marcin Wosinek
Marcin Wosinek

Posted on • Updated on


Native esm 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. 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 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

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.


The html part is very straight forward:

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

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

the main js file, is just one line:

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

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:

// 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 =;
  element.querySelector(".phone").innerHTML =;



Enter fullscreen mode Exit fullscreen mode

data file:

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

Enter fullscreen mode Exit fullscreen mode

and template file:

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

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

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:

and for the working code example you can go here:

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

Top comments (0)