ESM

ESM is the JS standard modularization specification introduced by ES6. Its design idea is as static as possible, so that the module dependencies and input and output variables can be determined at compile time.

Function: The function of the module consists of two commands: export and import. The export command is used to specify the external interface of a module, and the import command is used to input functions provided by other modules.

features

  • Determine module dependencies and input and output variables at compile time
  • Automatic adoption of strict mode
  • A module is a file. All variables inside the module cannot be obtained externally

benefits

  • Makes static analysis possible, such as type checking
  • No longer needUMDModule format
  • In the future, the browser’s new apis will be available in module format and will no longer have to be global variables ornavigatorObject properties.
  • Objects are no longer required as namespaces (e.gMathObject), and in the future these functions could be provided through modules.

export

If you want outsiders to be able to read a variable inside a module, you must print that variable through the export keyword

  • The output variable
// profile.js
export const a = 1;
export const b = 'aaa';
export const c = 2021;

// Another way to write it
const a = 1;
const b = 'aaa';
const c = 2021;

export {a, b, c}
Copy the code

The two notations above are equivalent, but the second is recommended because you can see at the end of the module what variables are being output

  • Output function
export function fn() {
    console.log()
}

// Another way to write it
function fn1(){}
function fn2() {}

export {fn1, fn2}
// Rename the function
export {fn1 as st1, fn2 as st2, fn2 as st3}
Copy the code

The above code renames the external interfaces of the functions v1 and v2 using the AS keyword. After the rename, V2 can be printed twice with different names.

  • Note:exportCommands specify the external interface of the module and must establish a one-to-one relationship with variables inside the module

For example, the following is an error

export 1; / / an error
const a = 1;
export a; / / an error
Copy the code

Both of the above methods give an error because there is no external interface provided. The first way to write it is to print 1 directly, and the second way to write it is to print m directly, again. 1 is just a value, not an interface.

The correct way to write it

/ / write 1
export const a = 1;

/ / write 2
const a = 1;
export { a }

/ / writing 3
const a = 1;
export {a as m}
Copy the code

The above three notations are correct, specifying the external interface A. Other scripts can use this interface to get the value 1. Their essence is to establish a one-to-one correspondence between the interface name and the module’s internal variables.

Functions and classes must also follow the above rules

function fn() {}
export fn; / / an error

export function fn() {} / / right

function fn() {}
export {fn} / / right
Copy the code
  • exportThe interface of the statement output is dynamically bound to its corresponding value, that is, the real-time value of the module is obtained through the interface
export let foo = 'bar';
setTimeout(() = > foo = 'baz'.500);
Copy the code

The above code outputs as bar and baz after 500ms

  • Export can only appear at the top level of a module, not in a block-level scope

  • Export Default: used to export modules by default. Only one export default can exist in a module

// index.js
export default function() {... }// The anonymous function can be given any name
import aaa from './index.js'
Copy the code

import

The import command is used to input functions provided by other modules

import { a, b, c } from './index.js';

// Use it directly
console.log(a);
console.log(b);
console.log(c);
Copy the code

The import command can also rename loaded modules

import { a as st1, b as st2, c as st3 } from './index.js';
Copy the code
  • importThe variables in the command input are read-only because they are essentially input interfaces, that is, interfaces are not allowed to be overwritten in scripts that load modules
import {a} from './xxx.js'

a = {}; // Syntax Error : 'a' is read-only;
Copy the code

In the above code, the script loads variable A and reassigns it to an error because A is a read-only interface. However, if A is an object, overwriting a’s properties is allowed.

import { a } from './xxx.js'

a.foo = 'hello'; // It is valid
Copy the code
  • The from after import specifies the location of the module file, which can be a relative or absolute path. If you don’t have a path but just a module name, you must have a configuration file that tells the JavaScript engine where the module is.

  • The import command is promoted to the top of the module and executed first.

  • Because import is executed statically, you cannot use expressions and variables, which are syntactic structures that are only available at run time.

/ / an error
import { 'f' + 'oo' } from 'my_module';

/ / an error
let module = 'my_module';
import { foo } from module;

/ / an error
if (x === 1) {
  import { foo } from 'module1';
} else {
  import { foo } from 'module2';
}
Copy the code
  • importStatement in nofromIf the import of the same module is executed multiple times, it is executed only once
import 'lodash';
import 'lodash';
Copy the code
  • If the import statement is executed for the same module, it is equivalent to loading it only once
import { foo } from 'my_module';
import { bar } from 'my_module'; // This is not recommended

/ / is equivalent to
import { foo, bar } from 'my_module';
Copy the code

Composite writing

If the same module is input and then output within a module, the import statement can be written together with the export statement.

export { foo, bar } from 'my_module';

// It can be used as an example
import { foo, bar } from 'my_module';
export { foo, bar };
Copy the code

import()

The ES2020 proposal introduces an import() function that supports dynamic loading of modules and returns a Promise object.

import(module)
Copy the code

And CommonJs

  • The CommonJS module prints a copy of the value, the ESM module prints a reference to the value.
  • The CommonJS module is run time loaded and the ESM module is compile time output interface.
  • CommonJS modulerequire()Synchronous loading module, ES6 moduleimportCommands are loaded asynchronously, with a separate module-dependent parsing phase.

CommonJS modules can only determine these things at run time.

/ / CommonJS module
let { stat, exists, readfile } = require('fs');

/ / is equivalent to
let _fs = require('fs');
let stat = _fs.stat;
let exists = _fs.exists;
let readfile = _fs.readfile;
Copy the code

The above code essentially loads the FS module as a whole, generates one object, and then reads three methods from those three objects. This loading is called runtime loading, because the object is only available at runtime, making it completely impossible to do “static optimization” at compile time.

  • NodeJsThe ESM module is supported from version 13.2

CommonJS Module Loads the ESM module

CommonJs cannot load ESM modules through require(), only through import()

(
  async() = > {await import(modlue)
  }
)()
Copy the code

One reason require() does not support the ESM module is that it is loaded synchronously, whereas ES6 modules can use top-level await commands internally and thus cannot be loaded synchronously.

The ESM module is loadedCommonjs

The IMPORT command for ESM modules can load CommonJs modules, but only as a whole, not as a single output item