First, what is modularity, is to package independent function code into an independent file, other modules need to use, in reference.

Modularity is good for code splitting and architectural decoupling. Modularity has long been mature in the server world, and NodeJS already supports it.

On the browser, JS scripts are loaded asynchronously and executed in sequence according to the encoding order. Dependencies can only be controlled according to the encoding order. So the front end has a modular technology early, but wake up every day the front end is more than a noun more than a framework, the development is really rapid, there are several kinds of front-end modular accumulation over the years, we take a look.

commonjs

Start with the CommonJS specification that comes with NodeJS. The CommonJS specification applies to NodeJS applications. In nodeJS applications, each file is a module and has its own scope. Variables and functions in the file are private and isolated from other files.

The CommonJS specification states that within each module, the module variable represents the current module. This variable is an object whose exports property (module.exports) is the interface to the outside world. Loading a module loads the module.exports property of that module. (Quoting teacher Ruan Yifeng’s description)

For example, how to write a modularized file

// util\index.js
let name = 'now';
let age = 18;

let fun = (a)= > {
    console.log('into fun');
    name = 'change'
}

module.exports = {
    name,
    fun
}
console.log(module)

// appJsBridge\index.js
var { name, fun } = require('./util/index.js')

Copy the code

The above documents, there are two variables, a function, through the module. Exports expose variable name and function fun, this variable age is private, external can’t directly access, if you want to let the age variable global can access, you can change to be global. Age = 18, But this contaminates the global scope and can lead to unexpected surprises.

Let’s look at the module printed out by util\index.js

Module has these attributes

Module. id The module’s identifier, usually the module’s file name with an absolute path. Module. filename specifies the filename of the module, with an absolute path. Module. loaded Returns a Boolean value indicating whether the module has completed loading. Module. parent returns a module object representing the module that called the module. If the module is not referenced, parent is null module.children returns an array of modules representing other modules used by the module. Module. exports indicates the value that the module exports. Module. paths This is used by require to find the location of the file.

Module. exports is used in development. The output of module. Exports is the required value

require

Module. Exports exports have the equivalent require import, as follows

Var {name, fun, object} = require(‘./util/index.js’) //

The require command looks for module files in different paths, depending on the format of the argument.

  1. If the argument string begins with a slash, it means that a module file is loaded in an absolute path. For example, require(‘/home/ Marco /foo.js’) will load /home/marco/foo.js.

  2. If the argument string begins with a “./ “, it means that a module file is loaded in a relative path (compared to where the script is currently executing). For example, require(‘./circle’) will load circ.js in the same directory as the current script.

  3. If the parameter string does not start with a “./ “or”/”, it indicates that either a core module provided by default (in Node’s system installation directory) or an installed module (global or local) in each node_modules directory is being loaded. Paths, remember module.paths, where this comes in handy. Script, for example, / home/user/projects/foo js performed the require (‘ bar. Js) command, the Node is on the basis of the module. The paths path and file name, search in turn. This is designed so that different modules can localize their dependencies.

  4. If the argument string does not start with a “./ “or”/” and is a path, such as require(‘example-module/path/to/file’), the location of example-module will be found first, and then the subsequent path will be found using it as an argument.

  5. If the specified module file is not found, Node will try to add.js,.json, and.node to the file name before searching. .js files are parsed as text JavaScript script files,.json files are parsed as json text files, and.node files are parsed as compiled binary files. Therefore, the suffix of the file name can be omitted.

  6. To get the exact filename of the require command to load, use the require.resolve() method.

The module exports and exports

Exports can also be exported for direct use, but it needs to be noted that exports are defined constants and cannot be defined when exported, as follows

let exports = module.exports // error #region exports Identifier 'exports' has already been declared
exports = module.exports; / / correct
Copy the code

Exports can be exported in this way, but it is important to note that you cannot change the direction of exports before exporting. If you change exports, it is not the same as module.exports.

exports = module.exports
// exports = ()=>{
exports.fun = (a)= > {
    console.log('into fun');
    name = 'change'
}
exports.name = 'now';
// exports = ()=>{
Copy the code

Exports alone is no different from module.exports. I recommend using Module. exports as it is the normal and safe way to write it.

Isolation,

The CommonJS specification is loaded at runtime, and objects are exported at runtime. The exported objects are isolated from the objects in the original module, which is simply a clone. Look at this chestnut down here

// util\index.js
let object = {
    age: 10
}
let fun = function() {
    console.log('modules obj', object);
    object = { age: 99}}module.exports = {
    fun,
    object
}

// index.js
var { name, fun, object } = require('./util/index.js')
console.log('before fun', object)
fun()
console.log('end fun', object)
Copy the code

Execute node index.js to see the print

before fun { age: 10 }
modules obj { age: 10 }
end fun { age: 10 }
Copy the code

The reference calls the fun method, which changes the object in the module. The fun method does not change the object exported in index.js, so it can be seen that the exported module under the CommonJS specification is a deep clone.

Use the CommonJS specification Browserify in the browser

Module exports require Global is missing in the browser, so you can’t use commonJS directly in the browser. Browserify is a common commonJS conversion tool. It can be used with gulp Webpack. Take a look at browserify’s code, and you’ve captured some of the key parts.

I’ve copied the core code, which looks like this: Browserify gives each module a unique ID and maps the module ID through the module path to find each module. ,

The code in the original module is wrapped in a function with three arguments: require Module exports, which loads other modules, and exports, which exports objects.

!function e(t, n, r) {
    function s(o, u) {
        if(! n[o]) {if(! t[o]) {var a = "function"= =typeof require && require;
                if(! u && a)return a(o, !0);
                if (i)
                    return i(o, !0);
                var f = new Error("Cannot find module '" + o + "'");
                throw f.code = "MODULE_NOT_FOUND",
                f
            }
            var l = n[o] = {
                exports: {}}; t[o][0].call(l.exports, function(e) {
                var n = t[o][1][e];
                return s(n || e)
            }, l, l.exports, e, t, n, r)
        }
        return n[o].exports
    }
    for (var i = "function"= =typeof require && require, o = 0; o < r.length; o++)
        s(r[o]);
    return s
}({
    1: [function(require, module, exports) {
        "use strict"}, {"babel-runtime/helpers/classCallCheck": 2},3.4]},
    2: [function(require, module, exports) {
        "use strict";
        exports.__esModule = !0,
        exports["default"] = function(instance, Constructor) {
            if(! (instanceinstanceof Constructor))
                throw new TypeError("Cannot call a class as a function"}},{}]},{},[])Copy the code

ES6 modular

ECMA launched the official standard modular solution, using export to export, import to import, simple coding, semantics more accessible.

Modules that support asynchronous loading of modules in ES6 are not objects, but are referenced at compile time, so they are loaded at compile time.

Personally, ES6 modular is the future mainstream.

Or the chestnuts above, with ES6 modular rewrite, changes are not big, a few key words can be modified

// util/index.js
let name = 'now';

let fun = (a)= > {
    name = 'change'
}

export {
    name,
    fun
}
// app.js
import { name, fun } from ".. /util";
console.log('before fun', object)
fun()
console.log('end fun', object)
Copy the code

Use in the browser

However, ES6 modularity is not well supported in browsers, and most browsers still don’t support it, so it needs to be converted

  1. Instead of using Webpack and using build flow tools like gulp, we need to use Babel to convert ES6 to ES5 syntax

Using the Babel transform, write in the Babel configuration file.babelrc

{
"presets": ["es2015"]}Copy the code

Use Browserify to convert the module specification.

  1. If you use Webpack, webpack supports ES6 modularity, so just reference babel-loader, es6 syntax processing can be done

An export of a module is a reference to an object

An export under ES6 modularity is a reference to an object, let’s look at the following chestnut

// util/index.js
let name = 'now';

let fun = (a)= > {
    name = 'change';
}
let getName = function() {
    console.log('module:',name)
}

export {
    name,
    fun,
    getName
}
// app.js
import { name, fun, getName } from ".. /util";
console.log("before fun:", name);
fun();
console.log("after fun:", name);
name = "change again";
getName();
Copy the code

Let’s look at the output

before fun: now
after fun: change
module: change
Copy the code

As you can see, functions inside a module change the objects inside the module, and the objects used by the external export also change. This is the biggest difference from the CommonJS specification. This feature can be used for state raising.

ES6 module specification and commonJS specification operating mechanism difference

The CommonJS module is run time loaded, and the ES6 module is compile time output interface

  • Runtime loading: CommonJS modules are objects; That is, the entire module is loaded on input, an object is generated, and methods are read from that object. This loading is called “runtime loading.”

  • Compile-time loading: ES6 modules are not objects, but are output code explicitly specified through the export command and static commands when importing. That is, when you import, you can specify that an output value is loaded instead of the entire module, which is called “compile-time loading.”

CommonJS loads an object (that is, the module.exports property) that is generated only after the script runs. An ES6 module is not an object, and its external interface is a static definition that is generated during the code static parsing phase.

AMD – the require. Js and CMD – sea. Js

Both AMD and CMD specifications are related to require.js and sea.js, which were developed a few years ago to solve the problem of browsers loading modules asynchronously. With the development of packaging tools, commonJS and ES6 will now run in browsers, so AMD and CMD will be replaced.

Modularity of the AMD specification: use require.config() to specify reference paths, etc., define modules with define(), and load modules with require().

Modularity of the CMD specification: define modules with define(), seajs.use references modules.

The specific introduction can see this one, write very detailed.

Module compatibility processing

We may need to support various modules when we develop plug-ins, so we can handle that

const appJsBridge = function(){};
if ("function"= = =typeof define) {
    // AMD CMD
    define(function() {
        returnappJsBridge; })}else if ("undefined"! =typeof exports) {
    // commonjs
    module.exports = appJsBridge;
} else {
    // No modularity
    window.appJsBridge = appJsBridge;
}
Copy the code

Refer to the link

Javascript.ruanyifeng.com/nodejs/modu… www.ruanyifeng.com/blog/2015/0… Juejin. Cn/post / 684490…