这是我参与8月更文挑战的第20天,活动详情查看:8月更文挑战
模块解析策略
什么是模块解析
模块解析是指编译器在查找导入模块内容时所遵循的流程。
相对与非相对模块导入
根据模块引用是相对的还是非相对的,模块导入会以不同的方式解析。
相对导入
相对导入是以 /、./ 或 ../ 开头的引用
// 导入根目录下的 m1 模块文件
import m1 from '/m1'
// 导入当前目录下的 mods 目录下的 m2 模块文件
import m2 from './mods/m2'
// 导入上级目录下的 m3 模块文件
import m3 from '../m3'
非相对导入
所有其它形式的导入被当作非相对的
import m1 from 'm1'
模块解析策略
为了兼容不同的模块系统(CommonJS、ESM),TypeScript 支持两种不同的模块解析策略:Node、Classic,当 --module 选项为:AMD、System、ES2015 的时候,默认为 Classic ,其它情况为 Node
--moduleResolution 选项
除了根据 --module 选项自动选择默认模块系统类型,我们还可以通过 --moduleResolution 选项来手动指定解析策略
// tsconfig.json
{
...,
"moduleResolution": "node"
}
Classic 模块解析策略
该策略是 TypeScript 以前的默认解析策略,它已经被新的 Node 策略所取代,现在使用该策略主要是为了向后兼容
相对导入
// /src/m1/a.ts
import b from './b.ts'
解析查找流程:
- src/m1/b.ts
默认后缀补全
// /src/m1/a.ts
import b from './b'
解析查找流程:
-
/src/m1/b.ts
-
/src/m1/b.d.ts
非相对导入
// /src/m1/a.ts
import b from 'b'
对于非相对模块的导入,则会从包含导入文件的目录开始依次向上级目录遍历查找,直到根目录为止
-
/src/m1/b.ts
-
/src/m1/b.d.ts
-
/src/b.ts
-
/src/b.d.ts
-
/b.ts
-
/b.d.ts
Node 模块解析策略
该解析策略是参照了 Node.js 的模块解析机制
相对导入
// node.js
// /src/m1/a.js
import b from './b'
在 Classic 中,模块只会按照单个的文件进行查找,但是在 Node.js 中,会首先按照单个文件进行查找,如果不存在,则会按照目录进行查找
- /src/m1/b.js
- /src/m1/b/package.json中'main'中指定的文件
- /src/m1/b/index.js
非相对导入
// node.js
// /src/m1/a.js
import b from 'b'
对于非相对导入模块,解析是很特殊的,Node.js 会这一个特殊文件夹 node_modules 里查找,并且在查找过程中从当前目录的 node_modules 目录下逐级向上级文件夹进行查找
- /src/m1/node_modules/b.js
- /src/m1/node_modules/b/package.json中'main'中指定的文件
- /src/m1/node_modules/b/index.js
- /src/node_modules/b.js
- /src/node_modules/b/package.json中'main'中指定的文件
- /src/node_modules/b/index.js
- /node_modules/b.js
- /node_modules/b/package.json中'main'中指定的文件
- /node_modules/b/index.js
TypeScript 模块解析策略
TypeScript 现在使用了与 Node.js 类似的模块解析策略,但是 TypeScript 增加了其它几个源文件扩展名的查找(.ts、.tsx、.d.ts),同时 TypeScript 在 package.json 里使用字段 types 来表示 main 的意义
命名空间
在 TS 中,export 和 import 称为 外部模块,TS 中还支持一种内部模块 namespace,它的主要作用只是单纯的在文件内部(模块内容)隔离作用域
namespace k1 {
let a = 10;
export var obj = {
a
}
}
namespace k2 {
let a = 20;
console.log(k1.obj);
}