TypeScript 学习笔记 之 模块的解析

模板的解析就是编译器通过导入语句如 import { a } from "moduleA" 找到 "moduleA" 模块然后找到 a 的定义的过程。
moduleA 可能是在 .ts.tsx.d.ts 文件中。编译器首先要做的就是找到对应的模块文件。

  1. 首先编译器通过 ClassicNode 策略查找。
  2. 如果第一步查找不到,并且如果模块名并不是相对的,则根据 ambient module 来查找。
  3. 如果以上方式都找不到,则抛出 查找 不到的异常。

Relative vs. No-relative imports

/./../ 开头的称之为相对导入模块名。其他的则称为非相对导入。

相对导入是基于执行导入的当前文件的,而且不会以ambient module 的解析方式去解析。一般只用于内部模块。

而非相对导入,一是可以基于 baseUrl 来查找 。或者根据 path 映射来查找 ,也会通过 ambient module 的声明来查找 。可用于任何外部依赖。

模块解析策略

Classic 策略

假设 /root/src/folder/A.ts 文件中有如下相对导入声明 import { b } from "./moduleB"。 那么将查找以下两个路径:

  1. /root/src/folder/moduleB.ts
  2. /root/src/folder/moduleB.d.ts

假设使用的是非相对导入声明,即 import { b } from "moduleB"
那么将查找以下路径:

  1. /root/src/folder/moduleB.ts
  2. /root/src/folder/moduleB.d.ts
  3. /root/src/moduleB.ts
  4. /root/src/moduleB.d.ts
  5. /root/moduleB.ts
  6. /root/moduleB.d.ts
  7. /moduleB.ts
  8. /moduleB.d.ts

Node 策略

先来看一下 Node.js 中的导入逻辑,Node.js 的导入操作其实是由 require 函数完成
的。
假设 /root/src/moduleA.js 中有如下相对导入声明: var x = require("./moduleB"); 那么 Node.js 将按下面的顺序解析:

  1. /root/src/moduleB.js
  2. 是否有 /root/src/moduleB目录包含了一个 package.json 的文件声明了 main 模块,如果有如: {"main":"lib/mainModule.js"} 则解析 /root/src/moduleB/lib/mainModule.js
  3. 是否有 /root/src/moduleB目录包含了名为 index.js 的文件。

在 Node.js 中对于非相对导入的话,差别就大一些了。
还是按上面的假设。导入声明换成非相对导入,即:var x = require("moduleB")

  1. /root/src/node_modules/moduleB.js

  2. /root/src/node_modules/moduleB/package.json (如果有指定 main 属性)

  3. /root/src/node_modules/moduleB/index.js

  4. /root/node_modules/moduleB.js

  5. /root/node_modules/moduleB/package.json (如果有指定 main 属性)

  6. /root/node_modules/moduleB/index.js

  7. /node_modules/moduleB.js

  8. /node_modules/moduleB/package.json (如果有指定 main 属性)

  9. /node_modules/moduleB/index.js

TS 的模块解析策略

TS 的相对导入

假设 /root/src/moduleA.ts 文件中有如下相对导入声明 import { b } from "./moduleB"。 那么将查找以下路径:

  1. /root/src/moduleB.ts
  2. /root/src/moduleB.tsx
  3. /root/src/moduleB.d.ts
  4. /root/src/moduleB/package.json (如果有指定 types 属性)
  5. /root/src/moduleB/index.ts
  6. /root/src/moduleB/index.tsx
  7. /root/src/moduleB/index.d.ts

TS 的非相对导入

假设 /root/src/moduleA.ts 文件中有如下相对导入声明 import { b } from "moduleB"。 那么将查找以下路径:

  1. /root/src/node_modules/moduleB.ts

  2. /root/src/node_modules/moduleB.tsx

  3. /root/src/node_modules/moduleB.d.ts

  4. /root/src/node_modules/moduleB/package.json (if it specifies a "types" property)

  5. /root/src/node_modules/moduleB/index.ts

  6. /root/src/node_modules/moduleB/index.tsx

  7. /root/src/node_modules/moduleB/index.d.ts

  8. /root/node_modules/moduleB.ts

  9. /root/node_modules/moduleB.tsx

  10. /root/node_modules/moduleB.d.ts

  11. /root/node_modules/moduleB/package.json (if it specifies a "types" property)

  12. /root/node_modules/moduleB/index.ts

  13. /root/node_modules/moduleB/index.tsx

  14. /root/node_modules/moduleB/index.d.ts

  15. /node_modules/moduleB.ts

  16. /node_modules/moduleB.tsx

  17. /node_modules/moduleB.d.ts

  18. /node_modules/moduleB/package.json (if it specifies a "types" property)

  19. /node_modules/moduleB/index.ts

  20. /node_modules/moduleB/index.tsx

  21. /node_modules/moduleB/index.d.ts

TS 的模块解析选项

Base URL

baseUrl 将告诉编译器查找非相对导入起始路径。

  1. 命令行参数指定, 如果是相当路径则表示相对于当前路径。
  2. 如果是通过 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

你可能感兴趣的:(TypeScript 学习笔记 之 模块的解析)