Modularization is the first mock exam in the most important front end development paradigm. Modularity is only thinking.
Modular evolution process
Stage1 file division method
- Pollution global scope
- Naming conflict problem
- Unable to manage module dependencies
- Early modularity depended entirely on conventions
Stage2 namespace mode
- Each module exposes only one global object to which all modules are attached
- Reduces the possibility of naming conflicts
- However, there is no private space, and module members can be accessed or modified externally
- Dependencies between modules have not been resolved
Stage3 IIFE executes the function immediately
- Wrap the code with the immediate execution function, and mount the traversal to be output to a global object
- Variables have private space and can only be modified and accessed through closures
- Parameters are used as dependency declarations, which makes the dependency of each module obvious
Modular specification
1. CommonJS specification
- A file is a module
- Each module has a separate scope
- Through module Exports export members
- Load the module through the require function
- CommonJS loads modules in synchronous mode
2. AMD(Asynchronous Module Definition) asynchronous module specification
-
Module loader: require js
// Define a module define('module1', ['jquery', './module2'], function ($, module2) { return { start: function () { $('body').animate({ margin: '200px' }) module2() } } })
// Load a module require(['./module1'], function (module1) { module1.start() })
-
At present, most third-party libraries support AMD specification
-
AMD is relatively complex to use
-
Frequent module JS file requests
3. Sea.com launched by Taobao JS + CMD (common module definition) general module specification
// CMD specification (similar to CommonJS specification) define(function (require, exports, module) { // Introducing dependencies through require var $ = require('jquery') // Through exports or module Exports exposed members module.exports = function () { console.log('module 2~') $('body').append('<p>module2</p>') } })
4. ES Module
// ./modulejs const foo = 'es modules' export { foo } // ./app.js import { foo } from './module.js' console.log(foo) // => es modules
- Use strict mode automatically, ignoring 'use strict'
- Each ESM module is a separate private scope
- ESM requests external JS modules through CORS
- ESM's script tag delays script execution
ESModules
import usage
// It cannot be omitted js extension name CommonJS // CommonJS can load the index under the directory by loading the directory JS ESM cannot be a full path import { name } from "./module.js"; console.log(name); // The extension name and default file can be omitted in the later packaging operation JS this operation import { lowercase } from "./util/index.js"; console.log(lowercase); // Must start with a dot, same as CommonJS // The letter beginning ESM loads third-party modules artificially // Number of root directories starting with slash import { name } from "/04-import/module.js"; console.log(name); // Full URL import { name } from "http://localhost:52330/04-import/module.js"; // Module files on CDN can be referenced directly console.log(name); // --------------------------------------------------------- import {} from "http://localhost:52330/04-import/module.js"; // Abbreviation import "http://localhost:52330/04-import/module.js"; // It will not be loaded repeatedly. It can only be loaded once // --------------------------------------------------------- // Export a lot import * as mod from "./module.js"; console.log(mod); // So the import member is realized // mod.age = 19; // Still, nice cannot be changed // console.log(mod); // --------------------------------------------------------- var modulePath = "./module.js"; import { age } from modulePath // Uncaught SyntaxError: Unexpected identifier console.log(age); if (true) { import { age } from "./module.js"; } Uncaught SyntaxError: Unexpected token '{' // How to import dynamically? The import() function returns a promise import("./module.js").then((module) => { console.log(module.name); }); import { age, default as chris } from "./module.js"; console.log(age, chris); // Abbreviation import chris, { age } from "./module.js"; console.log(age, chris);
Simultaneous import of export (middleman)
// import { button } from "./button.js"; // import { avatar } from "./avatar.js"; // export { button, avatar }; // Note that if it is default, it needs to be renamed, otherwise it will be regarded as the default export of index itself export { button } from "./button.js"; export { avatar } from "./avatar.js";
Polyfill
browser-es-module-loader
-
Transfer the unrecognized ESM in the browser to babel for transformation
-
Files that need to be import ed are requested via ajax
-
- The requested code is converted through babel again
-
If supported, polyfill will be repeated twice
-
script nomodule
-
Development can produce and use dynamic parsing script with caution, and the efficiency is low
-
It should be compiled and can work directly in the browser
<script src="https://unpkg.com/browse/browser-es-module-loader@0.4.1/dist/babel-browser-build.js"></script> <script src="https://unpkg.com/browse/browser-es-module-loader@0.4.1/dist/browser-es-module-loader.js"></script> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>polyfill</title> </head> <body> <!-- IE incompatible --> <!-- Compile tool into ES5 Just do it --> <!-- polyfill Direct support for most browsers ESM characteristic --> <script nomodule src="https://unpkg.com/browse/browser-es-module-loader@0.4.1/dist/babel-browser-build.js" ></script> <script nomodule src="https://unpkg.com/browse/browser-es-module-loader@0.4.1/dist/browser-es-module-loader.js" ></script> <!-- Promise Undefined --> <!-- introduce promise ployfill --> <script nomodule src="https://unpkg.com/promise-polyfill@8.1.3/dist/polyfill.min.js" ></script> <script type="module"> import { name } from "./module.js"; console.log(name); </script> <script></script> </body> </html>
Import and export
Export form:
- variable
- function
- class
- default
- Curly braces are required for centralized export
Precautions for import and export
-
Imported is a constant = > cannot modify variable
-
- If you export an object, you can modify it
-
The curly bracket is not a direct deconstruction object
-
- However, the exported object can also be used or deconstructed
-
If the variables of the exported module change, the imported module will also change
-
- But if you export an object, you can't change it
ESM in Nodejs
nodejs supports ESM natively and can be used directly. For a period of time in history, it is not supported. You need to add – experimental modules
Interact with CJS
- CJS members can be loaded in ESM
- exports. It's module Alias for exports
- esm loading cjs module extraction requires a third-party variable to make a transition+
- commonjs is not allowed to load es module in node
Difference from CJS
- There is no global module member in CJS in ESM
// The way of import and export has changed require/module/exports => import/export // The way to get the file name has changed __filename => import.meta.url + fileURLToPath = __filename import { fileURLToPath } from "url"; const __filename = fileURLToPath(import.meta.url);
- dirname => dirname(__filename )
import { fileURLToPath } from "url"; import { dirname } from "path"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename);
- Wrap the current module as a formal parameter of a function (implement the private module scope)
other
If the extension name is set to cjs, mjs does not need to be set. If mjs is set, cjs does not need to be set.
.babelrc => ''presets":["@babel/preset-env"]
Support ESM through babel!