Written in the beginning

The development of the front end always makes us see, and what is the norm out of this, THE last norm I haven’t understood thoroughly. But no matter how the future develops, it is still very important to understand the history, to look at the history as a mirror, can know the gains and losses. If we know the history of the specification, we can better understand the current specification.

What happens to front-end code without modularity?
  • Variables and methods are not easy to maintain and pollute the global scope
  • Resources are loaded from top to bottom via script tags.
  • Depending on the environment of subjective logic, more code will be more complex.
  • Resources on large projects are difficult to maintain, especially when multiple people work together, and the introduction of resources can be overwhelming.
How we brought in the resources.

If you look at the script tag above, it looks familiar. Using a script to introduce the resources you want, from top to bottom, the order is very important, the resources load in order to determine whether your code will run. Of course we haven’t added the defer and async properties yet, otherwise the loading logic would be more complicated. The resources introduced here are relatively small, and too many script tags cause too many requests. At the same time, the larger the project, the more complex and difficult to maintain dependencies eventually, dependency ambiguity, too many requests. The potential for global contamination is greater. So the question is, how do you form a separate scope?

The difference between defer and Async

Defer does not execute until the entire page has been rendered properly in memory (the DOM structure has been fully generated, and other scripts have been executed); Once async is finished downloading, the rendering engine interrupts the rendering, executes the script, and continues rendering. In a word, defer means “render before execution” and Async means “download after execution”. Also, if you have multiple defer scripts, they are loaded in the order they appear on the page, which is not guaranteed by multiple Async scripts.

Building blocks of modularity

The Immediate-Execute Function Expression, or IIFE, is actually a javaScript function. You can define methods and private properties inside a function, acting as a closed scope. For example:

let module = (function() {let _private = 'myself';
    let fun = () =>{
        console.log(_private)
    }
    return {
        fun:fun
    }
})()
module.fun()//myself
module._private//undefined
Copy the code

The above code can then form a separate scope, reducing the possibility of global contamination to some extent. This notation is the cornerstone of modern modularity. While you can define methods, you can’t define properties, and various front-end specifications start to appear.

First up is common.js

The first to comply with the CommonJS specification is Node.js. This change has been called the first milestone in modularity, enabling javaScript to be written in js on the server side as well as in the browser. Think about the long March 25,000, where is the first milestone?

Features of the CommomJS module
  • Code within a module runs only within the module scope and does not pollute the global scope
  • Modules can be imported multiple times, but only run once on the first load, with subsequent runs fetching cached values. To get a module running again, you must be aware of the cache.
// delete require.cache[moduleName]; Keys (require.cache).foreach ()function(key) {
  delete require.cache[key];
})
Copy the code
  • The loading order of modules follows the order in which they appear in the code.
Why exports

Exports is just a variable pointing to module.exports. Exports is just a reference. So when exporting modules, we can add methods and attributes through exports. Exporting through module.exports is also a variable that reads Module. exports. Be careful with exports, though, because you can be cut off from Module. exports. Such as:

exports = function(x) {console.log(x)};
Copy the code

Exports no longer points to module.exports after the above code runs. Exports: If you can’t tell the difference, it’s probably best to avoid exports and just use module.exports.

How to tell whether a module executes directly or is called to execute.

MainAPI does this. If the module is executing directly, then the require.main attribute points to the module itself. For example:

require.main === module
Copy the code
Why don’t clients use the CommonJS specification?

We know that the client (browser) load resources, mainly through the network to obtain the general local read less, and the node. Js is mainly used for server programming, module file generally exists on the local hard disk, and then read the I/O is very fast, so also can apply even synchronous loading, the browser loads resources must be through asynchronous access, For common Ajax requests, for example, the AMD specification is perfect for asynchronously loading modules and allowing callback functions.

The client specification is not only AMD, but also CMD.

There is always a reason behind the rise of every specification. Requirejs was popular because CommonJS didn’t do what we needed it to do, and Sea-js was created because requireJS didn’t do what we needed it to do.

The difference between AMD and CMD
AMD CMD
The principle of Define (id? , dependencies? , factory) defines a single function “define”. Id is the module to be defined. The factory object passed in to dependencies is a factory parameter that specifies the exported value of the module. The CMD specification is similar to AMD and keeps it as simple as possible, but is more compatible with common.js.
advantages It is especially suitable for asynchronous loading in the browser environment and can be loaded in parallel. Dependencies are front-loaded and executed ahead of time. When you define a module, you can clearly declare which module to depend on Rely on proximity and delay execution. Load as needed and require when needed
disadvantages The development cost is high, and the semantics of module definition are difficult to understand, which is not in line with the modular way of thinking. Depending on SPM packaging, the loading of modules is subjective and logical.
reflect require.js sea.js
ES6 puts front-end modularity within reach
concept

ES6 modules are not objects, and the import syntax is statically analyzed by the JavaScript engine. Please note that this is an important feature. We usually use CommonJS to load the code at runtime, whereas ES6 introduces module code at compile time. You need a variety of build tools (Webpack) to properly use the modular features of ES6. It is also the ability to introduce module code at compile time that makes static analysis possible.

What are the advantages of ES6 modularity
  • If you can statically compile, you can determine module dependencies and output and input variables at compile time, and then CommonJS and AMD and CMD can only determine these relationships at run time.

  • No special UMD modular format Is required. The ES6 modular format will be supported by both servers and browsers in the future. Webpacks already do this.

  • All kinds of global variables can be modularized. For example, navigator is now a global variable and can be modularized later. This eliminates the need for objects as namespaces.

Something to watch out for
  • After the interface output by export statement is introduced through import, its corresponding value is dynamically bound, that is, even if the value in the module is changed, the real-time value can be obtained. The commonJS module outputs a cache of values with no dynamic updates.
  • Since ES6 is designed for static optimization, the export command cannot be in the block-level scope. If it occurs, an error will be reported. Therefore, export is generally written at the bottom or top level.
function fun() {export default 'hello' //SyntaxError
}
Copy the code
  • The import command is promoted to the head of the entire module and executed first. Such as:
fun()
import {fun} from 'myModule';
Copy the code

The code import above is executed before the FUN call because the import command is executed at compile time, before the code is run.

Export the default use

Export default is just printing out a variable or method called default, and then the system allows you to call it whatever you want. So, you can see the following.

//modules.js
function add(x,y){
  return x*y
}
export{add as default}; / / is equivalent toexport default add;

//app.js
import {default add foo} from 'modules'; // Equivalent to import foo from'modules'
Copy the code

This is because the export default command simply prints a variable named default, so it cannot be followed by a variable declaration statement.

Special techniques to detect whether code is in an ES6 module

Using the top-level syntax point this equals undefined, you can detect whether the current code is in an ES6 module.

const isNotModuleScript = this ! == undefined;Copy the code

If you want to continue to discuss or learn more knowledge, welcome to join QQ or wechat: 854280588