This is the 11th day of my participation in the August More Text Challenge. For details, see:August is more challenging

preface

Prior to ES6, the community developed several module loading schemes, the most prominent of which were CommonJS and AMD. The former is for the server and the latter for the browser. ES6 implements modular functionality at the language standard level and is fairly simple enough to replace CommonJS and AMD specifications as a universal modular solution for browsers and servers.

This article focuses on the Module syntax of ES6 and the related proposals.

Module embedding

A

<script type="module"> 
 // Module code
</script> 
<script type="module" src="path/to/myModule.js"></script>
Copy the code

It has the following characteristics:

  • For multiple module labels, they are executed in writing order.
  • Engine parses to<script type="module">The module file is downloaded immediately after the tag, but execution is delayed until the document is parsed.
  • The same module is only loaded once.
<! -- Second execution --> 
<script type="module"></script> 
<! -- Third execution --> 
<script type="module"></script> 
<! -- First execution --> 
<script></script>// Load the external file as a module<! -- Second execution --> 
<script type="module" src="module.js"></script> 
<! -- Third execution --> 
<script type="module" src="module.js"></script> 
<! -- First execution --> 
<script><script>
Copy the code

export

Module exports use the export keyword.

Export statements can only be used in the outermost layer of a module.

/ / allow
export./ / not allowed
if (condition) { 
 export. }Copy the code

Named after the export

Named export Specifies that the variables to be exported must be declared and cannot be default variables.

The exported Module is actually a Module object, and the exported variable is the value of that object.

Module {__esModule: true.Symbol(Symbol.toStringTag): "Module"}
Line: Object
foo: "bar"
Symbol(Symbol.toStringTag): "Module"
__esModule: trueGet Line: ƒ () Get foo: ƒ ()__proto__: Object
Copy the code

Each export

A one-by-one export is to export each variable to be exported separately, but if the variable declaration is not on the same line as the export, export is to include the exported value in parentheses.

/ / allow
const foo = 'foo'; 
export { foo }; 
/ / allow
export const foo = 'foo'; 
// Allow, but avoid
export { foo }; 
const foo = 'foo';

/ / error
export foo
Copy the code

Collective export

Declare variables one by one and export declarations at the end.

// Export one by one
export const foo = 'foo'; 
export const bar = 'bar'; 
export const baz = 'baz';

// Group export
const foo = 'foo'; 
const bar = 'bar'; 
const baz = 'baz'; 
export { foo, bar, baz };
Copy the code

names

You can also provide aliases when exporting, which must be specified in the curly braces syntax of the export clause.

const foo = 'foo'; 
export { foo as myFoo };

const foo = 'foo'; 
const bar = 'bar'; 
const baz = 'baz'; 
export { foo, bar as myBar, baz };
Copy the code

Therefore, in the exported module, bar will exist under the property name myBar.

The default is derived

The properties of the named export are returned as property values of the Module object. Foreign imports must refer to the Module values using the object resolution operator.

The default export allows you to export variables directly from a template without wrapping them in a Module object.

It has the following characteristics:

  • Each module can only have one default export. Repeating the default export will causeSyntaxError.
  • The default exported property value is the original value of the property in the module.
  • The default exported property is treated as an anonymous property when imported, so you can alias it directly.
  • By default, the exported value is treated as an anonymous value, so the exported properties do not have to be declared.

Common derived form

const foo = 'foo'; export default foo; const foo = 'foo'; // equivalent to export default foo; export { foo as default }; // Export default 'foo'; export default 123; export default /[a-z]*/; export default { foo: 'foo' }; Export default function() {} export default function foo() {} export default function*() {} export default class {}Copy the code

Errors in the form of

// Variable declarations cannot appear in the inline export by default
export default const foo = 'bar';

// Only identifiers can appear in the export clause. 123 is a constant
export { 123 as default }

// The alias must be specified in the curly braces syntax of the export clause
export const foo = 'foo' as default;
Copy the code

The import

Like export, import can only be used in the outermost layer.

Related usage:

import { foo } from './fooModule.js';

// Foo is the default export and the rest is named export
import foo, * as Foo './foo.js';
Copy the code

Notes:

  • Imported modules are read-only, equivalent to variables declared as const.

  • When doing bulk imports with *, named exports assigned to aliases act as if they had been frozen with object.freeze ().

  • If the value of the imported property is a basic data type, modifying it directly will result in a not defined error. However, you can modify the properties of the exported object.

//foo.js
export default {name:"foo.js"}
export const foo = "foo.js"

//bar.js
import foo, * as Foo './foo.js'; // Import the default export and named export of the Module respectively, and all named exports are aliased as a Module object Foo
foo = 'foo'; // Modify the exported value directly
Foo.foo = 'foo'; // Error, modify the properties of the exported Module object
delete Foo.foo // Error, modify the properties of the exported Module object
foo.bar = 'bar'; // If yes, you can modify the properties of the exported object
Copy the code

The difference between named and default exports is also reflected in their imports. Instead of listing each identifier, you can use * to batch fetch and assign to the alias that holds the exported collection:

const foo = 'foo', bar = 'bar', baz = 'baz'; 
export { foo, bar, baz } / / export

import * as Foo from './foo.js'; / / import
console.log(Foo.foo); // foo 
console.log(Foo.bar); // bar 
console.log(Foo.baz); // baz
Copy the code

names

To alias imported properties, use the as keyword in the braces of the import statement:

import { foo, bar, baz as myBaz } from './foo.js'; 
console.log(foo); // foo 
console.log(bar); // bar 
console.log(myBaz); // baz
Copy the code

Default import and named import

The default export is as if the entire module were an exported value. You can import it using the default keyword and giving it an alias. You can also use no braces, in which case the specified identifier is the alias of the default export:

// The first sentence is equivalent to the second
import { default as foo } from './foo.js'; 
import foo from './foo.js';
Copy the code

If the module exports both the named export and the default export, you can get both in the import statement. This can be obtained by listing the specific exported identifiers in sequence, or by using * :

import foo, { bar, baz } from './foo.js'; 
import { default as foo, bar, baz } from './foo.js'; 
import foo, * as Foo from './foo.js';
Copy the code

Load modules only

If you do not need an export of the module, but only need to load and execute the module to use the results of its run, you can load it by path only:

import './foo.js';
Copy the code

Transfer the export

Syntactically, it is equivalent to the compound writing of export and import. After importing a module into another module, it can be exported as a property of that module.

// All named exports of a module are grouped together and exported via *
export * from './foo.js';
Copy the code

In this way, you can convert the default export of a module to a named export, or vice versa.

Change the default export to a named export

//foo.js
export default 'foo';
//bar.js
export {default as bar} from './foo.js'

Copy the code

Change the named export to the default export

//foo.js
export const foo = 'foo';
//bar.js
export { foo as default} from './foo.js'
Copy the code

Reuse the default export as the default export for the current module

//foo.js
export default 'foo';
//bar.js
export { default } from './foo.js';
Copy the code

TC39:export default from

TC39:export default from stagE1, the proposed module export method is not provided in ES6, because the transfer export syntax is very similar to the import syntax. Almost every import syntax has a corresponding transfer export syntax, but one is missing:

export someIdentifier from "someModule";
export someIdentifier, { namedIdentifier } from "someModule";

/ / corresponds to
import someIdentifier from "someModule";
import someIdentifier, { namedIdentifier } from "someModule";
Copy the code

The purpose of this syntax is to import the default export of a module and convert it to the named export of the module.

export someIdentifier from "someModule";
/ / equivalent to the
import someIdentifier from "someModule";
export {someIdentifier}
Copy the code

The solution is to use the Babel plugin @babel/plugin-proposal-export-default-from

Asynchronous loading

The ES2020 proposal introduces the import() function to support dynamic loading of modules.

import(modulePath)
Copy the code

Unlike import and export, which are keywords, import() is a function that takes an identifier argument, so the identifier is dynamic and concatenable.

const name = 'chart'

import(`@/components/${name}`)
    .then(module= >{
        //TODO
    })
Copy the code

Import () returns a Promise object that will be used as an argument to the then method after the module is successfully loaded.

conclusion

Import the grammar

expression The import module Export module The local name
import v from "mod"; "mod" "default" "v"
import * as ns from "mod"; "mod" "*" "ns"
import {x} from "mod"; "mod" "x" "x"
import {x as v} from "mod"; "mod" "x" "v"
import "mod";
import()

Export the grammar

expression The import module Export module The local name Export name
export var v; null null "v" "v"
export default function f(){}; null null "f" "default"
export default function(){}; null null "*default*" "default"
export default 42; null null "*default*" "default"
export {x}; null null "x" "x"
export {x as v}; null null "x" "v"
export {x} from "mod"; "mod" "x" null "x"
export {x as v} from "mod"; "mod" "x" null "v"
export * from "mod"; "mod" "*" null null

The new proposals

expression The import module Export module The local name Export name
export v from "mod"; "mod" "default" null "v"