使用Node.js為require設定別名(alias)
前言
由於本包包是個很懶惰的人,然後我們有些個專案設計的不是很好,所以導致寫程式碼的時候有很多這樣的程式碼:
require(`../../../../../../foo.js`);
寫的時候數那個小點點感覺人都要死了?
這種時候如果寫node能像用了webpack
(and so on)那樣能夠require
別名就好了。
比如這樣:
require(`modules/foo.js`);
於是我搜尋了幾種方法。
來自branneman總結的方法
以下內容來自於github上一名叫做branneman的同志的總結,我為他的內容進行了隨性的翻譯
原文可檢視這裡
1. Symlink
“偷”自focusaurus / express_code_structure # the-app-symlink-trick
- 在應用的
node_modules
資料夾下面建立一個symlink
- Linux:
ln -nsf node_modules app
- Windows:
mklink /D app node_modules
(叉燒包註釋:如果你在應用的目錄下,應該使用,以bash為例cd node_modules && ln -nsf [模組路徑]
,耍的時候請把app換成你要複製的模組的路徑)
然後你就可以
var Article = require(`app/article`);
小貼士:由於git不能處理跨平臺的symlinks,所以你不能再git repo裡面用這樣的檔案。不過如果你是在克隆後、git-hook或者是由開發人員手動建立一個symlink,那就沒啥問題
另外,你可以在npm裡面裡面增加一條postinstall鉤子,這個方法由scharf提出。可以把命令加進package.json
裡面
"scripts": {
"postinstall" : "node -e "var s=`../src`,d=`node_modules/src`,fs=require(`fs`);fs.exists(d,function(e){e||fs.symlinkSync(s,d,`dir`)});""
}
(叉燒包註釋:postinstall
會在npm run install
前先自動執行)
2. 全域性變數
在你的app裡面增加
global.__base = __dirname + `/`;
這樣你就可以這樣用了
var Article = require(__base + `app/models/article`);
3. 使用別人開發的庫
這裡下面再做推薦
4. 環境變數
設定環境變數NODE_PATH
成一個指向你app想用的模組的路徑(作者的情況下是.)。
(叉燒包註釋:最好是使用絕對路徑,這樣比較穩妥)
然後就可以
var Article = require(`app/models/article`);
4.1 提前設定
在啟動app前線確保已經設定好了環境變數
- Linux:
export NODE_PATH=.
- Windows:
set NODE_PATH=.
使用export
和set
是僅對當前shell有效的,如果你需要讓他全域性、永久的改變,需要修改你的配置檔案
4.2 只在執行node時設定
這個方法不會影響你的環境,除非node執行。他需要你改變應用啟用命令。
像這樣啟動你的app
- Linux:
NODE_PATH=. node app.js
- Windows:
cmd.exe /C "set NODE_PATH=.&& node app.js"
(在win下面如果你在path和&&之間加空格的話就啟動不了)
(叉燒包註釋:這裡推薦一下cross-env外掛,可以跨平臺使用命令,這樣的話就可以用這樣使用命令啦~ cross-env NODE_PATH=. node app.js
)
5. 啟用指令碼
其實和4.2差不多
其實就是寫成一個指令碼來執行,不過這樣比較方便加各種引數
例:
- Linux:
./app
(Windows PowerShell可) - Windows:
app
5.1 Node.js
看這裡
程式碼具體是這樣
#!/usr/bin/env node
`use strict`;
var spawn = require(`child_process`).spawn;
var args = [
`--harmony`,
`app/bootstrap.js`
];
var opt = {
cwd: __dirname,
env: (function() {
process.env.NODE_PATH = `.`; // Enables require() calls relative to the cwd :)
//叉燒包註釋: 如果需要多個路徑可以這樣(需要額外 require path 模組)
//process.env.NODE_PATH = [`.`, `./lib`].join(path. delimiter)
return process.env;
}()),
stdio: [process.stdin, process.stdout, process.stderr]
};
var app = spawn(process.execPath, args, opt);
5.2 作業系統特定的啟動指令碼
- Linux
可以建立一個app.sh
#!/bin/sh
NODE_PATH=. node app.js
- Windows
可以建立一個app.bat
@echo off
cmd.exe /C "set NODE_PATH=.&& node app.js"
6. Hack
謝謝@joelabair和4.2差不多,但不需要在app之外指定NODE_PATH。但是,由於這依賴於一個專用的Node.js核心方法。
你需要在require
之前執行這個方法。
process.env.NODE_PATH = __dirname;
require(`module`).Module._initPaths();
7. 包裹
感謝@a-ignatov-parc
簡單來說你可以在你的app最開始執行這樣的程式碼。
global.rootRequire = function(name) {
return require(__dirname + `/` + name);
}
然後就可以這樣
var Article = rootRequire(`app/models/article`);
叉燒包總結
基於我的原則一向來就是越快越好,打字越少越好,所以個人認為
- symlink的方式由於各種限制而且你增加一點你的包就得新生產一個,感覺比較的不爽 => pass
- 增加全域性變數,但是還需要自己拼接一下,難受 => pass
- 環境變數,我比較能接受寫一份指令碼的方法 0-0
- Hack方法,這個我比較的喜歡, 使用時也和原生一樣
- 包裹方法在require時比較難受,我喜歡能直接
require
…so => pass
包子的方法
1. 修改啟用命令
這個上面也提到過4和5中也提到過。
在啟用時這樣操作NODE_PATH=. node app.js
。
不過得考慮到不同作業系統下面path分割符的問題,所以個人推薦是採用5.1中的方法,寫一份node指令碼
2. HACK
我hack了_findPath()
方法,這個就是想設成啥別名就啥別名w,只不過只能相容到node6
已經封裝成外掛node-require-alias
,在這裡自薦一下。
使用方法:
const path = require("path")
require(`node-require-alias`).setAlias({
"@": path.join(__dirname, "this/is/a/path")
})
// or require(`node-require-alias`).setAlias("@", path.join(__dirname, "this/is/a/path"))
require模組時候↓
require(`@/abc.js`)
歡迎來PR(づ ̄3 ̄)づ╭❤~
其他人的方法
- hack了
require
方法,這個和我想的hack差不多,但是這樣相容性比較好。code看這裡。這個作者也封裝成了一個外掛,大家可以去支援一下sexy-require。這邊的別名是配置在package.json
下面的 - 還有hack了
export
方法的,通過Object.defineProperty
,在get方法時給模組的新增必要的屬性 - babel-plugin-resolver。這個本包倒是沒有細去了解,所以使用的小夥伴可以自己看一下
外掛推薦
各位有用過別的歡迎在評論裡面告訴我喲~(@^_^@)~
使用起來和原生沒有差別的
- 先羞羞的安利一下自己的外掛
node-require-alias
, node6.0環境以上的考慮一下 - 還有是通過讀
package.json
配置的sexy-require -
module-alias這個讀
package.json
和通過方法都可以設定別名
使用起來和原生有差別的
因為我個人比較嫌棄這種寫法,這裡就不做介紹了,只做推薦
最後的總結
我個人比較的作,喜歡自己寫還是比較喜歡HACK!不過我覺得加環境變數也很快,也不用管相容b( ̄▽ ̄)d。
另外對於HACK方法我還做了十分隨性的原理解析,大家想看的可以戳這裡