typescript路径映射踩坑

问题由来

我们通常引用一个npm模块,直接引用模块的名称就可以了,如 import module from 'module' 。
但是如果引用自己开发的模块,往往要使用相对路径的方式找到目标模块,如 import myComponent from '../../../components/myComponent' 。
这种方式可以正常开发,可以完成业务需求,但是维护起来就很难弄了,因为通过这种相对路径的方式你很难一下定位这个组件在哪里,在项目复杂的时候,可能会产生预期外的结果。

别名设置

其实这个问题的解决方案已经很成熟了,从各种构建工具及命令中都有相应的设置。
我这里只针对 typescript 做说明,因为他提供的工具集有点坑。

假如我想实现 import myComponent from '@components/myComponent' 。
而我的目录结构为

./
└── src
    ├── components
    └── views
          └── app.ts

tsconfig.json

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@components/*": ["src/components/*"]
    }
  }
}

这里的关键配置是 baseUrl 和 paths 
具体说明可以参见文档
https://www.tslang.cn/docs/handbook/module-resolution.html#virtual-directories-with-rootdirs

webpack

假设有一个 webpack.config.js 文件在 ./ 下面

resolve: {
  alias: {
      '@components': path.resolve(__dirname, './src/components'),
  }
}

这个比较基础,直接查看webpack文档就可以了
https://www.webpackjs.com/configuration/resolve/#resolve-alias

通过tsc编译会产生的问题

该文章并不是要教你怎么使用别名,而是 typescript 的开发中有个坑。

用tsc编译的后,映射的路径不会处理,将导致编译后的代码找不到模块

比如上面的 import myComponent from '@components/myComponent' ,如果你使用 commonjs 模式编译后应该是 const myComponent require('@components/myComponent') ,结果就是找不到这个模块。

解决方案一:使用webpack等构建工具进行编译

可以通过 ts-loader 等组件进行编译,来规避掉这个问题

解决方案二:使用module-alias

我现在的场景是,就想使用 tsc -w 来进行开发,那么经过一番寻找,比较优秀的方案就是 module-alias 了。
https://www.npmjs.com/package/module-alias
最简单的用法就是将 const moduleAlias = require('module-alias') 放到你的项目入口处。
然后设置你的 package.json ,以前面的结构为例。

"_moduleAliases": {
  "@components" : "./src/components"
}

这样就可以达到 tsc 编译后,仍然可以找到设置别名的路径了。
至于 module-alias 的原理是什么可以看一下他的npm模块的描述,我就不擅自翻译,免得误人子弟。