模板的解析就是编译器通过导入语句如 import { a } from "moduleA" 找到 "moduleA" 模块然后找到 a 的定义的过程。
moduleA 可能是在 .ts 或 .tsx 或 .d.ts 文件中。编译器首先要做的就是找到对应的模块文件。
- 首先编译器通过
Classic或Node策略查找。 - 如果第一步查找不到,并且如果模块名并不是相对的,则根据
ambient module来查找。 - 如果以上方式都找不到,则抛出 查找 不到的异常。
Relative vs. No-relative imports
以 / 或 ./ 或 ../ 开头的称之为相对导入模块名。其他的则称为非相对导入。
相对导入是基于执行导入的当前文件的,而且不会以ambient module 的解析方式去解析。一般只用于内部模块。
而非相对导入,一是可以基于 baseUrl 来查找 。或者根据 path 映射来查找 ,也会通过 ambient module 的声明来查找 。可用于任何外部依赖。
模块解析策略
Classic 策略
假设 /root/src/folder/A.ts 文件中有如下相对导入声明 import { b } from "./moduleB"。 那么将查找以下两个路径:
/root/src/folder/moduleB.ts/root/src/folder/moduleB.d.ts
假设使用的是非相对导入声明,即 import { b } from "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.js 中的导入逻辑,Node.js 的导入操作其实是由 require 函数完成
的。
假设 /root/src/moduleA.js 中有如下相对导入声明: var x = require("./moduleB"); 那么 Node.js 将按下面的顺序解析:
/root/src/moduleB.js- 是否有
/root/src/moduleB目录包含了一个package.json的文件声明了main模块,如果有如:{"main":"lib/mainModule.js"}则解析/root/src/moduleB/lib/mainModule.js - 是否有
/root/src/moduleB目录包含了名为index.js的文件。
在 Node.js 中对于非相对导入的话,差别就大一些了。
还是按上面的假设。导入声明换成非相对导入,即:var x = require("moduleB")
-
/root/src/node_modules/moduleB.js -
/root/src/node_modules/moduleB/package.json(如果有指定main属性) -
/root/src/node_modules/moduleB/index.js -
/root/node_modules/moduleB.js -
/root/node_modules/moduleB/package.json(如果有指定main属性) -
/root/node_modules/moduleB/index.js -
/node_modules/moduleB.js -
/node_modules/moduleB/package.json(如果有指定main属性) -
/node_modules/moduleB/index.js
TS 的模块解析策略
TS 的相对导入
假设 /root/src/moduleA.ts 文件中有如下相对导入声明 import { b } from "./moduleB"。 那么将查找以下路径:
/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
TS 的非相对导入
假设 /root/src/moduleA.ts 文件中有如下相对导入声明 import { b } from "moduleB"。 那么将查找以下路径:
-
/root/src/node_modules/moduleB.ts -
/root/src/node_modules/moduleB.tsx -
/root/src/node_modules/moduleB.d.ts -
/root/src/node_modules/moduleB/package.json(if it specifies a "types" property) -
/root/src/node_modules/moduleB/index.ts -
/root/src/node_modules/moduleB/index.tsx -
/root/src/node_modules/moduleB/index.d.ts -
/root/node_modules/moduleB.ts -
/root/node_modules/moduleB.tsx -
/root/node_modules/moduleB.d.ts -
/root/node_modules/moduleB/package.json(if it specifies a "types" property) -
/root/node_modules/moduleB/index.ts -
/root/node_modules/moduleB/index.tsx -
/root/node_modules/moduleB/index.d.ts -
/node_modules/moduleB.ts -
/node_modules/moduleB.tsx -
/node_modules/moduleB.d.ts -
/node_modules/moduleB/package.json(if it specifies a "types" property) -
/node_modules/moduleB/index.ts -
/node_modules/moduleB/index.tsx -
/node_modules/moduleB/index.d.ts
TS 的模块解析选项
Base URL
baseUrl 将告诉编译器查找非相对导入起始路径。
- 命令行参数指定, 如果是相当路径则表示相对于当前路径。
- 如果是通过
tsconfig.json指定。则表示相对tsconfig.json文件所在的路径。
Path mapping
如果一些库的路径无法通过上面的标准解析路径解析。那么可以通过在 tsconfig.json 中配置 paths 属性。
如 jquery 库的路径是 node_modules/jquery/dist/jquery.slim.min.js,不是一个标记的 node_modules 路径。则可使用如下配置:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"jquery": ["node_modules/jquery/dist/jquery"]
}
}
}
值得注意的是 paths 是相对 baseUrl 的。
Virtual Directories with rootDirs
当项目源文件的结构是有多路径,但是编译结果会在一个目录中。此时可以通过 rootDirs 来 指定编译期其他的相对路径查找列表。如下两个 views 目录下的文件就可以通过 ./template1.ts 来方式来引用另一目录的模块。
{
"compilerOptions": {
"rootDirs": [
"src/views",
"generated/templates/views"
]
}
}
Tracing module resolution
可以通过 tsc --traceResolution 来输出模块的解析日志。
参考 : Module Resolution








网友评论