Everything You Don't Know About ES Modules

Everything You Don't Know About ES Modules

ยท

5 min read

Before I get into how you don't know ES modules, let's review what you know about ES modules. Let's get started with default exports and imports.

// bar.js

export default () => "Bar!";
// foo.js

import Bar from "./bar";

const Foo = `Foo${Bar()}`;

You are importing a default value which can be renamed to anything easily. Now let's move on to named exports and imports.

// bar.js

export const Bar = () => "Bar!";
// foo.js

import { Bar } from "./bar";

const Foo = `Foo${Bar()}`

So what's going on is we are assigning the named export Bar to that function, which is then being imported by the exact same name which allows static optimizations such as ES6 tree shaking.

Now let's quickly go over importing from packages.

// foo.js

import { Bar } from "foo-bar";

const Foo = `Foo${Bar()}`;

You install a package from NPM and then import it by it's name. Now let me reset everything you know about ES modules and explain what they actually are.

Actual ES modules

Actual ES modules have only two big changes from the ES modules you know:

  1. You have to include extensions
  2. You import 3rd-party libraries from URLs

Let's go over the first one. You have to include extensions in imports. Why? Because it is possible that you are using an extensions other than .js and then the browser would have to loop over every possible extension and then send a request for it to see if it exists.

Now let's go over the second one. You import 3rd--party libraries from URLs and not from NPM package name. This is how it works because the web is meant to be decentralized, with a single package registry like NPM, if it was taken down the entire web could fall. Instead, modules are loading from URLs, so you could use something like skypack.dev to convert NPM packages to use actual ES modules syntax. But where did this fake ES modules syntax come from?

Node Module Resolution Algorithm

Let's go back to when NodeJS was created in 2006. It was 10 years before ES modules where created in 2016, and they had to create a module format for NodeJS.

They created what is now known as CommonJS. CommonJS has synchronous dynamic imports and exports. CommonJS also imports from NPM and the node_modules folder if it is not a relative path and CommonJS doesn't use extensions for importing. Older bundlers such as Webpack 1 used CommonJS for bundling.

Then came ES6 and ES modules. At that time, native ES modules weren't that supported so sites started using bundlers which can create code that is compatible with browsers that don't support ES modules. These bundlers started using what is known as the Node Module Resolution Algorithm, where it follows all the rules of resolving imports w/o extensions and importing from the node_modules folder.

Wrapping Up

Let me just say this. I am not trying to say that you should use native browser ES and you shouldn't use bundlers and stuff like that. I am just trying to point out that the ES modules that you probably use aren't the actual specification.

  1. What is ES6 Tree Shaking?
  2. List of JS Bundlers ๐Ÿš€