This is the 9th day of my participation in the August Wen Challenge.More challenges in August

With the development of front-end technology, the concept of modularization is becoming more and more mature.

With the advent of ES6, modules are designed to be as static as possible, allowing dependencies and input and output variables to be determined at compile time.

More articles on my github and personal public account [quan Zhandao Road], welcome to watch [front-end knowledge], if you benefit, no money, little hands dot a Star

Read this article and you will learn

  • Concept of modularity
  • The evolution of modularity
  • Detailed explanation of various modular resource introduction schemes
  • Frequently asked questions for various modular introduction options

Concept of modularity

  • Module is a complex program according to certain rules (specifications) encapsulated into several blocks (files), and combined together, the internal data and implementation of the block is private, just to expose some external interfaces (methods) and external other module communication.
  • The composition of a module consists of two parts: data (internal properties) and the behavior of manipulating data (internal functions).

Early implementations of modularity

globalFunctionmodel

  • Such global Function mode in the early stage was close to componentization for the purpose of extracting componentization, and it was easy to pollute each module.

  • ModuleFirst.js

Function fun() {console.log(' fun() ${data} '); } function funNext() { console.log(`funNext() ${data}`); }Copy the code
  • ModuleSecond.js
Let data = 'module 2' function fun() {console.log(' fun() ${data2}'); }Copy the code
  • index.html
<script type="text/javascript" src="ModuleFirst.js"></script> <script type="text/javascript" SRC =" modulesecond.js "></script> <script type="text/javascript"> let data =" modified data "; fun(); / / conflict funNext (); </script>Copy the code
  • The global function pattern is one of the early modularization ideas. The biggest problem of this approach is that the introduction of modules at the same time will cause data pollution and naming conflicts.

namespacemodel

  • ModuleFirst.js
let moduleFirst = { data: 'ModuleFirst', fun() { console.log(`fun() ${this.data}`); }, funNext() { console.log(`funNext() ${this.data}`); }}Copy the code
  • ModuleSecond.js
let moduleSecond = { data: 'ModuleSecond', fun() { console.log(`fun() ${this.data}`); }, funNext() { console.log(`funNext() ${this.data}`); }}Copy the code
  • index.html
<script type="text/javascript" src="ModuleFirst.js"></script> <script type="text/javascript" SRC =" modulesecond.js "></script> <script type="text/javascript"> // modulefirst.js modulefirst.fun () Modulefirst.funnext () // Modulesecond.js modulesecond.fun () modulesecond.funnext () modulefirst.data = 'other data' // Can directly modify the data modulefirst.foo () </script>Copy the code
  • This pattern is simple object encapsulation. Although it solves the problems of naming conflicts and data contamination, it can also be modified directly for internal data in the reference page.

Modular multiple ways

Require

  • Require is the CommonJS syntax, and CommonJS modules are objects that must look for object properties when typed.
// CommonJS module let {stat, exists, readFile} = require('fs'); // equivalent to let _fs = require('fs'); let stat = _fs.stat; let exists = _fs.exists; let readfile = _fs.readfile;Copy the code
  • Load the fs module as a whole (that is, load all the methods of FS), generate an object “_fs”, and then read three methods from that object. This is called “runtime load”, because this object is only available at runtime and cannot be static at compile time.
  • The ES6 module is not an object, but displays the specified output code through the export command, followed by input through import.
import { stat, exists, readFile } from 'fs';
Copy the code
  • The stat, exists, and readFile methods are loaded from fs. The other methods are not loaded.

Export

  • A module is a separate file, and all variables inside the file cannot be accessed externally. If you want to get a variable, you must export it.
// profile.js
export var firstName = 'Michael';
export var lastName = 'Jackson';
export var year = 1958;
Copy the code
  • Or better yet: use curly braces to specify a set of variables to output.
// profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;

export {firstName, lastName, year};
Copy the code
  • In addition to output variables, you can also output functions or classes.
export function multiply(x, y) {
  return x * y;
};
Copy the code
  • You can also batch output, again enclosed in curly braces, or rename it with as.
function v1() { ... }
function v2() { ... }

export {
  v1 as streamV1,
  v2 as streamV2,
  v2 as streamLatestVersion
};
Copy the code
  • The export command specifies the external interface and must establish a one-to-one relationship with the internal variables of the module.
Export var m = 1; Var m = 1; export {m}; Var n = 1; export {n as m}; Export 1; Var m = 1; export m;Copy the code
  • The reason for writing the error is that there is no external interface provided. The first type directly outputs 1, and the second type directly outputs 1 even though there is a variable M, so it cannot be deconstructed.
  • Similarly, the output of function and class must be written this way.
Function f() {} export f; Export function f() {}; Function f() {} export {f};Copy the code
  • The interface output by the export statement is dynamically bound to its corresponding value, that is, the real-time value obtained through this interface is inside the module.
  • The export module can be located anywhere in the module, but it must be at the top level of the module. If it is in another scope, an error will be reported.
function foo() {
  export default 'bar' // SyntaxError
}
foo()
Copy the code

Import

  • After export defines the external interface of a module, other JS files can load the module through import.
// main.js
import {firstName, lastName, year} from './profile';

function setName(element) {
  element.textContent = firstName + ' ' + lastName;
}
Copy the code
  • The import command accepts a pair of curly braces specifying that the name of the variable to be imported from another module must be the same as the name of the external interface of the imported module (profile.js).
  • If you want to rename the imported variable, use the as keyword
import { lastName as surname } from './profile';
Copy the code
  • The from after import can specify the path name of the module to be imported, either absolute or relative. The.js path can be omitted. If there is only the module name but no path, you need to specify it in the configuration file.
  • Note that the import command is promoted to the top of the module and executed first. (Is executed at compile time)
  • Because import is executed statically, expressions and variables cannot be used, meaning that the syntax structure of the result is available at run time (eg. If… The else…).

module

  • Instead of specifying an output value to load, you can use (*) to specify an object on which all variables will be loaded.
/ / circle. Js. Export function area(radius) {return math. PI * radius * radius; } export function circumference(radius) { return 2 * Math.PI * radius; } import {area, circumference} from './circle'; Console. log(' circle area: '+ area(4)); Console. log(' circumference: '+ circumference(14)); // The loading method is specified one by one. import * as circle from './circle'; Console. log(' circle area: '+ circle.area(4)); Console. log(' circumference: '+ circle. Circumference (14));Copy the code
  • The object to which the module is loaded (circle, for example) is supposed to be parsed statically, so runtime changes are not allowed.
import * as circle from './circle'; // The following two lines are disallowed circes. foo = 'hello'; circle.area = function () {};Copy the code

export default

  • In the previous example, when using import, you need to know the name of the variable or function to be loaded in the module. Users may not want to read the source code and just want to use the interface directly, so you can use the export default command to specify the output for the module.
// export-default.js
export default function () {
  console.log('foo');
}
Copy the code
  • The import command can specify any name for the anonymous function when the module is loaded by other modules.
// import-default.js import customName from './export-default'; customName(); // 'foo' export default can also be used before non-anonymous functions.Copy the code
  • Let’s compare the default output to the normal output.
Export default function crc32() {// export default function crc32() {// export default function crc32(); } import crc32 from 'crc32'; Export function crc32() {// export function crc32() { }; import {crc32} from 'crc32'; / / inputCopy the code
  • As you can see, when export Default is used, the import statement does not use curly braces.
  • Import and export commands can only be at the top level of a module, not in a code block. Otherwise, syntax errors will be reported.
  • Such a design can improve compiler efficiency, but there is no way to implement runtime loading.
  • Since require is loaded at runtime, the import command has no way of replacing require’s dynamic loading capabilities. So the import() function was introduced. Dynamic loading is complete.
import(specifier)
Copy the code
  • Specifier is used to specify the location of the module to load. What arguments can import take? Import () can take the same arguments.
  • Import () returns a Promise object.
const main = document.querySelector('main');

import(`./section-modules/${someVariable}.js`)
  .then(module => {
	    module.loadPageInto(main);
  })
  .catch(err => {
	    main.textContent = err.message;
  });
Copy the code

import()

  • According to the need to load
    • The import module is loaded only when the user clicks the button in the event listener function.
button.addEventListener('click', event => {
  import('./dialogBox.js')
  .then(dialogBox => {
	    dialogBox.open();
  })
  .catch(error => {
	    /* Error handling */
  })
});
Copy the code
  • Conditions of loading
    • Import () can be placed in if… Else statement, implement conditional loading.
if (condition) { import('moduleA').then(...) ; } else { import('moduleB').then(...) ; }Copy the code

Write in the last

If you find this article beneficial to you, please like it and share it with more people who need it!

Welcome to pay attention to “Quanzhandao road” and wechat official account “Quanzhandao Road”, get more good articles and free books!
If you need [Baidu] & [Bytedance] & [JINGdong] & [Ape Tutoring], please leave a message, you will enjoy VIP speed push service ~

Past oliver

Implementation of wechat JS API payment

Create a personalized Github profile

The interviewer asks you<img>What would you say about the element

Special JS floating-point number storage and calculation

Long [word] baidu and good interview after containing the answer | the nuggets technology essay in the future

Front end practical regular expression & tips, all throw you 🏆 nuggets all technical essay | double festival special articles

A detailed explanation of the unpopular HTML tabIndex

A few lines of code teach you to solve the wechat generated posters and two-dimensional code

Principle of Vue3.0 Responsive data: ES6 Proxy

Make the interviewer fall in love with you

How to draw a fine line gracefully

[3 minutes] Front-end performance optimization -HTML, CSS, JS parts

Front-end performance Optimization – Page loading speed optimization

Front-end Performance Optimization – Network transport layer optimization