import vs require - ESM & commonJs module differences

Mon Mar 13 2017

Paul Shan

ECMAScript Modules (ESM) are still in stage 3 (not finalized).

require import
Dynamic evaluation Static evaluation
Throws error at runtime Throws error while parsing
Non lexical Lexical

As Node.js uses commonJS moduling, I will refer to the workflow of node to address the commonJS modules. And will refer the ECMAScript modules as ESM.

Syntax difference

CommonJS

dep.js

dep = {
    foo: function(){},
    bar: 22
}
module.exports = dep;

app.js

var dep = require("dep");
console.log(dep.bar);
dep.foo();

ESM

dep.js

export foo function(){};
export const bar = 22;

app.js

import {foo, bar} from "dep";
console.log(bar);
foo();

Loading technique difference

What Node.js does with modules is, it wraps all the code inside a function scope. So the dep.js will look like below.

function (exports, require, module, __filename, __dirname) {
  const m = 1;
  module.exports.m = m;
}

So be it __filename, __dirname or module, they are not actually global but local to that particular module.

The actual loading of any module using require() happens in 5 steps.

  • Resolution
  • Loading
  • Wrapping
  • Evaluation
  • Caching

The first step resolution is an internal step where node.js calculates the file paths etc. In the second one, which is loading, node pulls the code in the ongoing process. In wrapping in wraps up the code in the function as shown above and then sends it to VM for evaluating and then eventually caches it.

So, basically node never knows what symbols a commonJS module is going to export until and unless the module is actually evaluated. And this is the biggest difference with ECMAScript modules, because ESM is lexical and thus, the exported symbols are known before the code is actually evaluated.

When an ESM module is parsed, then before it is evaluated by the VM, an internal structure called a Module Record is created. This module record keeps the list of exported symbols at the time of parsing. Thus, when you use import {f} from "foo", it actually creates a link between this f and the f which is there in module record’s symbols list (in case f is actually exported).
As a result, any error regarding the unavailability of mismatch of any exported symbol will raise an error before the evaluation.

import()

There is a proposal of import() function too to create nested import statements. Unlike the lexical import keyword, import() function is processed at the time or evaluation (more like require). The syntax is like the following.

import("foo").then((module) => {
    module.bar();
    console.log(module.someProp);
}).catch((err)=>{
    //handle error here
});

use cases

  • On demand module load is possible.
  • Conditional load of modules are also possible
  • Promise like asynchronous handling.

FAQ

Which has performance benefits?

As import is still in stage 3 and not implemented by browsers natively, we’re unable to run any performance test. Currently when you use import in your code, your transpilers transpile it back to require, the commonJS moduling system. So for the time being both are same.

Which one is better to use

Though there are no performance benefit at the moment, but I will still suggest to use import over require cause it’s going to be native in JS and may (just because it’s native) perform better than require.

SHARE THIS ARTICLE

post-thumbnail
Today everyone knows the importance of a lightning-fast website and how the speed impacts the conversion rate of a business. Today, everyone wants the site to be a PWA so that the mobile users can have an app-like experience with the website because, for the majority of the merchants, the customers come through mobile devices.
Tue Apr 20 2021
post-thumbnail
Here we are going to see how you can manage backup and restore of Postgres database with docker.
Thu Sep 03 2020
post-thumbnail
Image sliders or carousels always have increased the UI attraction of websites and they are pretty useful for reflecting the major roles/products too. In case, I am having a website that sells tee-shirts,
Mon Apr 30 2018

About VoidCanvas

This blog was created out of hobby and talks mostly about technology, web development, JavaScript, NodeJS and related topics. Thank you for reading my blog.

Copyright 2022 - www.voidcanvas.com

Popular Articles

Authentication using Google's oAuth api with node.js

Thu Mar 10 2016

OAuth authentications are pretty popular now a days and another thing which is popular is JavaScript. This article shows how to plugin google’s oAuth api for authentication in your own node application.

CSS3 Loader Snippet Collection: (Part 2 - Squares)

Sat Mar 01 2014

This is a continuation of my CSS3 loader snippet collection series. I've provided spinning css3 animation loader in the part 1 of this series and here in part 2, I'm providing various square type loading