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

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • relative 和 non-relative import Relative Import以/, ./或../為...
    柳正來閱讀 10,469評論 0 2
  • 布爾值 let isBoolean: boolean = true; 數字 let num: number = 1...
    田小寶_640c閱讀 776評論 0 2
  • nodejs通過require加載模塊,require里面分為相對路徑和非相對路徑,不同的表示方法,node的尋找...
    前端大魔王閱讀 896評論 1 2
  • 決不能餓著肚子去超市,因為那會徹底顛覆你的購物清單。但如果是剛吃過飯去呢,呵呵,居然不知買點兒什么好。有的超...
    西樓風雨閱讀 208評論 0 0
  • 今天是2月的最后一天,過了今天,18年就過去六分之一了。 1月的一次旅行,讓我發現身邊比你牛很多的人還比你認真學習...
    燈燈a燈燈閱讀 143評論 0 0