ts的模块解析策略ModuleResolution,路径别名BaseUrl & Paths以及虚拟目录rootDirs相关,而这几个配置项主要的作用和含义如下:
ModuleResolution
{
"compilerOptions": {
"moduleResolution": "node" // "node" or "classic"
}
}
TypeScript在编译时的模块解析策略,在不显式声明的情况下,针对CommonJS模块的策略默认为"node",其他规范模块(amd, system, umd, es2015, esnext)为"classic"。
大部分情况下你应该将其设置为"node","classic"主要用于对以前版本ts的兼容,这两种策略下的模块解析差别如下:
classic
相对路径引用
import { b } from "./moduleB"
当前文件所处目录为/root/src/folder/A.ts,在定位解析moduleB时,文件查找顺序如下:
/root/src/folder/moduleB.ts/root/src/folder/moduleB.d.ts
注意:引用不解析文件夹下的index文件/root/src/folder/index.ts,即文件无法将index.ts作为文件夹下模块的公共出口,文件引用需要带具体文件名。
非相对路径导入
import { b } from "moduleB"
当前文件所处目录为/root/src/folder/A.ts,在定位解析moduleB时,文件查找顺序如下:
/root/src/folder/moduleB.ts/root/src/folder/moduleB.d.ts/root/src/moduleB.ts/root/src/moduleB.d.ts/root/moduleB.ts/root/moduleB.d.ts/moduleB.ts/moduleB.d.ts
node
node参照的是Node中CommonJS的模块解析规范。
相对路径引用,不存在则将引用的地址视为文件夹,定位文件夹下是否有package.json(如果存在main字段,则定位到main指向的模块地址)
相对路径引用
import { b } from "./moduleB"
CommonJS的解析顺序如下:
- 先查找文件下命名为
moduleB.js的文件是否存在; - 将
moduleB视为文件夹,查找文件夹下是否存在package.json及声明main属性,符合条件则将模块解析定位为该属性键值对应的地址,如果存在{ "main": "lib/mainModule.js" },那么解析后模块定位为moduleB/lib/mainModule.js; - 读取
moduleB/index.js。
TypeScript的解析和上面基本一致,只是额外支持了.tsx和.d.ts的解析,此外读取package.json的属性为types。
/root/src/moduleB.ts/root/src/moduleB.tsx/root/src/moduleB.d.ts/root/src/moduleB/package.json("types")/root/src/moduleB/index.ts/root/src/moduleB/index.tsx/root/src/moduleB/index.d.ts
非相对路径引用
import { b } from "moduleB"
仍假定当前文件所处目录为/root/src/folder/A.ts,CommonJS的解析顺序如下:
/root/src/node_modules/moduleB.js/root/src/node_modules/moduleB/package.json("main")/root/src/node_modules/moduleB/index.js
本层找不到会跳到上级目录下的node_modules进行查找:
/root/node_modules/moduleB.js/root/node_modules/moduleB/package.json("main")/root/node_modules/moduleB/index.js
TypeScript和这上面基本类似,具体如下:
/root/src/moduleB.ts/root/src/moduleB.tsx/root/src/moduleB.d.ts/root/src/moduleB/package.json(if it specifies atypesproperty)/root/src/moduleB/index.ts/root/src/moduleB/index.tsx/root/src/moduleB/index.d.ts
也会在本层目录找不到时,去到上层的node_modules中按以上顺序查找,直至根目录。
BaseUrl & Paths
{
"compilerOptions": {
"baseUrl": ".", // 作为path映射的rootPath
"paths": {
"*": ["*", "generated/*"] // 相对于baseUrl的path
}
}
}
baseUrl和paths需要配合使用,类似于webpack中的resolve.alias用于设置别名路径。
以上*代表匹配任意路径名,<moduleName> => <baseUrl>/<moduleName>,匹配不上则继续匹配<moduleName> => <baseUrl>/generated/<moduleName>。
RootDirs
{
"compilerOptions": {
"rootDirs": ["src/views", "generated/templates/views"]
}
}
rootDirs用于运行时将数组内的目录合为同一个虚拟目录。
假设当前目录如下:
src
└── views
└── view1.ts (imports './template1')
└── view2.ts
generated
└── templates
└── views
└── template1.ts (imports './view2')
view1.ts内的引入会在查找srv/view目录下且未发现目标模块后,继续查找generated/templates/views以期望找到template1模块。