Modern JavaScript

Best of Modern JavaScript — Modules in Browsers and Import/Export Relationship

Spread the love

Since 2015, JavaScript has improved immensely.

It’s much more pleasant to use it now than ever.

In this article, we’ll look at how to use JavaScript modules in browsers and the relationship between exports and imports.

ES6 Modules in Browsers

We can use ES6 modules in most modern browsers.

To use them, we just add a script tag with the type attribute set to module .

The file extension is still js like regular script files.

The content of the JavaScript file is delivered via the webserver.

ES6 modules in the browser combine to convenience by combining the syntax os synchronous loading with async loading underneath.

They’re less flexible than ES6 modules.

They can only be loaded at the top level so they can’t be conditional.

The restriction lets us analyze modules statically do see what modules are imported by other modules before execution.

Regular scripts can’t become modules because they’re synchronous.

We can’t import modules declaratively since they load one by one,

Therefore, a new type of script is added so we can load modules asynchronously.

To import a module in the browser, we can write:

<script type="module">
  import _ from "";

  console.log(_.uniq([1, 2, 2, 3]));

We import the ES6 module version of Lodash and used its methods.

The type attribute is set to module so we can import modules in our script.

Whether a JavaScript file is a module or a script is determined by where the code is written.

If we don’t have any exports or imports and use the file with a script tag without the type attribute set to module , then it’s a script.

Otherwise, it’s a module.

Imports’ Relationship with Exports

Imports’ relationship with exports different between module systems.

In CommonJS, imports are copies of exported value.

In ES6 modules, imports are read-only views of exports that updates as their values update.

For instance, if we have:


module.exports = {
  add(x, y) {
    return x + y;
  subtract(x, y) {
    return x - y;

Then we can import it by writing:

const { add, subtract } = require("./baz");

const sum = add(1, 2);
const difference = subtract(1, 2);

A copy of the module is made when we require a CommonJS module.

This also applies when we import the whole module as one object.

So if we have:

const baz = require("./baz");

const sum = baz.add(1, 2);
const difference = baz.subtract(1, 2);

then baz is a copy of the baz.js module.

On the other hand, ES6 module imports and read-only views on the exported values.

Imports are connected live to the exported data.

If we import the whole module, then the whole imported module acts like a frozen object.

For example, if we have:


export const add = (x, y) => {
  return x + y;

export const subtract = (x, y) => {
  return x - y;


import { add, subtract } from "./baz";

const sum = add(1, 2);
const difference = subtract(1, 2);

add and subtract are read-only.

If we try to reassign an imported member to something, we’ll get an error.

We get the same result if we import the whole module:

import * as baz from "./baz";

const sum = baz.add(1, 2);
const difference = baz.subtract(1, 2);

We can’t assign a new value to baz .


ES6 module imports are read-only views on exports.

Also, we can use modules in the browser.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *