Understanding ES Modules in Javascript

栏目: IT技术 · 发布时间: 4年前

Understanding ES Modules in Javascript

How to use ES Modules to import Javascript modules statically or dynamically.

Understanding ES Modules in Javascript

Jun 11 ·8min read

Understanding ES Modules in Javascript

Photo by La-Rel Easter on Unsplash

Modules are found in every programming language. It is a way to include functionality in one code with another. These modules are where a developer can create code with specific functionality that can be reused elsewhere. Modules provide you with benefits such as code reusability and code that can be split into several chunks.

If you had been working with JavaScript before sometimes back, you would have come to know that JavaScript did not have modules as such. Developers resorted to using HTML <script> tags in order to load JavaScript files into their applications. Later on, several module definition formats started to surface.

  • CommonJS — the module.exports and require syntax used in Node.js
  • Asynchronous Module Definition (AMD)
  • Universal Module Definition (UMD)
  • ES Modules

Let us see why modules are needed in the first place.

Why Do We Need Modules

When you think about how programs work, all they do is manage variables. They assign values to variables, modify them, combine two variables together, etc. But when the number of variables increases with the size of your application, it can be cumbersome to manage them and maintain your code.

The solution to this was to have only a few variables that you should be worried about. JavaScript's way of achieving this was called scope . Because of how scopes work in JavaScript, functions can’t access variables that are defined in other functions.

Although this allows your variables to be inaccessible by other functions, it gave rise to another issue — it was hard for you to share variables between different functions. A common way of overcoming this and sharing variables out of scope was to put them on a scope above such as the global scope.

Although this approach worked, it came with problems. Your script tags should be in the correct order and you must make sure that no one changes that order. If the order does change, your app will throw an error. This made code management tricky. You never know what might break what. Any function can grab anything on the global, so you do not know which functions depend on which scripts.

Another issue was that every part of the code that’s inside of that global scope can change the variable. This would allow malicious and non-malicious code to access and even modify your global variables with or without malicious intent.

And then modules were introduced to help overcome these issues.

How Do Modules Make Things Better

Modules allow you to organize and manage variables and functions better. Usually, functions and variables that are apart of the same functionality are put together in a module. This puts these variables into the module scope. The module scope can be used to share variables between the functions in the module.

Understanding ES Modules in Javascript

Illustration by Lin Clark

This also allows for variables to be available for other modules as well. They can explicitly say which variable, class or function should be available to outsider modules. This is called export . Once you have an export, other modules can explicitly say that they depend on that variable, class or function. Due to this explicit relationship, you will know which modules will break if you remove one.

Once you are able to import and export variables and functions, it is easier for you to split and break up your code into chunks of code that can work independently. You can later build your application by using these modules, similar to building with Lego blocks.

In order to achieve this super useful feature, there have been multiple attempts to add module functionality with JavaScript.

Existing Module Systems

CommonJS

CommonJS is what has been used in NodeJS historically. With Node, you get CommonJS module.exports and require out of the box. However, unlike Node, the browser doesn’t support CommonJS. Moreover, CommonJS loads modules synchronously and therefore it is not an optimal solution for browsers. You can use bundlers such as Webpack or Browserify to overcome this problem.

//    filename: bar.js

//    dependencies
var $ = require('jquery');

//    methods
function myFunction(){};

//    exposed public method (single)
module.exports = myFunction;

Asynchronous Module Definition (AMD)

AMD was born out of a group of developers who did not like the direction of CommonJS. In fact, AMD was split from CommonJS early in its development. The main difference between AMD and CommonJS is that AMD loads modules asynchronously. This was very much popular in browsers as startup times are essential to good user experience.

//    filename: bar.jsdefine(['jquery'], function ($) {
    //    methods
    function myFunction(){};

    //    exposed public methods
    return myFunction;
});

Universal Module Definition (UMD)

As CommonJS and AMD were quite popular in their respective domains, there was a need for a “universal” pattern that supports both styles. But as it turns out, UMD was messy and ugly. Although it did support both AMD and CommonJS, as well as supporting the old-style “global” variable definition.

What are ES Modules

As you can clearly see, JavaScript lacked one proper standard module definition format. Hence a single, native module standard was therefore proposed in ES6.

The static nature of the import and export directive allows static analyzers to build a full tree of dependencies without running code.

The result is syntactically pleasing and compatible with both synchronous and asynchronous modes of operation in the browser. ES modules have quickly become available in the browser, but in Node.js it was a bit harder to come up with a solution that is backward-compatible and enables incremental upgrades. In Node.js native ES modules are available behind the experimental-modules flag for a long time.

The following is an example for ES6 modules.

JavaScript

//------ library.js ------
export const sqrt = Math.sqrt;
export function square(x) {
    return x * x;
}
export function diagonal(x, y) {
    return sqrt(square(x) + square(y));
}//------ main.js ------
import { square, diagonal } from 'library';
console.log(square(13)); // 169
console.log(diagonal(12, 5)); // 13
const app = document.getElementById("app");
app.innerHTML = "<h1>Demo App for ES Modules</h1>";const input = document.getElementById("num");
input.addEventListener("change",displaySquare);function displaySquare(){
 var sqrOutput = document.getElementById("sqr");
 sqrOutput.value = square(input.value);
}

HTML

<HTML>
<head>
<title>ES Modules Demo</title>
</head>
<body>
<script type="module" src="./main.js" ></script>
<div id="app"></div>
<label>Input</label>
<input id="num" type="number" placeholder="Enter number here"/>
<br>
<label>Output</label>
<input id="sqr" type="number" disabled/>
</body>
</HTML>

As you can see above in the HTML file, you need to specify type="module" in the script tag for the browser to treat it as an ECMAScript module.

Backwards Compatibility

For backwards compatibility, you can include nomodule in the script tag (where the JS file loaded is single bundled file). Browsers with ES Modules support will know to ignore that. This solution will work even in the oldest of browsers. Willem’s answer has explained this very well.

In the above scenario, we will include something like this in our HTML.

<script type="module" src="./main.js" >
</script>
<script nomodule src="./fallback.js" >
</script>

Note:

If you are testing this locally, you will need to run this on a server as you will run into CORS issues. Read more here

.

Modules are imported with either absolute or Relative references and must start with either “/”, “./”, or “../”.

Dynamic Imports

The latest ES2020 version does come with dynamic imports . To dynamically import modules, the import keyword may be called as a function. When used this way, it returns a promise.

import('/modules/library.js')
  .then((module) => {
    // Do something with the module.
  });//or using await
let module = await import('/modules/library.js');

ES Modules Browser Compatibility

The use of native modules in the browser depends on the import and export statements, the browser compatibility of which is as follows.

Understanding ES Modules in Javascript

Screenshot of MDN Docs

Understanding ES Modules in Javascript

Screenshot of MDN Docs

Should You Choose ES Modules?

For browsers, ES modules are the new standard. With asynchronous module loading out of the box, you can expect faster startup times for better performance. Although you can use CommonJS with some additional plugins in the browser, it is highly advised that you switch to ES modules as they are native in browsers.

ES native modules allow you to get individual modules loaded rather than a single bundle file. This is quite useful and it reduces the size of the data loaded. Browser compatibility for native modules is also important as it decides whether native ES modules will be implemented or whether we will fallback to our module bundler which will load a single bundle file.

One of the issues, when you get a single bundle file, is that when your applications become bigger, the size of the bundle js file will also increase and thereby affecting startup time and performance. You can avoid this by using code splitting which is a feature available in modern bundlers such as webpack.

But there might be instances where we would opt for a module bundler such as webpack over ES modules. If you have assets such as CSS, images, fonts and even data files such as XML, CSV, you might want to opt for a webpack solution as webpack provides asset bundling.

You also should take into account the support for HTTP2 in browsers. When you use native modules, your browser will load those modules individually. But rather than sending several HTTP requests, with the help of HTTP2, we can serve multiple requests simultaneously with a single connection. 96.49% of browsers use HTTP2 according to CanIUse .

But when you are developing an application that should cater even the remaining 3.51%, then you might want to switch to webpack. This is because your application would need to send several HTTP requests to load each individual modules if you stick with native ES modules.

In Node, things are quite different. As the feature is still flagged as experimental, it is better that you stick with CommonJS. You can still give ES modules a try though .

You can check out the source code for the above example over here .

You can also check out the live demo over here .

I hope you understood what ES modules are, and why they are needed. If you have any comments, feel free to drop them below.

Happy Coding!!


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

连线力

连线力

杨国斌 / 邓燕华 / 广西师范大学出版社 / 2013-9 / 39.00

《连线力》,最关切我们未来的“思想@网络.中国”丛书之一,互联网中国传媒参考书。 中国网民在行动。在中国的广大网民中,普遍存在着对正义的渴望和追求,对弱者和小人物的同情, 对贪官污吏的痛恶,对政府的失望, 对权贵的嘲讽,对沟通的渴望,甚至对革命的呼唤。这些因素有着共同的内在逻辑,即情感逻辑。在这个意义上,情感汹涌的网络事件,是整个中国社会情感结构的脉络。 1994年,中国开通了全功能的......一起来看看 《连线力》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具