当前位置:网站首页>Simple summary of front end modularization

Simple summary of front end modularization

2020-11-06 01:28:39 itread01

Preface

  JavaScript In the early stage, it is to realize the simple interactive logic of the page , Now CPU、 Browser performance has been greatly improved , A lot of page logic has migrated to the client side , Front end code is expanding , At this time in the js Aspects will consider how to manage, use modular specifications to manage .

   No matter what language is, once it has developed to a certain extent , Its engineering ability and maintainability are bound to get corresponding development . The modularity thing , It's a common thing in any field of programming , The purpose of modularity is to increase reusability , With as little code as possible is the need to achieve personalization . One of the three swordsmen in the front end CSS As early as 2.1 It's a version of @import To achieve modularity , however JavaScript until ES6 Only then did the official modular solution emerge : ES Module (import、export). Although in the early days JavaScript Modularization is not supported in the language specification , But it didn't stop JavaScript The development of , There's no official modularity standard, and developers start building their own specifications , Implement your own specifications .

Front end modularization

  JavaScript There were no modules in early design 、 The concept of packages and even classes , Although  ES6  There is  class  Keywords , That's just a grammar sugar . As the complexity of the project increases , Developers need to simulate the functionality of classes , To isolate 、 Package 、 The organization is complex JavaScript Code , And this packaging and isolation , It's also called modularity .

   A module is a file that implements a specific function or Code block . With the development of front end engineering system , Perhaps the concept of modularity is already familiar in the front-end circles . But for many developers ,ES6 Medium  exportimport,nodejs  Medium  requireexports.xxmodule.exports What's the difference ? Why there is  CommonJS, And then there is  AMD,CMD,UMD? What's the difference ? We're even writing ts When it comes to filing , You also need to specify the module mode in the configuration file , When used in a project , Do we really know , What kind of specification are you using for modularity ?

The value of modularity

  • Maintainability , Each module is independent . Good design can greatly reduce the coupling of projects . So that it can be modified independently of other functions . Maintain at least one independent function module , It's much easier than maintaining a mess of code .
  • Reduce global variable pollution , The early days of front-end development , We're all having trouble with global variables , Because it often triggers some difficult and non-technical bug. When some unrelated code accidentally renames a global variable , We're going to meet annoying “ Name space pollution ” The problem of . Before the modularity specification was defined , In fact, we are trying to avoid this .( It will be introduced later )
  • Reusability , Front end module function encapsulation , Greatly improves the reusability of code . There should be no need to elaborate on this point . Think about it from  npm  Look for  package  When , What are you doing ?
  • Facilitate dependency management , When the modularity specification is not fully defined , The interdependence between modules is very vague , It all depends on js The order of file Introduction . Vulgar ! No technical content at all , It's not only fuzzy but also hard to maintain .

 

Modular evolution

1、 Function encapsulation

Let's go back to the definition of modules that we just talked about , A module is a file that implements a specific function or Code block ( This is my own definition ). Professional definition is , In programming , A program or subroutine required to perform a function ; Or can be compiled by a compiler 、 An independent program unit for assembly programs, etc ; Or part of a large software system . One of the functions of a function is to package a set of statements with specific logic . And JavaScript The scope of is function based , So the most original place , Functions must be the first step in modularization .

Encapsulate different functions into different functions

  • Code : Encapsulate different functions into different global functions
  • The problem is : Contaminating global namespace , It is easy to cause naming conflicts or data insecurity , And there is no direct relationship between module members , The relationship between modules is fuzzy
// Function 1
function fn1(){
  //statement
}
// Function 2
function fn2(){
  //statement
}

2、namespace Pattern  

It can also be understood as object encapsulation , In fact, it is to put the related function 、 Variables are added to the outside

let module1 = {
  let tag : 1,
  let name:'module1',
  
  fun1(){
    console.log('this is fun1')
  },
  
  fun2(){
    console.log('this is fun2')
  }
}

When we use it , Just directly

module1.fun2();

Advantages

  • It optimizes naming conflicts to some extent , It reduces the risk of contamination of global variables
  • There is a certain module encapsulation and isolation , And it can be further semantically

Disadvantages

  • There's no real change in naming conflicts
  • External members can modify internal member variables at will , It's still prone to unexpected risks

 

 

 3、IIFE Pattern : Execute anonymous functions immediately ( Closure )

 

let global = 'Hello, I am a global variable :)';

(function () {
  //  In the scope of a function, the following variables are private 

  const myGrades = [93, 95, 88, 0, 55, 91];

  let average = function() {
    let total = myGrades.reduce(function(accumulator, item) {
      return accumulator + item}, 0);

    return 'Your average grade is ' + total / myGrades.length + '.';
  }

  let failing = function(){
    let failingGrades = myGrades.filter(function(item) {
      return item < 70;});

    return 'You failed ' + failingGrades.length + ' times.';
  }

  console.log(failing());
  console.log(global);

// Need to be exposed api
return {
// something
} }()); // The console shows :'You failed 2 times.' // The console shows :'Hello, I am a global variable :)'

The advantage of this method lies in , You can use a local variable inside a function , It does not accidentally override a global variable with the same name , But you can still access global variables

Similar to the above  IIFE , There's a lot of evolution writing

For example, introducing dependencies :

Pass in the variables needed internally .

// module.js Archives 
(function(window, $) {
  let data = 'www.baidu.com'
  // Functions that manipulate data 
  function foo() {
    // Used to expose a function 
    console.log(`foo() ${data}`)
    $('body').css('background', 'red')
  }
  function bar() {
    // Used to expose a function 
    console.log(`bar() ${data}`)
    otherFun() // Internal calls 
  }
  function otherFun() {
    // Internal private functions 
    console.log('otherFun()')
  }
  // Exposure behavior 
  window.myModule = { foo, bar }
})(window, jQuery)

Use

 // index.html Archives 
  <!--  Introduced js There has to be a certain order  -->
  <script type="text/javascript" src="jquery-1.10.1.js"></script>
  <script type="text/javascript" src="module.js"></script>
  <script type="text/javascript">
    myModule.foo()
  </script>

Advantages

  • The basic encapsulation is realized
  • Only exposed external method operation , Using closures, we achieve something similar to  public  and  private  The concept of

Disadvantages

  • Module dependencies are fuzzy
  • It's not easy to manage between modules

   All of the above solutions , Although every method works , But there is no one that can solve variable pollution well 、 The dependency relationship between modules is clear 、 Easy to manage 、 Easy integration with equation 3 code . With the advent of the era of big front end , stay 2009 It was proposed that CommonJS Regulate , And nodeJs Use the specification directly to manage modularity , As time goes by , Now JavaScript The module specification is there :CommonJS、AMD、CMD、UMD、ES6 Modularity .

4、CommonJS

  CommonJS yes JavaScript A modular specification for (http://www.commonjs.org/), It is mainly used on the server side Nodejs in . According to the regulations , Every file is a module , The variables defined internally belong to this module , It doesn't pollute global variables . Inside each module ,module The variable represents the current module , This variable is an object , its exports Properties ( namely module.exports) It's an external interface . Load a module , In fact, the module is loaded module.exports Properties .

CommonJS The core idea is through require Method to load the dependent modules synchronously , And then through exports perhaps module.exprots To export the exposed interface . 

Basic usage

  • Exposure module :module.exports = value or exports.xxx = value
  • Introducing modules :require(xxx), If it's a third-party module ,xxx For the module name ; If it's a custom module ,xxx For module file path
// example.js
let x = 5;
let addX = function (value) {
  return value + x;
};
module.exports.x = x;
module.exports.addX = addX;
let example = require('./example.js');
console.log(example.x); // 5
console.log(example.addX(1)); // 6

require Command is used to load module files .require The basic function of the command is , Read in and execute a JavaScript Archives , Then return the module's exports thing , If the specified module is not found , Will report a mistake , If there are more than one exports   Only the first one exports It works .

require It's loading the file and executing , Back in 、 Output exports This object

console.log(' It's starting to load ') //  Will output   It's starting to load 

function run (val) {
  console.log(val)
}

Features

  • A module is a file module , Code execution is within the scope of the module , It doesn't pollute global variables
  • Load module synchronously , It is no problem to read the local disk directly on the server side , Not for browsers
  • Modules can be loaded multiple times , But it will only be executed on the first load , And then load , It's the cache file to be read . You need to clear the cache before you can read the file again
  • The order in which modules are loaded , In the order in which they appear in the code
  • Export is a copy of the value , This and ES6 There's a big difference ( It will be introduced later )

Add some knowledge

Node in , A file is a module ->module

The source code is defined as follows :

function Module(id = '', parent) {
  this.id = id;
  this.path = path.dirname(id);
  this.exports = {};
  this.parent = parent;
  updateChildren(parent, this, false);
  this.filename = null;
  this.loaded = false;
  this.children = [];
}
// Instantiate a module 
var module = new Module(filename, parent);

CommonJS A module of , It's a script file .require The command loads the script for the first time , It will execute the entire instruction code , And then create an object in memory .

{
  id: '...',
  exports: { ... },
  loaded: true,
  ...
}

   The code above is Node An object generated after the module is loaded internally . Of the object id The property is the module name ,exports Property is the interface of the module output ,loaded The attribute is a Boolean value , Indicates whether the instruction code of the module is completed . There are many other properties . When you need to use this module later , It will come to exports The value above the attribute is . Even if you do it again require command , The module will not be executed again , It's in the cache . That is to say ,CommonJS No matter how many times a module is loaded , Will only be executed once on the first load , Load later , Return the result of the first execution , Unless you manually clear the system cache .

About AMD、CMD

  CommonJS  stay Node.js It's been a great success in the environment , A lot of people want to put commonJs The specification is pushed to the browser side , But the browser can't directly read the contents of the disk like the server, so there is the following AMD、CMD Regulate .ES6 At the level of language standards , The module function is realized , And it's quite simple to implement , It can completely replace the existing CommonJS and AMD Regulate , Become a common module solution for browsers and servers , Because I've only been in the front end in recent years , AMD、CMD Not too much use of , therefore AMD、CMD Here is just a brief introduction .

 

 

5、AMD

 

AMD Its full name is Asynchromous Module Definition( Asynchronous module definition )

AMD yes RequireJS The standardized output of module definition in the promotion process , It's a specification for modular development on the browser side . AMD Patterns can be used in browser environments and allow asynchronous loading of modules , At the same time, it can ensure the correct order , You can also dynamically load modules on demand .

Features

  • Asynchronous load module , It won't cause fake death due to network problems
  • Explicitly list its dependencies , And with the function ( The function that defines this module ) These dependencies are injected in the form of arguments
  • At the beginning of the module , Load all the required dependencies

Define modules

define(id?: String, dependencies?: String[], callback: Function|Object);
  • id, An optional argument , It's like giving the module a name , But it's the only identification of the module . If it is not provided, the file name of the script is taken
  • dependence, Dependent module array
  • callback, Factory approach , Some operations of module initialization . If it's a function , Only once . If it's an object , The output value of the module

Using modules

require([moduleName],callback);
Use
//article.js Archives 
//  Define modules that have dependencies 
define(['user'], function(user) {
  let name = 'THE LAST TIME'
  function consoleMsg() {
    console.log(`${name} by ${user.getAuthor()}`);
  }
  //  Exposure module 
  return { consoleMsg }
})
//  call  article  Module type  consoleMsg
require(['article'], function(alerter) { article.consoleMsg() })
About require.js Use , Look at the document carefully , In fact, there are many knowledge points . But we don't use it much now ( I'm not familiar either ), So here also refer to the excellent articles on the Internet and their own practice , Throw a brick to attract jade .
 

6、CMD

  CMD namely Common Module Definition General module definition ,CMD yes SeaJS The standardized output of module definition in the promotion process , It was Ali's jade uncle who brought it up , It and AMD It's very similar , Files are modules .CMD The main difference is the implementation of on-demand loading , Respect the principle of relying on the nearest , Module delay execution , and AMD The dependent module is executed ahead of time (requireJS 2.0 Later, it was changed to postpone execution )
 
therefore AMD and CMD The biggest difference is that the execution timing of dependent modules is different , Note that it's not a different time or way to load .CMD Keep the specification as simple as possible , And with CommonJS The specification maintains a lot of compatibility . Through CMD The module of standard writing , It can be very easy in Node.js In the implementation of .
stay CMD In the specification , A module is a file . The format is as follows :
define(factory);

define Is a global function , Used to define modules , Arguments factory It can be objects 、 String 、 Function

factory For objects 、 When the string is , The interface representing the module is the object 、 String . For example, one can be defined as follows JSON Data module :

define({ "foo": "bar" });

You can also define template modules through strings :

define('I am a template. My name is {{name}}.');

factory When is a function , Representation is the construction method of the module .

Execute the constructor , You can get the interface provided by the module .factory When the method is executed , By default, three arguments are passed in :require、exports and module:

define(function(require, exports, module) {
  //  Module code 
});

Use sea.js

/** sea.js **/
//  Define modules  math.js
define(function(require, exports, module) {
    var $ = require('jquery.js');
    var add = function(a,b){
        return a+b;
    }
    exports.add = add;
});
//  Load module 
seajs.use(['math.js'], function(math){
    var sum = math.add(1+2);
});

About sea.js Use , Look at the document carefully , In fact, there are many knowledge points . But we don't use it much now ( I'm not familiar either ), So here also refer to the excellent articles on the Internet and their own practice , Throw a brick to attract jade .

 7、UMD

UMD yes AMD and CommonJS The combination of . As mentioned above ,AMD It's the browser , Non blocking load .CommonJS It is mainly used on the server side Nodejs Use in . So people came up with a general pattern UMD(universal module definition). To solve cross platform problems .
That's right ! Namely ifElse How to write .
The core idea is : First judge whether to support Node.js Module of (exports) Whether there is , To be is to use Node.js Module mode .
Judging whether to support AMD(define Whether there is ), To be is to use AMD Mode loading module .

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        //AMD
        define(['jquery'], factory);
    } else if (typeof exports === 'object') {
        //Node, CommonJS And so on 
        module.exports = factory(require('jquery'));
    } else {
        // Browser global variables (root  namely  window)
        root.returnExports = factory(root.jQuery);
    }
}(this, function ($) {
    // Method 
    function myFunc(){};
    // Expose public methods 
    return myFunc;
}));

 

8、ES Module

   stay ES Module Before , The community has developed some module loading schemes , The main ones are CommonJS and AMD Two kinds of . The former is used for servers , The latter is used for browsers .ES Module At the level of language standards , The module function is realized , And it's quite simple to implement , It can completely replace CommonJS and AMD Regulate , Become a common module solution for browsers and servers .

ES Module The design idea is static as far as possible , So that the module dependencies can be determined at compile time , And input and output variables .CommonJS and AMD Module , They can only be determined at the time of execution .

  CommonJS and AMD Module , Its essence is to generate an object for export at runtime , It's called “ Load at run time ”, It can't be done “ Compiler optimization ”, and ES Module It's not an object , It's through export The command explicitly specifies the output code , And then through import Command input . This is called “ Load at compile time ” Or statically load , namely ES Module Modules can be loaded at compile time , More efficient than CommonJS The loading mode of modules is high . Of course , It also makes it impossible to quote ES Module The module itself , Because it's not an object .

Because of ES Module Is compile time loading , Making static analysis possible . With it , Can further broaden JavaScript The grammar of , For example, introducing a macro (macro) And type checking (type system) These functions can only be realized by static analysis .

Features

  • Static compilation
  • The output value references , Instead of copying values
  • import It can only be written at the top , Because it's static syntax

 

9、CommonJs、ESM The difference is

CommonJs ES6 Module
Load at run time ;CommonJs Modules are objects (module.exports Properties )), That is, the whole module is loaded first when input 、 Execution module , Create an object , Then read the method from the object . Load at compile time ;ES6 Modules are not objects , It's through export The command explicitly specifies the output code ,import In the form of static commands . That is to say import You can specify to load an output value when , Instead of loading the entire module .
The output is a copy of the value ( Once a value is output , Changes within the module do not affect this value .) The output is a reference to the value (JS When the engine statically analyzes the script , Module loading command encountered import, A read-only reference will be generated . When the script actually executes , According to this read-only reference , Go to the loaded module to get the value . That is, the original value has changed ,import The loaded values will change accordingly . therefore ,ES6 Modules are dynamic references , And it's not going to take values quickly , The variables in a module are bound to the module in which they are located .)

 

The difference

  • CommonJS What the module outputs is a copy of the value ,ES6 The module outputs a reference to the value .
  • CommonJS Modules are loaded at run time ,ES6 A module is a compile time output interface .

 

Load & Compile

Because CommonJS Loading is an object (module.exports), Objects can only be generated when there is a script running . and ES6 A module is not an object , It's just a static definition . During the code parsing phase .

 

ES6 A module is a compile time output interface , So there are the following 2 Characteristics :

  • import Orders will be JS Engine static analysis , Takes precedence over other contents in the module
  • export The command will have variables to declare the effect of promotion , therefore import and export The location of the command in the module does not affect the output of the program .

 

  • Asynchronous load module , It won't cause fake death due to network problems
  • Explicitly list its dependencies , And with the function ( The function that defines this module ) These dependencies are injected in the form of arguments
  • At the beginning of the module , Load all the required dependencies

版权声明
本文为[itread01]所创,转载请带上原文链接,感谢