[Nodejs] nodejs modular specification: CommonJS

insert image description here

1 Introduction


The website is becoming more and more complex, and there are more and more js codes and js files, and some problems will be encountered:

  • file dependencies
  • Global pollution, naming conflicts

Program modularity includes:

  • date module
  • Mathematical Calculation Module
  • log module
  • login authentication module
  • Report display module, etc.

All these modules together make up the program software system.
Writing once and using many times is the core of improving efficiency.

2. Modular understanding


2.1 What is modularity

Concept: Encapsulate a complex program into several blocks (files) according to certain rules (standards) and combine them together.

The internal data and implementation of the module are private, and only some interfaces (methods) are exposed to the outside to communicate with other external modules.

At the earliest time, we would write all the codes in a js file, then the coupling would be high (strong correlation), which is not conducive to maintenance; and it would cause global pollution, and it would be easy to name conflicts.

2.2 Benefits of Modularity

Avoid naming conflicts, reduce namespace pollution
, reduce coupling; better separation, on-demand loading
High reusability: codes are easy to reuse, modules developed by others can be used directly, and similar functions do not need to be developed repeatedly.
High maintainability: The longest stage in the software statement cycle is actually not the development stage, but the maintenance stage, where requirements change frequently. Using modular development, the way is easier to maintain.
Easy to deploy

3. Modular specification


3.1 Introduction of modular specification

Suppose we introduce modularization, the first idea that may come to mind is: introduce multiple js files in one file. as follows:

<body>
    <script src="zepto.js"></script>
    <script src="fastClick.js"></script>
    <script src="util/login.js"></script>
    <script src="util/base.js"></script>
    <script src="util/city.js"></script>
</body>

But doing so creates a lot of problems:

  • Too many requests: If ten js files are introduced, there will be ten http requests.
  • Fuzzy dependencies: Different js files may depend on each other, if one of the files is changed, another file may report an error.

The above two points eventually lead to: difficult to maintain. Thus, this introduces the modular specification.

3.2 Interpretation of the concept of modularization

Modularity originated in Node.js. In Node.js, many js are packaged into packages, and when needed, they are called directly through require (CommonJS), which is the way of modularization.

So how to apply this modular thinking to the front end? This leads to two great js: RequireJS and SeaJS.

3.3 Modular specification

Server-side specification:

  • CommonJS specification : is the modular specification used by Node.js.
    – CommonJS is a set of convention standards, not a technology. A structure used to agree on what our code should be.

  • Browser-side specification:
    AMD specification : It is the standardized output of RequireJS's modular definition during the promotion process.
    – Load modules asynchronously;
    – Pre-dependency and early execution: require([ foo, bar],function(foo,bar){}); //That is to say, require all packages successfully, and then continue to execute the code.
    – define defines a module: define([ require, foo],function(){return});

  • CMD Specification : It is the standardized output of SeaJS's modular definition during the promotion process. Developed by Taobao team.
    同步加载模块; 依赖就近,延迟执行:require(./a) 直接引入。或者Require.async 异步引入。 //依赖就近:执行到这一部分的时候,再去加载对应的文件。 define 定义模块, export 导出:define(function(require, export, module){});
    PS: During the interview, the difference between AMD and CMD is often asked.
    In addition, there is the ES6 specification: import & export. In this article, we'll talk about CommonJS, the modular specification used by Node.js.

4. The basic syntax of CommonJS


4.1 Introduction to CommonJS

CommonJS: is the modularization specification used by Node.js. In other words, Node.js is written based on the modular specification of CommonJS.

The CommonJS specification stipulates: Inside each module, the module variable represents the current module. This variable is an object, and its exports attribute (ie module.exports) is an external interface object. Loading a module is actually loading the module.exports object of the module.

In CommonJS, each file can be considered a module:

On the server side: modules are loaded synchronously at runtime.
On the browser side: Modules need to be compiled and packaged in advance. First of all, since it is synchronous, it is easy to cause blocking; second, the browser does not understand the require syntax, so it needs to be compiled and packaged in advance.

4.2 Exposure and introduction of modules

There is only module-level scope in Node.js. The variables and methods between two modules do not conflict with each other by default, and do not affect each other. This leads to a problem: how does module A use the variables & methods in module B? This needs to be achieved through the exports keyword.

In Node.js, each module has an exports interface object, we can mount public variables and methods to this interface object, and other modules can use it.

Next, I will talk about the exposure of modules and the introduction of modules in detail.

(1) The first way to expose the module: exports
exportsthe object is used to export the public methods or properties of the current module. When other modules requirecall the current module through the function, what they get is exportsthe object of the current module.

Grammar format:

// 相当于是:给 exports 对象添加属性
exports.xxx = value

The value can be of any data type.

Note: The exposed keyword is exports, not export. In fact, the exports here are similar to the usage of export in ES6, which is used to export an object with a specified name.

Code example:

const name = 'qianguyihao';

const foo = function (value) {
    
    
	return value * 2;
};

exports.name = name;
exports.foo = foo;

(2) The second way of exposing the module: module.exports
module.exportsit is used to export a default object without specifying the object name.

Grammar format:

// 方式一:导出整个 exports 对象
module.exports = value;

// 方式二:给 exports 对象添加属性
module.exports.xxx = value;

The value can be of any data type.

Code example:

// 方式1
module.exports = {
    
    
    name: '我是 module1',
    foo(){
    
    
        console.log(this.name);
    }
}
// 我们不能再继续写 module.exports = value2。因为重新赋值,会把 exports 对象 之前的赋值覆盖掉。

// 方式2
const age = 28;
module.exports.age = age;

module.exportsIt is also possible to modify the original exported object of the module. For example, the current module originally exported an object, we can modify it to export a function through module.exports. as follows:

module.exports = function () {
    
    
    console.log('hello world')
}

4.3 The difference between exports and module.exports

The most important difference:

  • When using exports, you can only set the property exports.a = a single;
  • When using module.exports, you can set the property module.exports.a individually, or you can assign module.exports = obj as a whole.

Other points:

  • At the end of each module in Node, it will be executed return: module.exports.
  • Each module in Node will assign the object pointed to by module.exports to a variable exports, that is to say exports = module.exports.
  • module.exports = XXX, indicating that the current module exports a single member, and the result is XXX.
  • Must be used if multiple members need to be exported exports.add = XXX; exports.foo = XXX. or use module.exports.add = XXX; module.export.foo = XXX.

4.4 Question: Who exactly is the exposed module?

Answer: The essence of exposure is exportsthe object. ★★★★★

For example, method 1 exports.a = acan be understood as adding attributes to the exports object. The second method module.exports = acan be understood as assigning a value to the entire exports object. The second method module.exports.c = ccan be understood as adding attributes to the exports object.

Each module in Node.js has a module object, and an exports attribute in the module object is called an interface object. We need to mount the common methods or properties between modules in this interface object for the convenience of other modules.

4.5 Ways to import modules: require

The require function is used to import a module into another module. Pass in the module name and return the module export object.

Grammar format:

const module1 = require('模块名');

explain:

  • Built-in module: require is the package name.
  • Downloaded third-party modules: require is the package name.
  • Custom module: require is the file path. The file path can be either an absolute path or a relative path. The suffix .js can be omitted.

Code example:

const module1 = require('./main.js');
const module2 = require('./main');
const module3 = require('Demo/src/main.js');

The two functions of the require() function:

  • Execute the code in the imported module.
  • Return the interface object in the imported module.

4.6 Main module

The main module is the entry point for the execution of the entire program and can schedule other modules.

# 运行main.js启动程序。此时,main.js就是主模块
$ node main.js

4.7 Module initialization

The JS code in a module is only executed once when the module is used for the first time, and is initialized during use, and then cached for subsequent use.

Code example:
(1) calModule.js:

var a = 1;

function add () {
    
    
  return ++a;
}

exports.add = add;

(2) main.js: (introduce hello.js module in main.js)

var addModule1 = require('./calModule')
var addModule2 = require('./calModule')

console.log(addModule1.add());
console.log(addModule2.add());

Execute the node main.js running program on the command line and print the result:

2
3

As can be seen from the printed results, although the module calModule.js is referenced twice, it is only initialized once.

5.commonjs-Example of server-side implementation


(1)module1.js:

//暴露方式一:module.exports = value
//暴露一个对象出去
module.exports = {
    
    
    name: '我是 module1',
    foo(){
    
    
        console.log(this.name);
    }
}
//我们不能再继续写 module.exports = xxx。因为重新赋值,会把之前的赋值覆盖掉。

(2)module2.js:

//暴露方式一:module.exports = value
//暴露一个函数出去
module.exports = function(){
    
    
    console.log('我是 module2');
}

Note that the exports object exposed at this time is equivalent to the entire function.

(3)module3.js:

//暴露方式二:exports.xxx = value
//可以往 export 对象中不断地添加属性,进行暴露
exports.foo1 = function(){
    
    
    console.log('module3 中的 foo1 方法');
}
exports.foo2 = function(){
    
    
    console.log('module3 中的 foo2 方法');
}
exports.arr = [1,1,2,2,3,5,11];

(4) app.js: (bring together other modules into the main module)

//将其他模块汇集到主模块

let uniq = require('uniq'); //引入时,第三方模块要放在自定义模块的上面

let module1 = require('./modules/module1');
let module2 = require('./modules/module2');
let module3 = require('./modules/module3');

//调用module1对象的方法
module1.foo();

//调用module2的函数
module2();  //注意,在定义时,module2对象等价于整个函数function。所以,module2()的意思是,直接调用了函数。

//调用module3中的属性
module3.foo1();
module3.foo2();

uniq(module3.arr); //将module3中的数组进行去重操作
console.log(module3.arr); //打印数组去重后的结果

In this case, our code is finished.

We can run the code by typing node app.js on the command line. The printed results are as follows:

我是 module1
我是 module2
module3 中的 foo1 方法
module3 中的 foo2 方法
[ 1, 11, 2, 3, 5 ]

6. Commonjs-Browser-based Implementation Example


6.1 Initialize the project

Create the following directories and files in the project file:

    dist //打包生成文件的目录
    src //源码所在的目录
      | module1.js
      | module2.js
      | module3.js
      | app.js //应用主源文件
index.html    //因为CommonJS是基于浏览器端,js文件要跑在浏览器的页面上,所以要有这个html页面

Then create the following command in the root directory:

  npm init

Then follow the prompts and enter the following in sequence:

  • Package name: You can choose your own package name, or use the default package name. Note that there cannot be Chinese characters or capital letters in the package name.
  • Version: You can use the default version 1.0.0, or you can modify the package name yourself.

For other parameters, press Enter all the way.

Therefore, the package.json file will be automatically generated in the root directory. Click in and have a look:

{
    
    
  "name": "commonjs_browser",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    
    
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

6.2 Download third-party packages:Browserify

Here you need to use the Browserify tool to compile and package. Browserify is a browser-side bundling tool for CommonJS.

Enter the following command to install: (both commands must be entered)

npm install browserify -g          //全局
npm install browserify --save-dev  //局部。

In the above code, -dev means development dependency. Here is an explanation of related concepts:

Development dependencies: Currently this package is only used in the development environment.
Running dependencies: This package is currently used in a production environment.

6.3 Custom Module & Code Run

(1)module1.js:

//暴露方式一:module.exports = value
//暴露一个对象出去
module.exports = {
    
    
    name: '我是 module1',
    foo(){
    
    
        console.log(this.name);
    }
}
//我们不能再继续写 module.exports = xxx。因为重新赋值,会把之前的赋值覆盖掉。

(2)module2.js:

//暴露方式一:module.exports = value
//暴露一个函数出去
module.exports = function(){
    
    
    console.log('我是 module2');
}

Note that the exports object exposed at this time is equivalent to the entire function.

(3)module3.js:

//暴露方式二:exports.xxx = value

//可以往export对象中不断地添加属性,进行暴露

exports.foo1 = function(){
    
    
    console.log('module3 中的 foo1 方法');
}

exports.foo2 = function(){
    
    
    console.log('module3 中的 foo2 方法');
}

(4) app.js: (bring together other modules into the main module)

Explanation of the introduced path:
./it is a relative path, referring to the current path (the current path of app.js is src), so far, our main code is finished. However, if we write directly in index.html like the following, it will not work: (because the browser does not recognize the require keyword)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <script src="./js/src/app.js"></script>
</body>
</html>

In order to allow index.html to import app.js, we need to enter the following command:

  • Package processing js:
browserify js/src/app.js -o js/dist/bundle.js
  • Then introduce the packaged file in index.html:
<script type="text/javascript" src="js/dist/bundle.js"></script>

Guess you like

Origin blog.csdn.net/weixin_43094619/article/details/131899371