我正在开发的 cli 工具 wcli 是用
node
+
typescript
编写的,在编写的过程中不免需要引用到大量的模块。
大量的
import utils from '../../../../../utils'
太麻烦也太恶心了,于是开始了 ts 的路径别名踩坑之旅。
ts 的路径别名设置
ts 的路径别名设置在社区中已经十分成熟了,官网中也有相应的文档描述。接下来的内容将直接引用官网的描述以及设置。
ts 官网的路径映射配置
有时模块不是直接放在
baseUrl
下面。 比如,充分
"jquery"
模块地导入,在运行时可能被解释为
node_modules/jquery/dist/jquery.slim.min.js
。 加载器使用映射配置来将模块名映射到运行时的文件,查看
RequireJs documentation和SystemJS documentation
。
TypeScript
编译器通过使用 tsconfig.json 文件里的"paths"来支持这样的声明映射。 下面是一个如何指定
jquery
的
paths
的例子。
"compilerOptions"
: {
"baseUrl"
:
"."
,
"paths"
: {
"jquery"
: [
"node_modules/jquery/dist/jquery"
]
请注意
paths
是相对于
"baseUrl"
进行解析。 如果
baseUrl
被设置成了除"."外的其它值,比如 tsconfig.json 所在的目录,那么映射必须要做相应的改变。 如果你在上例中设置了
baseUrl: ./src
,那么 jquery 应该映射到
../node_modules/jquery/dist/jquery
。
课代表总结
baseUrl: 用来设置下面 path 路径的根路径
。
path: 用来设置相对应的路径映射,数组中的路径相对应 baseUrl 的路径
。
"baseUrl": ".",
"paths": {
"@srcTypes/*": ["src/types/*"],
"@constants/*": ["src/constants/*"],
"@commands/*": ["src/commands/*"],
"@utils/*": ["src/utils/*"]
配置完即可在项目中使用。
import XXX from "@utils/getPluginFile";
import { xx } from "@utils/checktype";
import { xx } from "@utils/createContext";
tsc 的坑
路径映射是做好了,但是在执行 tsc 打包完之后的代码发现报错了:用 tsc 编译的后,映射的路径不会处理,将导致编译后的代码找不到模块。
比如上面的 import XXX from '@utils/getPluginFile'
,如果你使用 commonjs 模式编译后应该是 const XXX = require('@utils/getPluginFile')
,结果就是找不到这个模块。
根据是否使用 webpack 打包,请自行选择
如果项目是通过 webpack 进行打包的,那么可以把路径的替换交给 webpack 的 alias 处理即可。
module.exports = {
resolve: {
alias: {
@utils: path.resolve(__dirname, 'src/utils/')
问题是我的 wcli 不是用 webpack 打包的,纯粹就是使用 tsc 编译成 js 在 node 上执行的那怎么办呢?后面发现社区上提供了一个库-module-alias
。在配置完 tsconfig 的基础上只需要通过简单的两步即可实现。
在package.json
配置跟 webpack alias 的路径指向然后在入口文件调用引用方法即可。
"_moduleAliases": {
"@root" : ".",
"@deep" : "src/some/very/deep/directory/or/file",
"@my_module" : "lib/some-file.js",
"something" : "src/foo",
require('module-alias/register')
一些另外的用法可以去官网查看即可,这里是跳转连接。
eslint 的坑
根据上面的内容,tsc 是好使了打包出来的代码也能正常运行。不过有一个新的坑出来了:eslint 并不能识别路径别名,虽然能够正确跳转以及引用。难受啊!马飞!。
最简单最暴力的方式自然是直接去掉这个插件,或者关闭相关 ESLint rules
,但 eslint-plugin-import
30+ rules 集合 JS 社区 ES6 多年最佳实践,关闭这个规则实乃下下策。最终在一位大佬的博客下找到了一个完美的 eslint 插件解决这个问题-eslint-import-resolver-typescript
。
eslint-import-resolver-typescript
eslint-import-resolver-typescript光从名字就可以看出和这个问题极为相关。从项目 README 可以发现,这个 lib 可以在 TypeScript 项目使 eslint-plugin-import 找到正确的 .ts 和 .tsx 文件,也能识别 tsconfig.json 的 path 配置(路径别名 2),甚至 monorepo 这类一个 git 仓库多个项目的工程也支持。
用法也很简单在 eslint 的"import/resolver":
指向当前配置了 path 的 tsconfig 的路径即可,eslint 就会自动识别就不会报错了。
"plugins": ["import"],
"rules": {
"import/no-unresolved": "error"
"settings": {
"import/parsers": {
"@typescript-eslint/parser": [".ts", ".tsx"]
"import/resolver": {
"typescript": {
"alwaysTryTypes": true,
"typescript": {
"directory": "./path/to/folder"
"typescript": {
"directory": "./packages/*/tsconfig.json"
"typescript": {
"directory": [
"./packages/module-a/tsconfig.json",
"./packages/module-b/tsconfig.json"
"typescript": {
"directory": [
"./packages/*/tsconfig.json",
"./other-packages/*/tsconfig.json"
贴一下我的 eslintrc 配置,可以作为参考:
module.exports = {
'parser': '@typescript-eslint/parser',
'extends': ['airbnb-base', 'plugin:@typescript-eslint/recommended'],
'plugins': ['@typescript-eslint'],
'env': {
'browser': false,
'node': true
'settings': {
'import/resolver': {
'node': {
'extensions': ['.js', '.jsx', '.ts', '.tsx']
'typescript': {
'alwaysTryTypes': true
ESLint 检查 TypeScript 时报 “Unable to resolve path to module ‘xxx’” 错误