diff --git a/docs/note/Front-end Engineering.md b/docs/note/Front-end Engineering.md
index 09f0adff..1c16c16c 100644
--- a/docs/note/Front-end Engineering.md
+++ b/docs/note/Front-end Engineering.md
@@ -257,6 +257,10 @@ console.log(name, age) // Ziu 18
- 当通过`require`导入时:`const env = require('env.js')`
- `env`这个变量等于`env.js`中的`exports`对象
- 本质上是`env`是`exports`对象的引用赋值
+ - `{ id: '...', exports: { ... }, loaded: true, ... }`
+- 后续即使再次执行`require`导入模块,模块中的代码也不会重新执行(`module.loaded`属性)
+ - 当从模块中取值时,会从已经加载的`exports`对象缓存上取值
+
::: code-group
@@ -402,3 +406,422 @@ console.log(utils.age) // undefined
- CommonJS会被WebPack解析
- 将CommonJS代码转化为bundle 浏览器可以直接运行
+### ESModule
+
+- ES6 模块采用**编译时加载**,使得**编译时就能确定模块的依赖关系**,有助于**静态优化**
+- CommonJS模块在运行时加载,且必须借助对象加载模块内容
+
+#### `export`和`import`用法概览
+
+ESModule借助`export`和`import`导入导出内容,需要注意的是导入导出的并不是对象
+
+`export`定义的是当前模块导出的**接口**,`import`可以导入来自其他不同模块的**接口**
+
+- `export default`可以设置默认导出对象
+- `export { ... }`可以统一导出多个内容
+- `export`和`import`都可以使用`as`关键字重命名导出/导入的接口
+- `import * from 'xxx'` `export * from 'xxx'`批量导入/导出
+
+::: code-group
+
+```js [utils.js]
+// utils.js
+export function sum(a, b) {
+ return a + b
+}
+export function sub(a, b) {
+ return a - b
+}
+export default function log(...args) {
+ console.log(...args)
+}
+export {
+ name: 'Ziu',
+ age: 18
+}
+export const ENV_VARIABLE = 'Hello, World!'
+```
+
+```js [index.js]
+// index.js
+import { sum, sub, name, age, ENV_VARIABLE } from './utils'
+import log from './utils.js'
+
+sum(1, 2) // 3
+sub(2, 3) // -1
+log(name, age, ENV_VARIABLE) // 'Ziu' 18 'Hello, World!'
+```
+
+:::
+
+需要注意的是,在浏览器中要使用ESModule,需要为``
+
+- 当浏览器解析到`type="module"`的JS代码后,会**分析模块中导入的ESModule模块**
+- 每导入一个ESModule模块,**浏览器都会发起一个HTTP请求去加载它**
+- 在本地运行时加载不同协议头的文件会遇到跨域问题,需要开启本地Web服务器
+
+另外,**`export`与`import`必须位于模块的顶层**,如果位于作用域内会报错,因为这就**无法对代码进行静态分析优化了**
+
+#### `export`详解
+
+`export`有两种导出方式:
+
+- 命名导出 `export const name = 'Ziu'` `export { v1, v2 } export * from 'xxx'`
+ - 导出时需要指定名字
+ - 导入时也需要知道对应的名字
+- 默认导出 `export default AGE = 18`
+ - 在从其他位置导入时需要为此默认导出指定新的名字
+ - 给用户方便:不必阅读文档就可以加载模块
+
+#### 值的动态绑定
+
+- ESModule模块通过`export`语句输出的接口,与其对应的值是**动态绑定关系**,即通**过该接口,可以取到模块内部实时的值**
+- CommonJS模块输出的是值的缓存,不存在动态更新
+
+我们援引之前介绍CJS时的案例,**将后缀名改为`mjs`即可在Node中运行ESModule模块代码**
+
+初始获得的`a`值为0,经过1s后,在`utils.mjs`中修改了a的值,这时导入`utils.mjs`模块的其他模块可以获取到`a`最新的值
+
+::: code-group
+
+```js [utils.mjs]
+// utils.mjs
+export let a = 0
+
+// 1s后修改a值
+setTimeout(() => {
+ a = 1
+}, 1000)
+```
+
+```js [index.mjs]
+// index.mjs
+import { a } from './utils.mjs'
+
+console.log(a) // 0
+
+setTimeout(() => {
+ console.log(a) // 1
+}, 1500)
+```
+
+:::
+
+- 需要注意的是,导入的其他模块的变量是不允许被修改的,因为`index.mjs`导入的本质是一个接口
+- 如果从其他模块导入的是一个对象,也不推荐修改导入内容的任何值,最好将其当做完全只读
+
+拓展阅读:CommonJS与ESModule加载模块的异同
+
+#### `import`详解
+
+检查下述代码:
+
+```js
+foo()
+
+import { foo } from 'foo'
+```
+
+- `import`命令具有提升效果,会提升到整个模块的顶部
+- `import`的执行早于函数的调用,`import`命令是在编译阶段执行的,在代码运行之前
+- 由于`import`是静态执行,所以不能使用表达式和变量(只有运行时才有值)
+
+```js
+import 'lodash'
+import 'lodash'
+```
+
+- 如果仅仅导入了一个模块,那么该模块的代码会被执行,但是没有任何变量被导入
+- 如果同一模块被导入多次,那么导入操作只会被执行一次
+
+```js
+import * from 'utils'
+add(1, 2)
+
+export * from 'utils'
+```
+
+- 可以通过`*`一次性导入模块中所有导出的变量、函数、类
+- 也可以实现二者的复合操作:导入全部模块的同时导出全部模块
+
+#### `import()`函数
+
+通过`import`命令导入的模块是静态的,会被提升到模块顶部,并不支持条件导入
+
+ES2020引入了`import()`函数,可以通过`import()`函数实现条件导入,动态加载ESModule模块
+
+```js
+const main = document.querySelector('main');
+
+import(`./section-modules/${someVariable}.js`)
+ .then(module => {
+ module.loadPageInto(main);
+ })
+ .catch(err => {
+ main.textContent = err.message;
+ })
+```
+
+- 返回值是一个Promise对象,可以通过`await`同步地操作它
+- `import()`函数可以在模块外的JS脚本中使用,用于**在运行时加载外部模块**,类似于`require()`
+- 区别于`require()`,`import()`是异步加载模块
+
+通过`.then`函数处理导入的模块时,行为和`import`是相同的:
+
+- 如果有默认导出对象,则`.then`入参为默认导出对象
+- 可以通过解构直接取到模块中导出的变量或函数:`.then(({ add, sub }) => { ... })`
+
+**应用场景**
+
+按需加载:按钮点击后才加载相关的JS文件
+
+```js
+btn.addEventListener('click', () => {
+ import('./dialogBox.js')
+ .then(dialogBox => {
+ dialogBox.open()
+ })
+ .catch(err => console.log(err))
+})
+```
+
+条件加载:根据主题色加载不同JS文件
+
+```js
+if(darkMode) {
+ import('dark.js').then(() => ...)
+} else {
+ import('light.js').then(() => ...)
+}
+```
+
+传入动态值
+
+```js
+let moduleName = () => ['Home', 'History', 'User'][0]
+import(`./${moduleName()}.js`)
+```
+
+#### `import.meta`
+
+ES2020引入了`import.meta`,它仅能在模块内部使用,包含一些模块自身的信息,即模块元信息
+
+- `import.meta.url` 返回当前模块的URL路径
+ - 浏览器加载ESModule都是通过HTTP发起请求
+ - 例如当前模块为`fetchData.js`,要在模块内引入一个名为`data.json`的数据:
+ - `import( new URL('data.json', import.meta.url) )`
+ - Node.js环境下,该值都是`file://`协议的链接
+- `import.meta.scriptElement`
+ - 浏览器特有的属性
+ - 返回加载模块的`