Loading an ES6 module in a CommonJS module using require()

By: (plus.google.com) +David Herron; Date: February 16, 2018

Tags: Node.JS » JavaScript

ES6 modules are a nifty new way to write modules. They're rather similar to the CommonJS module format traditionally used by Node.js, but there are significant differences. At the current time (Node.js 9.5) an ES6 module can load a CommonJS module using import, but a CommonJS module cannot load an ES6 module. The core problem is one of semantics and capabilities - ES6 modules behave and work differently enough that the Node.js require function can't use them directly. Which raises a big problem with integrating ES6 modules into the Node.js ecosystem that is dominated by CommonJS modules.

First, how do you use an ES6 module in Node.js? The current release (Node.js 9.5) makes it easy. Simply run the Node.js program with the --experimental-modules flag as so:

$ node --experimental-modules ./module-name
(node:5813) ExperimentalWarning: The ESM module loader is experimental.
... module output

With that option enabled you can use the .mjs extension (e.g. module-name.mjs) to identify ES6 Modules. You may see that extension referred to as Michael Jackson Script (.mjs). Such files are interpreted by the Node.js runtime as ES6 Modules, and regular .js modules are interpreted by the CommonJS semantics we've used with Node.js all along.

The default rules for loading modules are:

  • An ES6 Module can load other ES6 modules using import
  • An ES6 Module can load CommonJS using import
  • A CommonJS module can load other CommonJS modules using require
  • A CommonJS module CANNOT load an ES6 Module

That's the gap we're looking to solve - that CommonJS modules cannot load ES6 Modules.

The example I faced recently had to do with writing a Mocha test suite for an application written using ES6 modules. Mocha tests must be written using CommonJS semantics. Therefore testing ES6 modules requires somehow loading those modules in a CommonJS module. Well, that's if we want to keep using Mocha. Maybe it's time to write a new test framework based on ES6 modules?

Generally speaking the Node.js community has a large body of code written with CommonJS modules. It's not feasible to do what I just flippantly said and toss all that CommonJS code and immediately rewrite the world in the ES6 Module format. Instead what's needed is a solution to load ES6 modules in a CommonJS/Node.js module.

Module loading review

To review CommonJS ... a module is loaded as so:

const TheModule = require('module-specifier');

There are well-known rules for the module-specifier in the Node.js documentation. For exammple, ./foo loads a module in the current directory, whereas foogrep loads a module from the node_modules directory.

ES6 modules load other ES6 modules as so:

import * as TheModule from `es6-module-specifier`;

That's the basic mode, there are several alternatives available.

And an ES6 module loads CommonJS modules as so:

import TheModule from `module-specifier`;

In both cases the module-specifier uses the same rules for locating the module as Node.js supports in the require function.

The reason for using .mjs versus .js for different module formats is that the semantics are different. ES6 modules have a structure that's known by the language - export and import are now keywords in JavaScript. Further, their content is loaded asynchronously. Contrarily, Node.js modules are not baked into the language but instead require is a function provided by Node.js. And, exporting values from a Node.js/CommonJS module is similarly a code convention rather than a language feature.

Those differences create a situation where - at the current stage of things - Node.js could not automatically account for ES6 modules in a file with the .js extension. That resulted in the two extensions, .mjs and .js, as well as the rules matrix above.

Problem identified - look for solution

Enabling ES6 module support in Node.js CommonJS modules is as simple as putting this at the top of each module:

require = require("@std/esm")(module,{"esm":"js"});

The (www.npmjs.com) @std/esm supports using ES6 modules in Node.js separately from the --experimental-modules flag. Unlike that flag which was introduced in Node.js 9.x, the @std/esm team says their module supports Node.js 4.x and later.

You'll notice that what happens is the require function is being replaced. Therefore this line must appear BEFORE all other module loading activities, AND it has to be loaded in every module which desires to load ES6 modules.

Once you've done this, a CommonJS/Node.js module can load an ES6 module as so:

const TheModule = require(`es6-module-specifier`);

The object assigned to TheModule is the default export of the ES6 module. Other exports of the module are available as TheModule.exportName as you might expect.

That the @std/esm module makes this possible indicates it's within the power of the Node.js team to fix the problem. It seems they are working on the issue but it won't be ready for the upcoming Node.js 10.x release. It will be a minor miracle just getting ES6 module support into the platform.

« Deploying an Express app with HTTPS support in Docker using Lets Encrypt SSL Deploy Node.js application using Passenger on Dreamhost or other hosting providers »
2016 Election 2018 Elections Acer C720 Ad block Air Filters Air Quality Air Quality Monitoring AkashaCMS Amazon Amazon Kindle Amazon Web Services America Amiga and Jon Pertwee Android Anti-Fascism AntiVirus Software Apple Apple Hardware History Apple iPhone Apple iPhone Hardware April 1st Arduino ARM Compilation Artificial Intelligence Astronomy Astrophotography Asynchronous Programming Authoritarianism Automated Social Posting AWS DynamoDB AWS Lambda Ayo.JS Bells Law Big Brother Big Data Big Finish Big Science Bitcoin Mining Black Holes Blade Runner Blockchain Blogger Blogging Books Botnets Cassette Tapes Cellphones China China Manufacturing Christopher Eccleston Chrome Chrome Apps Chromebook Chromebox ChromeOS CIA CitiCards Citizen Journalism Civil Liberties Climate Change Clinton Cluster Computing Command Line Tools Comment Systems Computer Accessories Computer Hardware Computer Repair Computers Conservatives Cross Compilation Crouton Cryptocurrency Curiosity Rover Currencies Cyber Security Cybermen Cybersecurity Daleks Darth Vader Data backup Data Formats Data Storage Database Database Backup Databases David Tenant DDoS Botnet Department of Defense Department of Justice Detect Adblocker Developers Editors Digital Nomad Digital Photography Diskless Booting Disqus DIY DIY Repair DNP3 Do it yourself Docker Docker MAMP Docker Swarm Doctor Who Doctor Who Paradox Doctor Who Review Drobo Drupal Drupal Themes DVD E-Books E-Readers Early Computers eGPU Election Hacks Electric Bicycles Electric Vehicles Electron Eliminating Jobs for Human Emdebian Encabulators Energy Efficiency Enterprise Node EPUB ESP8266 Ethical Curation Eurovision Event Driven Asynchronous Express Face Recognition Facebook Fake News Fedora VirtualBox Fifth Doctor File transfer without iTunes FireFly Flash Flickr Fraud Freedom of Speech Front-end Development G Suite Gallifrey Gig Economy git Github GitKraken Gitlab GMAIL Google Google Chrome Google Gnome Google+ Government Spying Great Britain Green Transportation Hate Speech Heat Loss Hibernate High Technology Hoax Science Home Automation HTTP Security HTTPS Human ID I2C Protocol Image Analysis Image Conversion Image Processing ImageMagick In-memory Computing InfluxDB Infrared Thermometers Insulation Internet Internet Advertising Internet Law Internet of Things Internet Policy Internet Privacy iOS iOS Devices iPad iPhone iPhone hacking Iron Man iShowU Audio Capture iTunes Janet Fielding Java JavaFX JavaScript JavaScript Injection JDBC John Simms Journalism Joyent Kaspersky Labs Kext Kindle Kindle Marketplace Large Hadron Collider Lets Encrypt LibreOffice Linux Linux Hints Linux Single Board Computers Logging Mac Mini Mac OS Mac OS X MacBook Pro Machine Learning Machine Readable ID Macintosh macOS macOS High Sierra macOS Kext MacOS X setup Make Money Online Make Money with Gigs March For Our Lives MariaDB Mars Mass Violence Matt Lucas MEADS Anti-Missile Mercurial MERN Stack Michele Gomez Micro Apartments Microsoft Military AI Military Hardware Minification Minimized CSS Minimized HTML Minimized JavaScript Missy Mobile Applications Mobile Computers MODBUS Mondas Monetary System MongoDB Mongoose Monty Python MQTT Music Player Music Streaming MySQL NanoPi Nardole NASA Net Neutrality Network Attached Storage Node Web Development Node.js Node.js Database Node.js Performance Node.js Testing Node.JS Web Development Node.x North Korea npm NVIDIA NY Times Online advertising Online Community Online Fraud Online Journalism Online Photography Online Video Open Media Vault Open Source Open Source and Patents Open Source Governance Open Source Licenses Open Source Software OpenAPI OpenJDK OpenVPN Palmtop PDA Patrick Troughton PayPal Paywalls Personal Flight Peter Capaldi Peter Davison Phishing Photography PHP Plex Plex Media Server Political Protest Politics Postal Service Power Control President Trump Privacy Private E-mail server Production use Public Violence Raspberry Pi Raspberry Pi 3 Raspberry Pi Zero ReactJS Recaptcha Recycling Refurbished Computers Remote Desktop Removable Storage Republicans Retro Computing Retro-Technology Reviews RFID Rich Internet Applications Right to Repair River Song Robotics Robots Rocket Ships RSS News Readers rsync Russia Russia Troll Factory Russian Hacking Rust SCADA Scheme Science Fiction SD Cards Search Engine Ranking Season 1 Season 10 Season 11 Security Security Cameras Server-side JavaScript Serverless Framework Servers Shell Scripts Silence Simsimi Skype SmugMug Social Media Social Media Networks Social Media Warfare Social Network Management Social Networks Software Development Software Patents Space Flight Space Ship Reuse Space Ships SpaceX Spear Phishing Spring Spring Boot Spy Satellites SQLite3 SSD Drives SSD upgrade SSH SSH Key SSL Stand For Truth Strange Parts Swagger Synchronizing Files Tegan Jovanka Telescopes Terrorism The Cybermen The Daleks The Master Time-Series Database Tom Baker Torchwood Total Information Awareness Trump Trump Administration Trump Campaign Twitter Ubuntu Udemy UDOO US Department of Defense Video editing Virtual Private Networks VirtualBox VLC VNC VOIP Vue.js Walmart Weapons Systems Web Applications Web Developer Resources Web Development Web Development Tools Web Marketing Webpack Website Advertising Weeping Angels WhatsApp William Hartnell Window Insulation Windows Windows Alternatives Wordpress World Wide Web Yahoo YouTube YouTube Monetization