history

modular

It’s just an idea or a theory, not a concrete implementation

Description of content

  1. Modular evolution process
  2. Modular specification
  3. Commonly used modular packaging tools
  4. Build modern Web applications based on modular tools
  5. Optimization tips for packaging tools

1. Modular evolution process

Early front-end standards did not anticipate the scale of the front-end industry today, so there are a lot of design legacies that have led to a lot of problems when it comes to modular implementation.

  • Stage 1 – File partitioning (Each function and specific data is stored in a separate file, and each file is an independent module) -> Early modularity depended entirely on convention
    • Contamination global scope
    • Name conflict problem
    • Unable to manage module dependencies
<script src="module-a.js"></script>
<script src="module-b.js"></script>
<script>
// Name conflict
method1()
// Module members can be modified
name = 'foo'
</script>
Copy the code
// module-a.js
var name = 'module-a'
function method1() {
    console.log(name + '#method1')}// module-b.js
var name = 'module-b'
function method1() {
    console.log(name + '#method1')}Copy the code
  • Stage 2 – Namespace mode

Each module exposes only one global object to which all of our module members are mounted

<script>
moduleA.method1()
moduleA.method2()
// Module members can be modified
moduleA.name = 'foo'
</script>
Copy the code
var moduleA = {
    name: 'module-a'.method1: function() {
        console.log(this.name + '#method1')}}Copy the code
  • Stage 3-iife (Call function expressions now)

We use the immediate execution of functions to provide private space for our modules

; (function() {
    var name = 'module-a'
    function method1() {
        console.log(name + '#method1')}// Members that need to be exposed can be mounted to the global object
    window.moduleA = {
        method1
    }
})()
Copy the code

This was an early approach to modularity without tools and specifications

2. The emergence of modular specifications

Since we still use the script tag to load different modules, module loading is not controlled by our code

  • We need modular standard + module loader
  • CommonJSSpecification –NodejsOne set of standards is to load modules in synchronous mode (loading modules at startup, not during execution); Browser usageCommonJSInevitable inefficiency (master synchronization request every time browser loads)
    • A file is a module
    • Each module has a separate scope
    • throughmodule.exportsMembers of the derived
    • throughrequireFunction loading module
  • AMD (Asynchronous Module Definition)The (browser-side) asynchronous module definition specification -> the well-known library is calledRequire.js
    • AMDRelatively complex to use
    • Module JS file requests are frequent

It was a compromise, not the final solution, but it made sense in the context of the time, because it provided a standard for front-end modularity. In addition, there is also the launch of Taobao called Sea. Js + CMD

Most third-party libraries currently support the AMD specification

// Define a module
define('module1'['jquery'.'./module2'.function($, module2) {
    return {
        start: function() {$('body').animate({ margin: '200px' })
            module2()
        }
    }
}
// For details, see
// modular-evolution/stage-5

// Load a module
require(['./module1'].function(module1) {
    module1.start()
})
Copy the code
  • Sea.js + CMDThe standard is CMD

The idea was to make CMD code as similar to CommonJS as possible to reduce the learning pressure for developers

// CMD specification (similar to CommonJS specification)
define(function(require.exports.module) {
// introduce dependencies via require
var$=require('jquery')
Exports or module.exports exposes members
module.exports = function() {
    console.log('module 2~');
    $('body').append('<p>module2</p>')}Copy the code

Use ES Modules in the browser environment; Use CommonJS in Node

ESModules is the latest module system in ECMAScript 2015(ES6)

ESModules

1. ES Modules

  • ESMAutomatically adopt strict mode, ignoring ‘use strict’
  • eachESMBoth run in separate private scopes
  • ESMIs through theCORSRequest externallyJSThe module
  • ESMscriptTags will delay script execution similarlydefer
<! By adding a type = module attribute to a script, you can execute JS code in ES Module standards.
<script type="module">
    console.log('this is es module')
</script>

<script type="module" src="https://unpkg.com/[email protected]/dist/jquery.min.js"></script>
Copy the code

2. ES Modules Export

// 
export var name = 'foo module'

export function hello() {
    console.log('hello')}export class Person {}

// 
var name = 'foo module'
function hello () {}

// 
export default name
// It is used accordingly
import { default as name } from ' '
// or
import name from ' '
//

export {
    name as fooName, // You can call it another name
    hello as fooHello
}
Copy the code

2.2 Precautions for Import and Export

  • exportIt is not a literal object
  • exportIn fact, it’s puttingReference relationshipTo the outside, and isread-onlythe
var name = 'jack'
var age = 18

// Many people mistake this for a literal object
export { name, age }
// Here is the deconstruction of literal objects
import { name, age } from 'xxx'
// This is actually wrong


// This is a fixed usage
export {}
Copy the code

3. ES Modules import usage

// module.js
var name = 'jack'
var age = 18

export { name, age }

console.log('module action')

export default 'default export'


// app.js
// import { name } from './module'
// import { name } from './module.js'
// console.log(name)

// import { lowercase } from './utils'
// import { lowercase } from './utils/index.js'
// console.log(lowercase('HHH'))

// import { name } from 'module.js'
// import { name } from './module.js'
// import { name } from '/04-import/module.js'
// import { name } from 'http://localhost:3000/04-import/module.js'
// console.log(name)

// --------------

// import {} from './module.js'
// import './module.js'

// ---------------

// import * as mod from './module.js'
// console.log(mod)

// ---------------

// var modulePath = './module.js'
// import { name } from modulePath
// console.log(name)

// if (true) {
// import { name } from './module.js'
// }

// import('./module.js').then(function (module) {
// console.log(module)
// })

// ----------------

// import { name, age, default as title } from './module.js'
import abc, { name, age } from './module.js'
console.log(name, age, abc)

Copy the code

3.1 Exporting Imported Members

  • export { foo, bar } from ‘./module.js’
// import { Button } from './button.js'
// import { Avatar } from './avatar.js'

// export { Button, Avatar }

export { default as Button } from './button.js'
export { Avatar } from './avatar.js'
Copy the code

4. Polyfill the browser environment

Here are the ones that support IE

<script nomodule src="https://unpkg.com/[email protected]/dist/polyfill.min.js"></script>
<script nomodule src="https://unpkg.com/[email protected]/dist/babel-browser-build.js"></script>
<script nomodule src="https://unpkg.com/[email protected]/dist/browser-es-module-loader.js"></script>
<script type="module">
import { foo } from './module.js'
console.log(foo)
</script>
Copy the code

5. ES Modules support in Node

To use ESM in NodeJS, there are two steps

  • Change.js to.mjs
  • Using the commandnode --experimental-modules index.mjs

Note: import {} can be exported from the system’s built-in modules

// index.mjs
import fs from 'fs'
import { writeFileSync } from 'fs' 
// Either of the above is ok

import _ from 'lodash'
console.log(_.camelCase('ES Module'))
// The above is ok
// But the following is not allowed
import { camelCase } from '_'
console.log(camelCase('ES Module'))
Copy the code

5.2 Using CommonJS in NodeJS

  • ES ModulesCan be imported fromCommonJSThe module
  • CommonJSCannot be imported inES ModulesThe module
  • CommonJSOnly one default member is always exported
  • Pay attention toimportInstead of deconstructing the exported object
// commonjs.js
module.exports = {
    foo: 'commonjs exports value'
}

// es-module.mjs
// Note that members cannot be extracted directly. Note that import is not a deconstructed export object
import mod from './commonjs'
// node --experimental-modules es-module.mjs  
// There is output
Copy the code

5.3 ES Modules in Nodejs vs. CommonJS

// cjs.js
// Load the module function
console.log(require)
// Module object
console.log(module)
// Export the object alias
console.log(exports)
// The absolute path to the current file
console.log(__filename)
// Current file directory
console.log(__dirname)

// esm.mjs
// ESM does not have the CommonJS module global members
import { fileURLToPath } from 'url'
import { dirname } from 'path'
const __filename = fileURLToPath(import.meta.url)
console.log(__filename)
const __dirname = dirname(__filename)
console.log(__dirname)
Copy the code

5.4 Node 12.10.0

  • inpackage.jsonadd"type": "module"– So you don’t have to change the suffix to.mjs
  • To change the"type"afterCommonJSThe file needs to be changed.cjs

5.5 Babel Compatibility Scheme

  • yarn add @babel/node @babel/core @babel/preset-env -D

Add a.babelrc file

{
    "presets": ["@babel/preset-env"]}Copy the code
  • useyarn babel-node index.jsperform

Note that presets are a set of plug-ins, but we can also use a single plug-in here

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