modular

Modularity is the process of dividing a project into functional modules for development and maintenance. Modules are also called components.

Modular evolution process

At the earliest, modularization was realized by exposing module variables globally in a conventional way, but the disadvantages of this way are obvious:

  • Contamination global scope
  • Name conflict problem
  • Unable to manage module dependencies

Later, the namespace approach was developed to achieve modularity by making a module a global object for global use. However, this approach only resolves the naming conflict, the module will still be changed externally, and module dependencies will not be managed. Later, in order to solve the above problem, it was thought that we could use immediate execution functions (IIFE) to block the scope, to provide the module with private space, and self-executing parameters as declarations of module dependencies. Members that need to be exposed globally are provided to global calls in the form of “window. module = member “. But this approach is not easy to maintain. There is no uniform standard for modules and they cannot be automatically loaded (removing or adding a module requires modifying references in the HTML file).

Modular specification

CommonJS specification

  • A file is a module
  • Each module has a separate scope
  • Exports members through module.exports
  • Load the module via the require function

CommonJS loads modules in synchronous mode, which is not a problem on the server side, but can cause inefficiency and slow page loading in browsers, so this specification is not applicable to browsers.

AMD specification

AMD specification, Asynchronous Module Definition specification. A specification made specifically for browsers. The once popular require.js is an implementation of the AMD specification. Most third-party libraries currently support the AMD specification. However,

  • AMD is relatively complex to use
  • Module JS file requests are frequent

Taobao team once launched a modular implementation scheme of Sea-.js +CMD, which is similar to CommonJS and later absorbed by require.js.

ES Moudules specification

The ES Moudules specification is a modular standard specification that is a best practice for browser-side modularity and was only introduced in 2014. Browser compatibility was not good at the beginning, but with the popularity of various packaging tools, browsers have basically implemented support for it. Therefore, we mainly study the usage of this module specification.

ES Moudules

usage

By adding a type=”module” attribute to the script tag, the JS code can be executed using ES Moudule standards.

<script type="module">
</script>
Copy the code

The basic features

  • Automatically adopt strict mode, ignoreuse strict. For example, in ES Module, this defaults to undefined, not window.
<script type="module">
  console.log(this)/ / output is undefined
</script>
Copy the code
  • Each ES Module runs in a separate private scope. There is no variable contamination
  • Request external JS modules through CORS. Therefore, the external server is required to support CORS cross-domain request, and it must also be required to use HTTP serve to request JS files
  • ES of the ModulescriptThe tag delays script execution. Script content is executed after the page has been rendered so that it does not block the page load

Export module Export

// ./modules.js
const foo = 'es modules'
export { foo }
// as rename
// export { foo as fooName } 
// export {foo as default} // Export as default member
// export default foo // as the default member
Copy the code

Import module import

// ./app.js
import { foo } from './modules.js'
// Import the default member for renaming
// import { default as fooName } from './modules.js'
// import fooName from './modules.js'
console.log(foo)
Copy the code

Import {member name} from ‘module path’,

  • If it’s a relative path,. /Don’t omit
  • The absolute path should be written from the site root, such as/04-import/module.js
  • If it starts with a letter, it represents a third-party module and can only import default members
  • It can also be accessed through a URL, for examplehttp://localhost:3000/04-import/module.js

If the member name is omitted, only the module is loaded and no member reference is made:

import {} from './modules.js'
// Short form
import './modules.js'
Copy the code

If you import a large number of members, you can use * to represent all member names instead of writing them individually:

import * from './modules.js'
// All imported members are saved into the object by renaming them
import * as mod from './modules.js'
Copy the code

You can’t replace paths with variables or write import commands into statements like if. To dynamically import a module, use the import() function, which returns a promise:

import('./modules.js').then(function (module) {
    console.log(module)// The module object represents all members of module.js
})
Copy the code

If both named and default members exist in the import module,

import { name, age, default as title } from './module.js'
// Short form
import title, { name, age } from './module.js'
Copy the code

Precautions for import and export

  1. export { foo, name }It’s not exporting literal objects, it’s really just a fixed syntax, and in the same way,

    import { foo, name }Nor is it a member of a deconstructed object that gets a literal.
  2. Export The exported member is only a reference to the exported member, not a value.
  3. Import The imported member reference isconstConstant, cannot be changed.

Export the imported members again

Sometimes we need to export the imported members again,

import { name, age } from './module.js'
export { name, age }
// Short form
export { name, age } from './module.js'
// To import and export the default member, you need to rename the default member; otherwise, the default member will be exported this time
export { default as Button } from './button.js'
Copy the code

Polyfill solves browser environment compatibility issues

Although most browsers now support ES Modules, there are still Some Incompatible Internet Explorer and some domestic browsers. So we have to think about compatibility.Polyfill is recommended for ES Modules compatibility. The address on Github is:Github.com/ModuleLoade…

ES Modules is compatible with most browsers by referencing relevant files:

Nomodule runs only on browsers that don't support ES Modules<script nomodule src="https://unpkg.com/[email protected]/dist/polyfill.min.js"></script>Complete the ES6 conversion to ES5<script nomodule src="https://unpkg.com/[email protected]/dist/babel-browser-build.js"></script># Read ES Modules<script nomodule src="https://unpkg.com/[email protected]/dist/browser-es-module-loader.js"></script>
Copy the code

The above code is only suitable for use in the development phase. In the production environment, the code needs to be compiled so that the browser can use it directly, otherwise it will affect efficiency.

ES Modules differ from CommonJS in Node.js

ES Modules is available in node.js versions 8.5 and above, but it is still an experimental feature and is not recommended for production use. But we can also test it with two requirements:

  • The node.js version must be 8.5 or later
  • Change the extension of the.js module to.mjs

Create modules. MJS and app. MJS. The contents of modules.

var foo = "Es Modules Test"
export { foo }
Copy the code

The contents of app.mjs are:

import { foo } from './modules.mjs'
console.log(foo)
Copy the code

Run the CMD command line in the root directory of the MJS file and enter

node --experimental-modules app.mjs
Copy the code

ES Module can import ConmmonJS Module:

import mod from './commonjs.js'
console.log(mod)
Copy the code

But in Node. js, the ConmmonJS Module cannot call ES Module via require:

const mod = require('./es-module.mjs')/ / complains
console.log(mod)
Copy the code

ConmmonJS module exports only one default member.

ES Modules support features in the latest version of Node.js

In the latest version of Node.js, just write in package.json

{
    "type":"module"
}
Copy the code

That is, js files can be recognized in ES Modules mode, but ConmmonJS files should be named.cjs, otherwise they will not be loaded as ConmmonJS files.

ES Modules Babel compatible scheme in Node.js

Babel is the most common ES Modules compatibility solution in earlier versions of Node.js. Since Babel implements the conversion of new features through plug-ins, one plug-in for each feature, it is inefficient to install the corresponding feature conversion plug-ins one by one in the actual development.It is recommended to install the preset-env plug-in, which contains transformations for all new JS features. The installation command is as follows:

Yarn add @babel/node @babel/core @babel/preset-env --dev # Run index.js yarn babel-node including ES modules  index.js --presets=@babel/preset-envCopy the code

After installing the Babel dependency, you can also set a. Babelrc configuration file, which contains the following contents:

{
   "presets":["@babel/preset-env"]
}
Copy the code

PS: Presets are plug-in sets. You can fill them with any plug-in you need

You can then run the ES Modules JS file directly with babel-Node without adding parameters.

yarn babel-node index.js
Copy the code

If we knew exactly how many features we needed to convert, it would have been faster to use a single plug-in. For example, the ES Modules conversion module is plugin-transform-modules-commonjs, and the installation command is as follows:

yarn add @babel/plugin-transform-modules-commonjs --dev
Copy the code

Modify. Babelrc configuration file:

{
   "plugins":["@babel/plugin-transform-modules-commonjs"]
}
Copy the code

Run ES Modules JS with babel-node directly:

yarn babel-node index.js
Copy the code