1.导入导出
- commonjs采用module.exports/require 的方式,最终返回的对象是module.exports对象,但在导出时,this,exports,module.exports是同一块内存空间,除非对三者重新赋值。
- esm采用export/import的方式,可以使用默认导出和具名导出,对于默认导出的,可以直接使用import xxx from;
对于具名导出的,需要使用import { xxx } from;同时还可使用as重新命名,或者使用import * from,*是包含所有
具名导出的对象
2.查找策略
- 文件名查找:commonjs支持模糊匹配,如果有对应路径的文件名,则直接使用该文件,如果没有,则会尝试添加.js、.json、.node等后缀名
- 目录查找:如果目录下有package.json,则会匹配main字段对应文件,如果没有,则会会尝试加载目录下的index.js或index.node文件
- node_modules查找:会逐级向上查找node_modules,直至找到后执行目录查找策略
- 文件名/目录查找:esm则遵循严格的路径名查找
- node_modules查找:如果目录下有package.json,则会匹配exports字段对应文件,否则使用index文件
3.加载
- commonjs是同步加载,相当于立即执行require函数,并缓存结果
- esm是异步加载的,对于import,会在先解析依赖树,然后按依赖树到顺序异步加载模块,等到所有模块加载完后,才开始执行代码;对于import(),其返回一个promise,需等待它完成,才能获取加载结果
4.缓存机制
- commonjs在每个模块代码执行完后,会将其结果缓存,当require相同路径时,会直接返回缓存结果
- esm中每个模块的代码也会将相同路径的结果缓存,但是由于esm中导出的内容都是静态绑定的,所以会出现类似闭包的问题,导入的变量会随着模块内部状态的变化而更新
// counter.mjs
export let count = 0;
export function increment() {
count++;
}
// main.mjs
import { count, increment } from './counter.mjs';
console.log("Initial count:", count); // 0
increment();
console.log("After increment:", count); // 1
5.清除缓存
- commonjs可以通过require.cache手动清除缓存
- esm不支持手动清除缓存,但是可以通过import()给url增加参数绕过缓存
(async () => {
const moduleA = await import(`./example.mjs?${Date.now()}`);
console.log(moduleA.value);
})();
6.TS中的查找策略
-
"moduleResolution": "node"
-
文件查找:
依次寻找: /src/myModule.ts /src/myModule.tsx /src/myModule.d.ts /src/myModule/package.json(访问 "types" 字段) /src/myModule/index.ts /src/myModule/index.tsx /src/myModule/index.d.ts -
node_modules查找
/src/node_modules/axios.ts /src/node_modules/axios.tsx /src/node_modules/axios.d.ts /src/node_modules/axios/package.json(访问"types"字段) /src/node_modules/@types/axios.d.ts /src/node_modules/axios/index.ts /src/node_modules/axios/index.tsx /src/node_modules/axios/index.d.ts 如果当前目录没找到,继续向上再来一次 /node_modules/axios.ts /node_modules/axios.tsx /node_modules/axios.d.ts /node_modules/axios/package.json(访问"types"字段) /node_modules/@types/axios.d.ts /node_modules/axios/index.ts /node_modules/axios/index.tsx /node_modules/axios/index.d.ts 如果当前目录没找到,继续向上再来一次...... ...... -
TS不会帮我们处理模块说明符,所以在编译后,在esm环境下,仍然无法识别我们的路径别名,这一点可以在import的时候采用js后缀的url路径
-
-
"moduleResolution": "node16/nodeNext"
-
在声明了package中的exports配置时,是高于types指定的配置的,具体查找顺序如下
/src/node_modules/axios.ts /src/node_modules/axios.tsx /src/node_modules/axios.d.ts /src/node_modules/axios/package.json(优先访问"exports"字段,后访问"types"/"main"/"module"字段) /src/node_modules/@types/axios.d.ts /src/node_modules/axios/index.ts /src/node_modules/axios/index.tsx /src/node_modules/axios/index.d.ts 如果当前目录没找到,继续向上再来一次 /node_modules/axios.ts /node_modules/axios.tsx /node_modules/axios.d.ts /node_modules/axios/package.json(优先访问"exports"字段,后访问"types"/"main"/"module"字段) /node_modules/@types/axios.d.ts /node_modules/axios/index.ts /node_modules/axios/index.tsx /node_modules/axios/index.d.ts 如果当前目录没找到,继续向上再来一次...... ......
-