在 TypeScript 项目中,baseUrl
主要用于模块路径解析。它为编译器提供了一个基础路径,当导入模块时,编译器会以这个baseUrl
为起点来查找模块文件。
例如,假设你的项目结构中有一个 src
目录,里面包含了各种模块文件。如果设置 baseUrl
为 src
,那么在导入模块时,编译器就会从src
目录开始寻找对应的模块,而不是从当前文件所在的目录开始。
假设,有如下项目目录结构:
project
├── module
│ └── calc.ts
├── src
│ └── module
│ └── calc.ts
│── index.ts
└── tsconfig.json
calc.ts
的代码如下,导出 add 函数:
function add(a: number, b: number) {
return a + b
}
export {
add
}
index.ts
的代码如下:
import { add } from 'module/calc'
add(2, 3)
如果 baseUrl
的配置为:
{
"compilerOptions": {
"baseUrl": "./"
}
}
则 index.ts
引入的 calc
模块为 src
文件夹外面定义的。
如果 baseUrl
的配置为:
{
"compilerOptions": {
"baseUrl": "./src",
}
}
则 index.ts
引入的 calc
模块为 src
文件夹里面定义的。
还有,当 TypeScript 编译器在解析模块路径时,通过 baseUrl
配置进行的路径解析具有比从 node_modules
查找更高的优先级。
通常情况下,在模块解析过程中,当尝试导入一个模块时,编译器会查看 node_modules
目录来寻找匹配的模块。例如,当使用 import React from 'react';
时,编译器会首先在 node_modules
目录中查找 react
模块。
如果配置了 baseUrl
,编译器会先按照 baseUrl
指定的方式来解析模块路径。例如,假设 baseUrl
被设置为 src
,并且在 TypeScript 代码中有这样的导入语句 import { myModule } from 'my-module';
,编译器会优先尝试从 src
目录下查找 my-module
相关的文件,而不是直接去 node_modules
查找。
只有在按照 baseUrl
的配置无法找到合适的模块时,编译器才会考虑从 node_modules
进行查找。
使用 baseUrl
配置,可以简化模块导入的相对路径写法。
例如,从 src/utils/file1.ts
文件导入 src/services/file2.ts
中的模块,可能需要写成 import { someFunction } from '../services/file2';
这种相对路径形式。
当设置了 baseUrl
(如设为 src
)后,导入路径可以简化为 import { someFunction } from 'services/file2';
。这样的路径更简洁直观,尤其在项目结构复杂、模块层次较多的情况下,能够减少因相对路径过长或嵌套过深而导致的错误。
baseUrl
也可以和 paths
配合使用,配置路径别名。路径别名允许为特定的模块路径设置更简洁的名称。使用路径别名也是方便模块导入的一个手段,不用写那么长的模块路径,例如,将 src/components
路径设置为 @components
别名。如下面的配置:
将 src/components
路径设置为 @components
别名。
不过要注意的是,js 本身是不认识别名的,比如 @components
。直接运行下面的代码,是会报错的:
import { add } from '@components/calc';
const total = add(2, 3);
console.log('total ', total);
因此,在 TypeScript 中配置了路径别名后,通常都需要借助构建工具,比如 Webpack 、Rollup 等把路径别名替换为真实的路径,比如下面的 Webpack 配置:
从 TypeScript 4.1 开始,也可独自使用 paths
配置路径别名,只是不能使用非相对路径,如下面的配置:
js 不仅不认识别名,baseUrl
配置也是不认识的,也需要使用 Webpack 等构建工具,将 baseUrl
替换为真实路径。如下面的配置,配置了 baseUrl
为 src 目录(受 include
影响):
{
"compilerOptions": {
"baseUrl": ".",
"outDir": "dist",
"target": "es6",
"module": "es6",
"esModuleInterop": true
},
"include": ["src"]
}
整个的项目结构如下:
由于配置了 baseUrl
,在 index.ts
文件中可直接通过 my-util
引入 isArr
函数:
import { isArr } from 'my-util'
console.log('isArr ', isArr([1, 2, 3]))
但是使用 tsc
编译出来的源码是无法执行的,会报 ERR_MODULE_NOT_FOUND
的错误:
因为 baseUrl
是 TypeScript 的东西,JavaScript 是不认识他的,如果要生成能够执行的代码,需要使用 Webpack 将 baseUrl
替换为真实路径:
$
表示精确匹配,具体可见 resolve.alias
与 include 的关联
include
配置项用于指定哪些文件或文件夹应该被 TypeScript 编译器包含进来编译。
include
配置会影响到 baseUrl
,baseUrl
会以 include
中的路径为基准。
如下面的配置,设置 include
为 src
,baseUrl
为 .
,则实际上 baseUrl
不是项目的根目录,而是 src
。
整体的项目目录结构如下:
可以发现根目录下的 index.ts 是无法引入 my-util
的:
如果将 include
配置去掉,则 TypeScript 编译器会将整个项目根目录都包进来处理,baseUrl
也是指项目根目录,受 baseUrl
影响,在 src
文件夹下的 index.ts 引入的也是根目录下的 my-util
模块:
总结
baseUrl
用于配置 TypeScript 编译器查找模块的起点。
baseUrl
可用于简化模块导入的路径,也可与 paths
配合使用,配置路径别名。
要注意的是,js 是不认识 baseUrl
和路径别名的,因此为了生成可以运行的代码,需要借助 Webpack 、Rollup 等构建工具将 baseUrl
、路径别名替换为真实的路径。
include
配置会影响到 baseUrl
,baseUrl
会以 include
中的路径为基准。