Module system in javascript


brief introduction

A long time ago, js existed simply as an interactive operation of the browser. It is generally a very short script, so it exists independently.

However, with the development of modern browsers, especially the emergence of nodejs, js can do more and more complex things. So we need a module system to organize scripts for different purposes and make logical distinction and reference.

Today we will introduce the module system in js.

CommonJS and Nodejs

CommonJS was proposed by Mozilla in January 2009. Yes, it's the company of Firefox.

The original name was ServerJS. In August 2009, it was renamed CommonJS to show the universality of this standard.

The main application of CommonJS is nodejs on the server side. The browser side does not directly support CommonJS. If you want to use it on the browser side, you need to convert it.

CommonJS uses require() to introduce modules, and uses module Exports to export the module.

Let's take an example of CommonJS:

exports.doStuff = function() {}; 
module.exports = someValue;

Note that CommonJS is loaded synchronously.

AMD asynchronous module loading

AMD's full name is Asynchronous Module Definition. It provides a mode of loading modules asynchronously.

AMD is the standardized output of RequireJS for module definition in the promotion process.

The advantage of asynchronous loading is that it can be loaded when the module needs to be used, which reduces the time of loading all at once. Especially on the browser side, it can improve the user experience.

See the definition of AMD loading module:

 define(id?, dependencies?, factory);

AMD defines and loads dependent modules through define.

Where id represents the name of the module to be defined, dependencies represents the dependent module of the module, and factory is a function used to initialize the module or object.

Let's take an example:

   define("alpha", ["require", "exports", "beta"], function (require, exports, beta) {
       exports.verb = function() {
           return beta.verb();
           return require("beta").verb();

In this example, we define an alpha module, which needs to rely on "require", "exports" and "beta".

And the verb method of the beta module is exported in the factory.

The dependencies in both define and define must not be:

//No id
  define(["alpha"], function (alpha) {
       return {
         verb: function(){
           return alpha.verb() + 2;

//No dependency
     add: function(x, y){
       return x + y;

We can even use CommonJS in AMD:

   define(function (require, exports, module) {
     var a = require('a'),
         b = require('b');

     exports.action = function () {};

After definition, AMD uses require to load the module:

require([dependencies], function(){});

The first parameter is the dependent module, and the second parameter is the callback function, which will be called after the previous dependent modules are loaded. The loaded modules will be passed into the function in the form of parameters, so that these modules can be used inside the callback function.

require(["module", "../file"], function(module, file) { /* ... */ }); 

The require loading module is loaded asynchronously, but the subsequent callback function will only run after all modules are loaded.


CMD is the standardized output of module definition in the promotion process of SeaJS. Its full name is Common Module Definition.

CMD also uses define to define modules. CMD advocates a file as a module:

define(id?, deps?, factory)

It looks very similar to AMD's define, which has id, dependent module and factory.

The factory here is a function with three parameters, function(require, exports, module)

We can load the modules to be used through require in the factory, and export the exposed modules through exports. Module represents the current module.

Let's take an example:

// Define module mymodule js
define(function(require, exports, module) {
  var $ = require('jquery.js')

// Loading module
seajs.use(['myModule.js'], function(my){


Therefore, to sum up, the difference between AMD and CMD is that for the dependent modules to be loaded in front of AMD, the dependent modules must be declared when defining the modules.

CMD does not execute after loading a dependent module, but only downloads it. It uses require only when it is used.

ES modules and modern browsers

ES6 and modern browsers support modularization through import and export.

First, let's take a look at the support of import and export in the browser:

First, let's take a look at how to export the variables or methods to be exposed using export:

export const name = 'square';

export function draw(ctx, length, x, y, color) {
  ctx.fillStyle = color;
  ctx.fillRect(x, y, length, length);

  return {
    length: length,
    x: x,
    y: y,
    color: color

Basically, we can use export to export var, let, const variables or function or even class. The premise is that these variables or functions are at the top level.

A simpler way is to put all the to be export ed on one line:

export { name, draw, reportArea, reportPerimeter };

There are actually two ways to export, named and default. The export in the above example is in named format because they all have their own names.

Here's how to export the default values using export:

// export feature declared earlier as default
export { myFunction as default };

// export individual features as default
export default function () { ... } 
export default class { .. }

named can export multiple objects, while default can export only one object.

After exporting, we can use import to import:

import { name, draw, reportArea, reportPerimeter } from './modules/square.js';

If default is selected when exporting, we can use any name when import ing:

// file test.js
let k; export default k = 12;

// some other file
import m from './test'; // Because default is exported, we can use import m to import it here
console.log(m);        // will log 12

We can use import and export in a module to import from different modules, and then export in the same module, so that third-party programs only need to import this module.

export { default as function1,
         function2 } from 'bar.js';

The above export from is equivalent to:

import { default as function1,
         function2 } from 'bar.js';
export { function1, function2 };

In the above example, we need to import function1 and function2 respectively to use them. In fact, we can use all imports as the attributes of the Module object in the following way:

import * as Module from './modules/module.js';


Then function1 and function2 become the attributes of Module, which can be used directly.

Using module in HTML and problems needing attention

How to introduce module into HTML? We have two ways. The first is to use the src option:

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

The second method is to put the contents of the module directly into the script tag.

<script type="module">
  /* JavaScript module code here */

Note that the type of both script tags is module.

When using script to load module s, the default is defer, so there is no need to add the defer attribute.

If you use file: / / to load local files during testing, you are likely to get a CORS error because of the security requirements of JS module.

Finally, import() can also be used as a function to dynamically load modules:

squareBtn.addEventListener('click', () => {
  import('./modules/square.js').then((Module) => {
    let square1 = new Module.Square(myCanvas.ctx, myCanvas.listId, 50, 50, 100, 'blue');

Author: what about the flybean program

Link to this article:

Source of this article: flybean's blog

Welcome to my official account: the most popular interpretation of "those things", the most profound dry cargo, the most concise tutorial, and many small tricks you don't know, etc. you'll find them!

Tags: Javascript node.js

Posted by akimm on Thu, 14 Apr 2022 23:04:54 +0930