First, why modularity

In the past, without modularity, we might have divided modules as follows: importing files with

<script src="module1.js"></script>
<script src="module2.js"></script>
<script src="module3.js"></script>
Copy the code

If modularized in this way, it is easy to create global variable conflicts as the project gets larger and larger, and the project becomes more and more difficult to manage.

So we need to find a way to help us modularize, and what are the benefits of modularization? Specifically, it mainly includes the following aspects:

  1. Reduce global variable pollution
  2. Control dependence
  3. Enhance the maintainability of code
  4. Increase code reuse
  5. The practice of divide and conquer

Second, the status quo of modular standards

1. CommonJS

specification

  1. Module identification should follow certain writing rules.
  2. Defining global functionsrequire(dependency)To introduce other dependent modules by passing in the module identifier, and the result is the API exposed by other modules.
  3. If the module introduced by the require function also contains external dependencies, those dependencies are loaded in turn.
  4. If importing a module fails, the require function should throw an exception.
  5. The module exposes the API through the exports variable. Exports can only be an Object Object, and the exposed API must be a property of that Object.

use

Export module:

// math.js
var num = 0;
function add(a, b) {
  return a + b;
}
module.exports = {
  num: num,
  add: add
}
Copy the code

Loading modules:

// When importing a custom module, the argument contains the path and can omit.js
Var HTTP = require(" HTTP ");
var math = require('./math');
math.add(1.2)/ / 3
Copy the code

advantages

  1. Simple and easy to use
  2. Resolved module dependency issues
  3. Global variable pollution is reduced

disadvantages

  1. Cannot be used on the browser side
  2. You cannot load multiple modules in parallel without blocking

2. AMD (Async Module Definition)

RequireJS

specification

  1. Module Identifiers follow CommonJS Module Identifiers.
  2. Defining global functionsdefine(id, dependencies, factory)Is used to define a module. Dependencies are an array of modules that depend on each other.
  3. If the value of Dependencies contains require, exports, or Module, it is consistent with the implementation in CommonJS.
  4. If dependencies are omitted, they default to [‘require’, ‘exports’, ‘module’].
  5. If factory is a function, a module can expose the API in one of three ways: return any type;Exports. XModule = XModule, module.exports = XModule.
  6. If Factory is an object, that object is the exported value of the module.

use

Define modules:

  • An independent module
define({
    method1: function() {},
    method2: function() {}});// The return value of the function is the output module
define(function () {
    return {
        method1: function() {},
        method2: function() {}}; });Copy the code
  • Modules with dependencies
define(['module1'.'module2'].function(m1, m2) {... });// Module1 and module2 refer to the module1.js file and module2.js file in the current directory, which are equivalent to ['./module1', './module2'].
Copy the code

Note that the callback must return an object, which is the module you defined.

Call module:

require(['foo'.'bar'].function ( foo, bar ) {
        foo.doSomething();
});
Copy the code

advantages

  1. Can be used in browsers
  2. Asynchronous loading module
  3. Multiple modules can be loaded in parallel

disadvantages

  1. Increased development costs
  2. Instead of loading on demand, all dependencies are loaded ahead of time

RequireJS has been deprecated since 2.0.

3. CMD (Common Module Definition)

CMD is the standardized output of module definition in the promotion process of Sea-js, which belongs to a specification of CommonJS.

use

Define modules:

define(function (require.exports.module) {
  var add = function (a, b) {
    return a + b;
  }
  exports.add = add;
})
Copy the code

Use modules:

seajs.use(['math.js'].function (math) {
  var sum = math.add(1.2);
});
Copy the code

advantages

  1. The modular loading of the browser is realized
  2. It can be loaded on demand
  3. Rely on proximity and delay execution

disadvantages

  1. Rely on SPM packaging, module loading logic is biased

4. UMD (Universal Module Definition)

UMD is a common JavaScript module definition specification that allows your modules to function in all JavaScript runtime environments.

The provisions are as follows:

  1. Whether there is an exports method is preferred. If there is, CommonJS is used to load modules.
  2. Secondly, determine whether there is define method. If there is, load the module in AMD mode.
  3. Finally, determine whether the required dependencies are defined on the global object. If so, use them directly. Otherwise, an exception is thrown.

5. ES Module

use

Export module:

/ / export
export function hello() {};export default {
  // ...
};
Copy the code

Introduction module:

import { readFile } from 'fs';
import React from 'react';
Copy the code

advantages

  1. Syntax level support, easy to use

disadvantages

  1. The browser is not fully compatible and must be converted to standard ES5 by tools

Browser support

Three, the evolution history of modularity

Back in 2009, Mozilla engineer Kevin Dangoor and his colleagues created a set of JsaveScript modular standards called ServerJS. ServerJS was originally used on the server side to provide modular import functionality in automated test work. Later ServerJS was renamed CommonJS.

In September of the same year, Ryan Dahl created Node.js without package management tools, and then NPM (Node Package Manager) using the CommonJS specification was born. With the rapid development of Node.js, the CommonJS specification has gradually entered the vision of the majority of front-end developers. So far, JavaScript the first modular specification, also officially logged in the historical stage.

With the popularity of NPM, front-end developers are looking to incorporate this modular approach into their daily development efforts. However, CommonJS can only be used on the server side, so the specification will need to be reformulated. At this point, there are three main schools of thought about how to develop new standards:

Conservative:

CommonJS has been successfully applied to the server, so before the browser loads the module, we use the tool to convert the module into code that the browser can execute. The idea is similar to that of tools like Babel today, which convert older versions of code into older versions of code, all for compatibility. Browserify is a product of this idea.

Radicals:

The browser is very different from the server, so we should abandon the require approach and use fallback to introduce modules according to the browser’s characteristics. Change synchronously loaded modules to asynchronously loaded modules.

The centre:

CommonJS specifications such as require have some merit. We can also introduce some good features, such as exports that export more types than objects, while keeping as close to the existing CommonJS specification as possible.

Respective progress:

Radicals:

The RequireJS module loader was developed in 2009 by James Burke, an activist. In 2011, based on RequireJS community, AMD (Async Module Definition) community was born. AMD was the first browser-side Javascript modular solution, RequireJS was quickly recognized and adopted by developers.

The centre:

In the middle, the story is more complicated. Wes Garland, one of the main contributors to CommonJS, gave an implementation called BravoJS. Wes Garland himself is an academic with strong theoretical foundation, but his works are not very practical. Another hands-on guru proposed the Modules/Wrappings solution and gave an implementation called FlyScript. The two had a bit of a dispute over the implementation and ended up with FlyScript’s GitHub repository being deleted.

In April 2011, Yu Bo, the front-end boss of Alibaba, wrote a module loader sea-.js by himself after referring to the schemes of AMD and CommonJS, and proposed the CMD specification at the same time, because his suggestions to RequireJS were constantly rejected. The main content of the CMD specification is similar to THAT of AMD, but retains the lazy loading and nearby declaration features of CommonJS.

UMD:

In September 2014, Chinese-American Homa Wong submitted the code for the first version of UMD. UMD, which stands for Universal Module Definition, is not really a modular solution per se, but rather a combination of CommonJS and AMD.

ES the Module:

In May 2016, ECMAScript 6.0 was officially adopted as an international standard after two years of discussion. In this standard, the JavaScript keywords import and export are introduced for the first time, and a modular solution called ES Module is provided. In September 2017, Chrome version 61.0 included support for ES Module on the browser side for the first time. Many browsers already support ES Module natively. With the rise of ES Module came building tools like Vite.