关于 TypeScript 模块加载机制

33 篇文章 0 订阅
9 篇文章 0 订阅

一、TS 文件的加载策略

TS 中的加载策略分为两种方式,分别为相对路径绝对路径两种方式。

1、相对路径

TypeScript 将 TypeScript 源文件扩展名(.ts.tsx.d.ts)覆盖在 Node 的解析逻辑上。同时TypeScript 还将使用 package.json named 中的一个字段 types 来镜像目的"main",编译器将使用它来查找“主”定义文件以进行查阅。

// 假设当前执行路径为 /root/src/modulea

import { b } from './moduleb'

此时,TS 对于 ./moduleb 的加载方式其实是和 node 的模块加载机制比较类似:

  • 首先寻找 /root/src/moduleb.ts 是否存在,如果存在使用该文件。
  • 其次寻找 /root/src/moduleb.tsx 是否存在,如果存在使用该文件。
  • 其次寻找 /root/src/moduleb.d.ts 是否存在,如果存在使用该文件。
  • 其次寻找 /root/src/moduleB/package.json,如果 package.json 中指定了一个types属性的话那么会返回该文件。
  • 如果上述仍然没有找到,之后会查找 /root/src/moduleB/index.ts
  • 如果上述仍然没有找到,之后会查找 /root/src/moduleB/index.tsx
  • 如果上述仍然没有找到,之后会查找 /root/src/moduleB/index.d.ts

可以看到 TS 中针对于相对路径查找的规范是和 nodejs 比较相似的。

Ts 在寻找文件路径时,在某些条件下是会按照目录去查找 .d.ts 的。

2、绝对路径

// 假设当前文件所在路径为 /root/src/modulea

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(如果它指定了一个types属性)
  • /root/src/node_modules/@types/moduleB.d.ts
  • /root/src/node_modules/moduleB/index.ts
  • /root/src/node_modules/moduleB/index.tsx
  • /root/src/node_modules/moduleB/index.d.ts

typescript 针对于非相对导入的 moduleb 会按照以上路径去当前路径的 node_modules 中去查找,如果上述仍然未找到。

此时,TS 仍然会按照 node 的模块解析规则,继续向上进行目录查找,比如又会进入上层目录 /root/node_modules/moduleb.ts ...进行查找,直到查找到顶层 node_modules 也就是最后一个查找的路径为 /node_modules/moduleB/index.d.ts 如果未找到则会抛出异常 can't find module 'moduleb'

上述查找规则是基于 tsconfig.json 中指定的  moduleResolution:node,当然还有  classic 不过  classic 规则是 TS 为了兼容老旧版本,现代代码中基本可以忽略这个模块查找规则。

 

3、解析 *.d.ts 声明

日常开发中,有这样一种场景,在 TS 项目中我们需要引入一些后缀为 png 的图片资源,那么此时 TS 是无法识别此模块的。

解决方法也非常简单,通常我们会在项目的根目录中也就是和 tsconfig.json 平级的任意目录中添加对应的声明文件 image.d.ts

// image.d.ts

declare module '*.png' {
    const src: String;
    export default src;
}
import logo from './assets/logo.png'

可以看到,通过定义声明文件的方式解决了我们的问题。

3.1 typescript模块加载机制是怎么查找到定义在项目目录中的 image.d.ts 呢?

本质上我们引入任何模块时,加载机制无非就是我们上边提到的两种加载方式。

不过,这里有一个细小的点即是 ts 编译器会处理 tsconfig.json 的 file、include、exclude 对应目录下的所有 .d.ts 文件:

简单来说,ts 编译器首先会根据 tsconfig.json 中的上述三个字段来加载项目内的 d.ts 全局模块声明文件,自然由于 '.png' 文件会命中全局加载的 image.d.ts 中的 声明的 module 所以会找到对应的文件。

include 在未指定 file 配置下默认为  **,表示 tsc 解析的目录为当前 tsconfig.json 所在的项目文件夹。

关于 file、include、exclude 三者本质上都是针对于 TSC 编译器处理的范围。
// tsconfig.json

{
  "compilerOptions": {
    "outDir": "build/dist",
    "module": "esnext",
    "target": "esnext",
    "lib": ["esnext", "dom"],
    "sourceMap": true,
    "baseUrl": ".",
    "jsx": "react-jsx",
    "resolveJsonModule": true,
    "allowSyntheticDefaultImports": true,
    "moduleResolution": "node",
    "forceConsistentCasingInFileNames": true,
    "noImplicitReturns": true,
    "noImplicitAny": false,
    "suppressImplicitAnyIndexErrors": true,
    "noUnusedLocals": true,
    "allowJs": true,
    "skipLibCheck": true,
    "experimentalDecorators": true,
    "strict": true,
    "paths": {
      "@/*": ["./src/*"],
      "@@/*": ["./src/.umi/*"]
    }
  },
  "include": [
    "mock/**/*",
    "src/**/*",
    "playwright.config.ts",
    "tests/**/*",
    "test/**/*",
    "__test__/**/*",
    "typings/**/*",
    "config/**/*",
    ".eslintrc.js",
    ".stylelintrc.js",
    ".prettierrc.js",
    "jest.config.js",
    "mock/*"
  ],
  "exclude": ["node_modules", "build", "dist", "scripts", "src/.umi/*", "webpack", "jest"],
  "files": []
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值