模块解析是指编译器在查找导入模块内容时所遵循的流程。
编译器一般遵循两种解析策略:
-
Classic 解析策略
-
Node 解析策略
模块引用分相对引用和非相对引用:
-
相对引用:相对引用是以 /,./ 或 ../ 开头
-
非相对引用:所有其它的引用当作非相对引用
解析策略设置:使用 --moduleResolution标记来指定使用哪种模块解析策略。若未指定,那么在使用了 --module AMD | System | ES2015时的默认值为Classic,其它情况时则为Node。
classic 策略:这种策略在以前是TypeScript默认的解析策略。 现在,它存在的理由主要是为了向后兼容。
相对导入的模块是相对于导入它的文件进行解析的。 因此 /root/src/folder/A.ts文件里的import { b } from "./moduleB"会使用下面的查找流程:
-
/root/src/folder/moduleB.ts
-
/root/src/folder/moduleB.d.ts
对于非相对模块的导入,编译器则会从包含导入文件的目录开始依次向上级目录遍历,尝试定位匹配的声明文件。
比如:
有一个对moduleB的非相对导入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.js里导入是通过require函数调用进行的。 Node.js会根据 require的是相对路径还是非相对路径做出不同的行为。相对路径很简单。 例如,假设有一个文件路径为 /root/src/moduleA.js,包含了一个导入var x = require("./moduleB"); Node.js以下面的顺序解析这个导入:
-
检查/root/src/moduleB.js文件是否存在。
-
检查/root/src/moduleB目录是否包含一个package.json文件,且package.json文件指定了一个"main"模块。 在我们的例子里,如果Node.js发现文件 /root/src/moduleB/package.json包含了{ "main": "lib/mainModule.js" },那么Node.js会引用/root/src/moduleB/lib/mainModule.js。
-
检查/root/src/moduleB目录是否包含一个index.js文件。 这个文件会被隐式地当作那个文件夹下的"main"模块。
非相对模块名的解析是个完全不同的过程。 Node会在一个特殊的文件夹 node_modules里查找你的模块。node_modules可能与当前文件在同一级目录下,或者在上层目录里。 Node会向上级目录遍历,查找每个node_modules直到它找到要加载的模块。
还是用上面例子,但假设/root/src/moduleA.js里使用的是非相对路径导入var x = require("moduleB");。 Node则会以下面的顺序去解析 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
node 允许的文件扩展名包含:.js、.json、.node,当引人文件不包含扩展名,node会依次补足扩展名,依次尝试。
TypeScript如何解析模块:
TypeScript在Node解析逻辑基础上增加了TypeScript源文件的扩展名( .ts,.tsx和.d.ts)
TypeScript在 package.json里使用字段"types"来表示类似"main"的意义
有一个导入语句import { b } from "./moduleB"在/root/src/moduleA.ts里,会以下面的流程来定位"./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
网友评论