../../../../.. 太low了

时间:2023-12-22 20:24:32

痛点

如果我们有这个目录:

├── webpack.config.js
├── src
│ ├── view
│ │ ├── index.js
│ │── router
│ │ ├── index.js

不使用任何方式的路径别名的话,在/view/index.js内要引入/router/index.js的话,就要使用../router。当目录结构变深的时候就会出现../../../../../,这是一个噩梦。

所以我们的目标是用@view指代/src/view目录,@router指代/src/router目录,

@src指代/src目录。@alias只是形式上表示这是一个别名,@并不是必需的,可以用$,%,^,甚至不使用,直接src指代/src

在JavaScript中的解决方案

构建工具的alias

在构建工具Webpack中可以使用 resolve.alias 属性定义。

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

这时在/view/index.js中就可以使用@router[/index.js]来引入/router/index.js了。

使用Webpack的alias属性推荐(必需)使用绝对路径,因为Webpack采用的使用时匹配替换形式的。就是说如果alias.@router 设为 ../router 的话,在使用2router引入的时候会被替换成../router,虽然在/view/index.js中能正常工作,但是在/view/user/index.js中就找不到文件了。所以坚决建议使用绝对路径。

重写require

重写require方法,如:sexy-require,在require的时候用自定义的路径替换,这个一般会在Node.js中使用。下面是一个简单实现:

const alias = {
'@view' : path.resolve(__dirname, 'src/view'),
'@router': path.resolve(__dirname, 'src/router')
}
const _require = Module.prototype.require;
Module.prototype.require = function(path) {
for (let ali in alias) {
path = path.replace(ali, alias[ali]);
}
return _require.call(this, path)
}

当然这种方法只能用在require方式引入文件,ES Module是用不了的。

在TypeScript中的解决方案

在TypeScript中需要在编译前配置路径映射的baseUrl和paths,用于告诉编译器到哪里去查找模块。但是编译过程中并不会将路径替换成目标路径,就是.ts文件中的@router在生成的.js文件中仍然是@router。这就要我们编译后的文件再设置一次路径别名了。如果用Webpack打包的当然可以使用构建工具的alias完成别名。如果没有用Webpack的也可以重写require方法,这里记得要将tsconfig.json里面"module"设为"commonjs",因为我们只能重写require方法。

注意:如果.ts文件存放在src目录,编译后.js文件存放在dist目录,记得.ts文件中的路径映射是要用以src目录为基础的,而对.js文件得路径别名要以dist目录为基础

// tsconfig.json
// baseUrl 是源代码目录
{
"compilerOptions": {
"target": "ES2017",
"module": "commonjs",
"outDir": "dist",
"baseUrl": "src",
"paths": {
"$*": ["*"]
}
},
"include": ["src/**/*"],
"exclude": ["dist"]
}
// package.json
// path.$* 的路径都是以tsconfig.json 中 outDir 为基础的
{
"name": "alias",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node ./dist/router"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@types/node": "^8.0.47",
"sexy-require": "^0.1.0"
},
"path": {
"$router": "/dist/router",
"$view": "/dist/view"
}
}
// src/router/index.ts
require("sexy-require"); const view = require("$view"); console.log(view); export = "router/index";
// src/view/index.ts
export = "view/index";