When you are asked about front-end modularity? (2023)

Preface

Recently, a former colleague chatted with me. When he went for an interview, he was asked by the interviewer about front-end modularity. His answer was the interviewer's "You said it, but it seems you didn't say it." He was hit hard and asked me doubting about life, what exactly is front-end modularity? He said that he seemed to know, but he seemed to be unable to explain why, so here is the content about modularization, let’s take a look at it together.

1. Brief description of modularization

Divide complex code into different modules according to different functions and maintain them separately to improve development efficiency and reduce maintenance costs. Modularization is just an idea and theory, and does not include specific implementation.

2. The birth of modularity

To put it simply, what can't be done by one person is divided into multiple people, each person is responsible for a piece of content (module), and finally the things done by each person are assembled into a whole.

Although there are many stages in the evolution of front-end modularization, the ultimate goal is to split the modules and divide the work for development. After everyone completes a module, they expose some parameters and methods to the caller. The path of evolution is nothing more than adhering to the How to optimize rows in more elegant, highly decoupled, highly compatible and other directions

3. The evolution of modularity

The first stage: the way to divide modules based only on files

The specific method is to put each function and its related status data into different files separately. It is agreed that each file is an independent module. To use a module is to introduce this module into the page, and then directly call the module in the module. Members (variables/functions) Disadvantages: All modules work directly globally, there is no private space, all members can be accessed or modified outside the module, and when there are too many modules, naming conflicts are easy to occur, and modules cannot be managed. dependencies between

Second stage: Each module exposes a global object, and all module members are mounted into this object. The
specific method is based on the first stage, by "wrapping" each module into a global object, which is a bit It feels like adding a "namespace" to the members in the module. The possibility of naming conflicts is reduced through "namespace", but there is also no private space. All module members can also be accessed or modified outside the module, and dependencies between modules cannot be managed.

The third stage: Use Immediately-Invoked Function Expression (IIFE) to provide private space for the module. The
specific method is to place each module member in a private scope provided by a function. For those that need to be exposed to the outside Members implement the concept of private members by hanging them on the global object. Private members can only be accessed through closures within module members.

The fourth stage: Use IIFE parameters as dependency declarations.
The specific method is to use the parameters of the immediate execution function to transfer module dependencies based on the third stage. This makes the relationship between each module more obvious.

The fifth stage: Modular specification
Require.js provides the AMD modular specification and an automated module loader---the emergence of the modular specification, and then more standards followed, including CommonJS and CMD. . .

4. The emergence of modular specifications

Required: Modular Standard + Module Loader

CommonJS specification (a set of standards proposed by nodejs)

Standard: A file is a module. Each module has a separate scope. Members are exported through module.exports. Modules are loaded through the require function.

Disadvantages: CommonJS loads modules in synchronous mode, and the node execution mechanism is to load the module at startup. There is no need to load the module during execution, just use it. There will be no problem in node; however, page loading on the browser side will cause a large number of synchronous requests. , and the efficiency is low

AMD (Asynchronous Module Definition) --- asynchronous module definition specification

Modules are defined through the define function

Advantages: Currently, most third-party libraries support AMD specifications

Disadvantages: Use complex modules to divide them carefully, and module JS files will be frequently requested.

Sea.js (launched by Taobao) + CMD (Common Module Definition Specification)

The CMD specification is similar to the CommonJS specification and was later compatible with Require.js.

Require.js

Provides AMD modularization specifications, and an automated module loader provides the require function to load modules

5. Modular default specification

The browser environment uses ES Modules
nodejs uses CommonJS

6. About ES Modules

Use ES Modules by adding the attribute type = module to the script

ESM automatically adopts strict mode, ignore 'use strict'.
Each ES Module runs in a separate private scope.
ESM requests external JS modules through CORS.
The script tag of ESM will delay the execution of the script.
For our daily front-end development, In fact, the most commonly used ones are es modules. Here is a brief introduction to some common ways of writing this specification.

ES Modules export

Single export

export const name = 'foo module'
export function hello () {
    console.log('hello')
}

 Merge export

const name = 'foo module'
function hello () {
    console.log('hello')
}
class Person {}
export { name, hello, Person }

 Merge export and rename

const name = 'foo module'
function hello () {
    console.log('hello')
}
class Person {}
export {
    name1: name,
    hello2: hello,
    Person3: Person
}

 Default export

const name = 'foo module'
function hello () {
    console.log('hello')
}
class Person {}

export default name;

 Things to note when importing and exporting ES Modules. The difference between exporting literals and exporting modules.

Export literals (such as objects): export default { name, age }
Note: import {name, age} from 'modulename' The imported module cannot use the values ​​​​of name and age.

Export module:
export { name, age }
import {name, age} from 'modulename' The imported module can use the values ​​​​of name and age.

Reason: import imports the internal use of the module

Export module reference

Note: export exposes the reference relationship (address) of the module, and is read-only and cannot be modified (trying to modify will report an error --- Uncaught TypeError: Assignment to constant variable)

important point

  1. In CommonJS, the entire module is first imported as an object, and then the required members are constructed from the object const { name, age } = require('./module.js')
  2. { } in ES Module is a fixed syntax, which means directly extracting module export members import { name, age } from './module.js'
  3. Importing members does not make a copy, but directly imports the reference address of the module member. That is to say, the variables obtained by import and the variables imported by export are in the same space in memory. Once the members in the module are modified, they will also be modified at the same time.
  4. The imported module member variable is read-only name = 'tom' // error
  5. What is imported is an object, and the reading and writing of the object's attributes are not affected name.xxx = 'xxx' // Normal

ES Modules import

Import file path

import('./module.js').then(function (module) {
    //所有模块成员都在module参数里
})
  1. name to be quoted
  2. ./ on the relative path cannot be omitted
  3. Absolute paths and full urls can be used

Whether to extract module members when importing a module

  1. Import modules and extract module members import {} from './module.js'
  2. Importing modules does not extract module members import './module.js' (useful when importing sub-functional modules that do not require external control)

Import multiple or all members of a module at the same time

import * as mod from './module.js' needs to put all extracted members into an object. Through as, the imported members will appear as object attributes.

Dynamic import of modules (available when certain conditions need to be met before importing)

import ('./module.js') returns the way promise takes module members:

import('./module.js').then(function (module) {
    //所有模块成员都在module参数里
})

Import both named members and default members

import { name, age, default as other} from './module.js'
or
import other, { name, age} from './module.js'other represents all default exported members of the module module

ES Modules in Node.js

ES Modules in Node.js - Interacting with CommonJS

CommonJS modules can be imported into ES Module

es-module.mjs

import mod from './commonjs.js'
console.log(mod)

 Members cannot be extracted directly. Note that import does not deconstruct the exported object.

import { foo } from './commonjs.js'
console.log(foo)
export const foo = 'es module export value'

 CommonJS modules will always export only one default member

commonjs.js

module.exports = {
    foo: 'commonjs exports value'
}
exports.foo = 'commonjs exports value'

 ES Module cannot be loaded through require in CommonJS module

const mod = require('./es-module.mjs')
console.log(mod)

 ES Modules in Node.js - Differences from CommonJS

Example:

// 加载模块函数
console.log(require)

// 模块对象
console.log(module)

// 导出对象别名
console.log(exports)

// 当前文件的绝对路径
console.log(__filename)

// 当前文件所在目录
console.log(__dirname)
1、ESM 中无法引用CommonJS中的那些模块全局成员
2、require, module, exports 可通过import 和export 代替
3、__filename 和 __dirname 通过import 对象的 meta 属性获取
const currentUrl = import.meta.url
console.log(currentUrl)
// 通过 url 模块的 fileURLToPath 方法转换为路径
import { fileURLToPath } from 'url'
import { dirname } from 'path'
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
console.log(__filename)
console.log(__dirname)

ES Modules in Node.js - further support in new version

  1. For versions after Node v12, you can change the default module system to ES Module by adding the type field to module in package.json. At this time, there is no need to modify the file extension to .mjs.
  2. If you need to continue using CommonJS with type=module, you need to change the file extension to .cjs

package.json:

{ "type": "module" }

 ES Modules in Node.js - Babel compatible solution

Install babel: yarn add @babel/node @babel/core @babel/preset-env --dev
run babel-node test: yarn babel-node index.js --presets=@babel/preset-env
**.babelrc configuration **

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

7. Summary

Questions are generally asked from the general to the details.
If the interview asks questions about modularization, answer them in a clear and organized manner. Answer the general concept first. If there are follow-up questions, then answer based on the details.

Tip: The person interviewing you does not necessarily need a deep understanding of what you have to say in one breath. You can use simple and easy-to-understand vernacular, clear and coherent, and throw it out first. For example: What is the difference between XXXX and YYYY
? Answer: There are 3 differences...

Q: Can you talk about front-end modularization
? A: Modular development method can improve the code reuse rate and facilitate code management. Usually a file is a module, which has its own scope and only exposes specific variables and functions.

Q: What are the standards for modularization?
Answer: The currently popular js modularization specifications include CommonJS, AMD, CMD and ES6 module system.

Q: What are some differences between ES Modules and CommonJS? Answer
:

  1. Using the syntax level, CommonJs uses module.exports, exports to export, and require to import; EESModule uses export to export and import to import.
  2. CommonJs loads modules at runtime, and ESModule determines module dependencies during static compilation.
  3. ESModule will raise all imports to the top during compilation, CommonJs will not raise require
  4. What CommonJs exports is a value copy, and the loading result will be cached. Once the value is modified internally, it will not be synchronized to the outside. ESModule is an exported reference, and internal modifications can be synchronized to the outside.
  5. The top-level this in CommonJs points to the module itself, while the top-level this in ESModule points to undefined
  6. CommonJS loads the entire module and all interfaces. ESModule can load one of the interfaces separately.

Guess you like

Origin blog.csdn.net/YN2000609/article/details/132409524