使用Node.js為require設定別名(alias)

魔力叉燒包發表於2019-02-16

使用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

  1. 在應用的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=.

使用exportset是僅對當前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方法我還做了十分隨性的原理解析,大家想看的可以戳這裡

相關文章