Modular development

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!

Keywords: Javascript Front-end

Added by lazytiger on Wed, 09 Feb 2022 11:47:00 +0200