DEV Community

Cover image for Clean up your HTML with ES6 Modules
Moussa
Moussa

Posted on • Edited on

Clean up your HTML with ES6 Modules

if you are that person who is working with the web regardless of the role how you doing it, maybe for your WordPress site, a simple static website or you are a backend or full-stack developer and working with Javascript inside HTML files with code in tags, so this post for you.

Modularity is one of the main factors of any solid software to make it more efficient, reusable, and maintainable. if you are coming from any programming language you probably know about modules or classes sharing ways import, module, use, #include etc.

But when it comes to JavaScript this language that written inside a <script> tag in HTML file bunch of people thinking about just doing the job making some animation or add a third-party plugin to the website with zero modularity consideration and crowdy HTML files, so let's get started! πŸ”₯

GIF

How HTML file looks

<body>
    <script>
        // function doAnimationForMe() {}
        // function doScrollToTopForMe()
    </script>
    <script>
        // function doFirebaseIntegrationForMe() {}
        // function danceWithMe()
    </script>
</body>
Enter fullscreen mode Exit fullscreen mode

let's focus on <body> content only, and imaging DRY some of these little functions on multiple HTML files and think about HTML file length one last imaging if you want to update something or doing another dance so yeah here we go and will work through all HTML pages again over and over.

GIF

Creating Javascript module

Yes, that's possible, js will not fight you, with newly introduced ES6 keywords import and export you can encapsulate the module. regardless of the other benefits of working with modules. so now we are just focused on making the HTML file more cleaner.

As example lets grap doAnimationForMe() from the HTML file, and create animation.js

const time = 1000

function start() { /* ..... */ }

function end() { /* ..... */ }

function doAnimationForMe() { 
  start()
  setTimeOut(function() {
    end();
  }, time)
}
Enter fullscreen mode Exit fullscreen mode

same code from the HTML file but in an isolated, manipulated, and reusable zone.

GIF

Modules Export and Import

Great its a time to making our pretty code modular ready. there are variant ways of export, default, named, and aggregation. let's find out. another feature of the module if we planning to use this doAnimationForMe() at another js files or only include this module to the HTML page that we can export all functions in the file or just doAnimationForMe() function only.

  • let's start with the Named export
export const time = 1000

export function start() { /* ..... */ }

export function end() { /* ..... */ }

export function doAnimationForMe() { 
  start()
  setTimeOut(function() {
    end()
  }, time)
}
Enter fullscreen mode Exit fullscreen mode

in this way all animation staff exported can be imported later. another tip if you plan to export multiple stuff from one module,

const time = 100

function start() { /* ..... */ }

function end() { /* ..... */ }

function doAnimationForMe() { 
  start()
  setTimeOut(function() {
    end()
  }, time)
}

export {start, end, doAnimationForMe}
// shorthand for {start: start, end: end, doAnimationForMe}
Enter fullscreen mode Exit fullscreen mode

also can export only doAnimationForMe() function and make the module more logical, just flag desired part by export or follow the export object tip.

// Code......
export {doAnimationForMe}
Enter fullscreen mode Exit fullscreen mode

Another tip: since we are talking about the named export we can also cast names, till now if we will import doAnimationForMe we have to use the same name doAnimationForMe or will cause an error. for rename exported part:

export {doAnimationForMe as useAnimation}
Enter fullscreen mode Exit fullscreen mode

let's create another pseudo module sample that gets data from API then applying some animation, for the whole picture drawing, creating an api.js file.

const url = '/api/item'

export function getAllItems() {
  return new Promise(function (resolve, reject) {
    fetch(url)
      .then(function (response) {
        resolve(response)
      })
      .catch(function (error) {
        reject(error)
      })
  })
}
Enter fullscreen mode Exit fullscreen mode

Module import and reuse

Yeah, let's have some fun and put it all together creating an app.js file.

import {doAnimationForMe} from './animation.js' // The relative path.
import {getAllItems} from './api.js' // The relative path.

// Another Code...
function renderUi(items) {
  // Render items in the ui
}

function handleError(err) {
  // Handle the error
  console.error(err)
}

getAllItems().then(function(data) {
  renderUi(data)
  doAnimationForMe()
}).catch(function(err) {
  handleError(err)
})

window.addEventListener('load', getAllItems())
Enter fullscreen mode Exit fullscreen mode

Adding Module into HTML page

it's the time to cleanup the HTML file and include only our encapsulated module, with only one line consider relative paths also :

<!DOCTYPE html>
<html>
<head>
    <!-- Code... -->
</head>
<body>
    <!-- Code... -->
    <script src="./app.js"></script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

The difference is clear now how clean it our HTML but, for the first time properly you will get a nice error!

Uncaught SyntaxError: Cannot use import statement outside a module
Enter fullscreen mode Exit fullscreen mode

GIF

Actually no. it's the trick not kidding but we have to include one last attribute to our script tag which is the type="module"

so after a little update, the code will look like this:

<script src="./app.js" type="module"></script>
Enter fullscreen mode Exit fullscreen mode

the error will go and now we can confirm that our modules all loaded into the HTML page by checking the network tab:

Network tab image

for further reading and it's very important also to check the browser compatibility for this feature with your project or the client devices.
JavaScript Modules -MDN

  • another way to doing the same job is default export there is no much difference but just in case you don't care about names and want to export some functionality from the module without a specific name in import, it also's good to avoid naming errors. let's see the same example but in default export.

animation.js

const time = 1000

function start() { /* ..... */ }

function end() { /* ..... */ }

export default function doAnimationForMe() { 
  start()
  setTimeOut(function() {
    end()
  }, time)
}
Enter fullscreen mode Exit fullscreen mode

api.js

const url = '/api/item'

function getAllItems() {
  return new Promise(function (resolve, reject) {
    fetch(url)
      .then(function (response) {
        resolve(response)
      })
      .catch(function (error) {
        reject(error)
      })
  })
}

export default getAllItems
// same but, in another way...
Enter fullscreen mode Exit fullscreen mode

the most interesting part here at import in app.js:

import doAnimation from './animation.js'
import kofta from './api.js'

// Another Code...
function renderUi(items) {
  // Render items in the ui
}

function handleError(err) {
  // Handle the error
  console.error(err)
}

kofta().then(function(data) {
  renderUi(data)
  doAnimation()
}).catch(function(err) {
  handleError(err)
})

window.addEventListener('load', getAllItems())
Enter fullscreen mode Exit fullscreen mode

that's will do the same job but in a simplified way.

GIF

Consolusion

The goal of this post is to simplify working with modules also encouraging you to write clean HTML pages focused only on markup, and keep JavaScript files isolated too like CSS with the benefit of modularity at the functionality code on your website. ES6 import and export also have a bunch of tips and tricks that's can make life easier also the third way mentioned before aggregation export. I just mentioned some basics.

Top comments (3)

Collapse
 
andreasvirkus profile image
ajv

Thanks for the article! Small typo - you didn't add type="module" to the "updated" script example, it still says

<script src="./app.js"></script>
Enter fullscreen mode Exit fullscreen mode

Even though I think you meant

<script src="./app.js" type="module"></script>
Enter fullscreen mode Exit fullscreen mode

πŸ‘‹

Collapse
 
muhammedmoussa profile image
Moussa

you are right, fixed. thanks for the feedback!

Collapse
 
camelcaseguy profile image
Shubhendra Singh Chauhan

A great blog @muhammedmoussa πŸ‘

We at DeepSource are also helping developers in improving their code quality. Do check our blogs here - dev.to/deepsource