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

痛点

如果我们有这个目录:

├── 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";

posted @ 2017-11-01 14:33  linyongkangm  阅读(605)  评论(0)    收藏  举报