DEV Community

SeongKuk Han
SeongKuk Han

Posted on

How to import and export in CommonJS and ES Modules

How to import and export in CommonJS and ES Modules

There are good articles out there to understand what they are and their differences. Here are the links that I read.
Before diving into code right away, I recommend you read these articles.


CommonJS

Basic Usage

[aboutme.js]



const person = {
  name: "Lico",
  role: "Frontend Engineer",
};

function printName() {
  console.log(person.name);
}

function printRole() {
  console.log(person.role);
}

module.exports = {
  person,
  printName,
  printRole,
};


Enter fullscreen mode Exit fullscreen mode

[main.js]



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

aboutme.printName();
aboutme.person.name = "lico!";
aboutme.printName();


Enter fullscreen mode Exit fullscreen mode

result

You can change the variables that imported from other modules, but do not encourage to do.


Named Import



const { printName, printRole } = require("./aboutme");

printName();
printRole();


Enter fullscreen mode Exit fullscreen mode

You can import it with Destructuring assignment.

result

Of course, if you do not export functions, you can't import the functions.

+ You can export anything instead of object

[aboutme.js]



const person = {
  name: "Lico",
  role: "Frontend Engineer",
};

function printName() {
  console.log(person.name);
}

function printRole() {
  console.log(person.role);
}

module.exports = {
  // person,
  // printName,
  printRole,
};


Enter fullscreen mode Exit fullscreen mode

[main.js]



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

console.log(aboutme);


Enter fullscreen mode Exit fullscreen mode

result


ES Modules

To use ES Modules, I added this line into package.json.



{
  ...
  "type": "module"
  ...
}


Enter fullscreen mode Exit fullscreen mode

Basic Usage



const person = {
  name: "Lico",
  role: "Frontend Engineer",
};

function printName() {
  console.log(person.name);
}

function printRole() {
  console.log(person.role);
}

export default {
  person,
  printName,
  printRole,
};


Enter fullscreen mode Exit fullscreen mode


import aboutme from "./aboutme.js";

aboutme.printName();
aboutme.person.name = "lico!";
aboutme.printName();


Enter fullscreen mode Exit fullscreen mode

It's very similar to CommonJS. You are also able to change the exported variables.


Named Import



import { printRole } from "./aboutme.js";

printRole();


Enter fullscreen mode Exit fullscreen mode

It is going to occur an error like below.



SyntaxError: The requested module './aboutme.js' does not provide an export named 'printRole'


Enter fullscreen mode Exit fullscreen mode

To use named import, you must export the functions.



export function printRole() {
  console.log(person.role);
}


Enter fullscreen mode Exit fullscreen mode

The error would be gone. you can export multiple functions and variables with only one export keyword instead of put export in front of every functions and variables that you want to export.



const person = {
  name: "Lico",
  role: "Frontend Engineer",
};

function printName() {
  console.log(person.name);
}

function printRole() {
  console.log(person.role);
}

export { person, printName, printRole };

export default {
  person,
  printName,
  printRole,
};


Enter fullscreen mode Exit fullscreen mode

And you are able to import with name.



import { printRole, printName } from "./aboutme.js";

printRole();
printName();


Enter fullscreen mode Exit fullscreen mode

You also can use default and Named Import both together and you can use as keyword to rename them.



import aboutme, { printRole as role } from "./aboutme.js";

console.log(aboutme);
aboutme.printName();
role();


Enter fullscreen mode Exit fullscreen mode

result


Import with the Asterisk

[aboutme.js]



const person = {
  name: "Lico",
  role: "Frontend Engineer",
};

function printName() {
  console.log(person.name);
}

function printRole() {
  console.log(person.role);
}

export { person, printName, printRole };

export default {
  person,
  printName,
};


Enter fullscreen mode Exit fullscreen mode

[main.js]



import * as aboutme from "./aboutme.js";

console.log(aboutme);


Enter fullscreen mode Exit fullscreen mode

result

You see default. That is the object which is exported using export default.


Import a module which uses CommonJS as a module system from ES Modules

Project Folder Structure

[lib/aboutme.js]



const person = {
  name: "Lico",
  role: "Frontend Engineer",
};

function printName() {
  console.log(person.name);
}

function printRole() {
  console.log(person.role);
}

module.exports = {
  person,
  printName,
  printRole,
};


Enter fullscreen mode Exit fullscreen mode

[main.js]



import aboutme, { person, printName, printRole } from "./lib/aboutme.js";

console.log(person);
console.log(printName);
console.log(printRole);
console.log(aboutme);


Enter fullscreen mode Exit fullscreen mode

result

You can use default and Named Import.

[main.js]



import * as aboutme from "./lib/aboutme.js";

console.log(aboutme);


Enter fullscreen mode Exit fullscreen mode

result

As you see, there are default and exported functions and a variable.

You cannot import a module which uses ES Modules as a module system from CommonJS. If you try it, you will see like this error. (With a bundler, it will be working)

error


I hope you found it useful.
Enjoy your coding!

Top comments (3)

Collapse
 
aklietz profile image
Alan Klietz

Importing ES modules into CommonJS can be tricky, but I figured out a way to do it. For example, Node 18 introduced top-level fetch. I wanted to implement a polyfill for Node 16 to fall back to using the ES module node-fetch.

I wanted to do import * as fetch from 'node-fetch', but CommonJS does not support it. So instead I implemented it like this:

var fetch = globalThis.fetch ??
    ((...args) => import('node-fetch').then(
        ({ default: _fetch} ) => _fetch(...args))
    );
Enter fullscreen mode Exit fullscreen mode

The lets me invoke fetch in a CommonJS module in both Node 16 and Node 18: fetch('https://foo.com/do_something').then(...) . Node 18 uses the native top-level fetch, while Node 16 falls back to the ES module node-fetch.

The idiom works for any ES module that exports an object that returns a then-able function.

Collapse
 
grants profile image
Qihao

Very helpful! Could you show me the content of package.json file in your last example project ?

Collapse
 
lico profile image
SeongKuk Han

I couldn't find the project, so, I've reproduced it.
They should be like the followings.

[package.json]

{
  "name": "js-module"
}
Enter fullscreen mode Exit fullscreen mode

[lib/package.json]

{
  "name": "lib",
  "type": "module"
}
Enter fullscreen mode Exit fullscreen mode