Project Summary

We are delighted to share a blog written by student Yareny Castellanos from Abundant Life Christian School, who is part of a team delivering a Global Goals project for the 2019–20 Global Goals…

Smartphone

独家优惠奖金 100% 高达 1 BTC + 180 免费旋转




10 Points to consider when migrating CommonJS to ES modules in Node

CommonJS modules have served the Node.js community well since its inception. In the meantime, JavaScript rose to dominate the browser alongside a plethora of frameworks and libraries. And with that success came the need for tools and an even greater desire to evolve the language.

A new official module standard, ECMAScript modules (or ES modules for short) was introduced. While the frontend ecosystem quickly embraced it, Node already had a stable and functional module system in CommonJS.

It wasn’t until Node 14 that we got the first LTS release where ES modules were stable. You can just add { “type”: “module” } to package.json in your next project and use ES modules. But what about existing projects? Is it just a syntax change or are there more nuanced differences? Continue reading to get a taste of what to expect when migrating an existing project and the effort involved!

Why would you choose to migrate then? What benefits will you enjoy or what new features will become available? When considering the benefits that apply to server-side Node projects, the major selling points are the unified syntax (with the frontend code) and the top-level await.

Whether these are reasons enough or not is something that only each developer and team can answer by themselves, at least until there is a clear direction and preference in the Node community.

Perhaps your team works full-stack and would love a unified syntax. Or you are a library maintainer who worries about its usage in frontend projects. Maybe you have existing services written with Express where CommonJS is working perfectly fine.

Take a moment to research the current state and decide for yourself.

The good news are that you can import a CommonJS module. The bad news are that you cannot require() an ES module. And that’s just the beginning before you consider the different import/export semantics

There are good reasons behind these rules and limitations. The top-level await support in ES modules means import is inherently async, while in CommonJS require() is a synchronous operation. This is what prevents require()to work with ES modules!

Another outcome of the interoperability rules is that you really want to avoid mixing CommonJS and ES modules on the same project. It can be hard to do so anyway. The moment you start introducing ES modules, it will spread like a virus if you are not careful. Module A is converted as ES module, which forces you to convert consumer module B, which in turn forces you to convert module C, etc.

It is possible to start from the outer layers of your app, so at least have control over the migration pace. However the rules are confusing enough that you want to continue until you have migrated the rest of the codebase.

You are probably very used to writing require()statements like:

However note the equivalent with ES import:

When importing relative files with ES modules, the .js extension is mandatory. That means importing your project code will require the file extension, while importing node modules or built-in modules won’t.

Another surprise if you have ever loaded a JSON file into a variable using a simple require()call.

For example, get your project’s version by loading the package.json file:

These 2 variables are available inside any CommonJS and contain the directory and file name of the current module. They are not available in ES modules, where instead you have a URL in import.meta.url.

Let’s say you had code like:

With ES modules it turns into:

With require() you could dynamically import any module, since require is just a function. For example, consider the function loadPlugin:

We cannot dynamically import a module using the import from syntax, but we can use the import() function. The caveat is that import() is an async function, which will convert the loadPlugin function into an async function. remember the support for top-level await? This is another consequence!

Now you will need to consider all the places in your code that call the loadPluginfunction. Each of them needs to be updated to either handle a returned promise, or to use async/await.

Sometimes you manipulate a module imported with require() in the same line that it gets imported.

This is less conveniently expressed with ES import, requiring an intermediate identifier:

Another common pattern is to directly pass the result of a require() call into another function:

When converted to ES import we also need to introduce an intermediate identifier:

If you use eslint in a project with {"type": "module"} and define the rules in a .eslintrc.js file, you will observe the following error:

To fix this problem, rename the file as .eslintrc.cjs to tell Node this is a CommonJS file. (and use CommonJS module.exports inside the file!)

At least mocha and prettier support ES modules out of the box!

If you have a project of which you are the final consumer, like a website or service that you build and deploy, then it’s fully up to you to decide if you want to migrate from CommonJS to ES modules. No other developers will try to import your code and run into compatibility issues due to the interoperability rules between the 2 module systems.

However consider maintainers of a library whose users might be both CommonJS and ES module users. They have 3 options:

If you are considering to migrate a project, hopefully you will find these points helpful. At least it should be clear that the migration is not as straightforward as you might initially expect.

Happy coding!

Add a comment

Related posts:

Political Swoosh

People are lighting their Nike shoes on fire because Colin Kaepernick is featured in a new ad for the brand. Is this a news story or simply a desperate plight for attention? Well, if we look back a…

Who can register on ContyAds?

ContyAds is an advertising platform with new functionality. At ContyAds, you can make money by watching advertisements or buy quality advertisement. Contyads is really an amazing site because you can…

Pandas and AI Lead the Way to the Beijing 2022 Winter Olympics

The Pyeongchang 2018 Winter Olympics’ closing ceremony on Sunday was capped by a spectacular eight-minute presentation from 2022 host Beijing that featured state-of-the-art robotics and AI…