這篇文章帶大家了解一下node.js中的module-alias,介紹一下module-alias原理、module-alias的一個常見問題(坑),希望對大家有幫助!
首先有必要介紹一下module-alias
是什麼,這裡有其官網連結(官網網址https://github.com/ilearnio/ module-alias)。
簡單點說,module-alias
提供了在node
環境下的路徑別名功能。一般前端開發可能會比較熟悉webpack
的alias
配置、typescript
的paths
配置等,這些都是提供了陸軍別名的功能。路徑別名在程式碼開發過程中是yyds,不然你看到這種../../../../xx
路徑時,是一定會抓狂的。
使用webpack
打包的項目webpack
本身會處理原始程式碼中路徑別名的配置到打包後程式碼的轉換過程,但如果單純使用typescript
進行編譯的項目,雖然typescript
在編譯過程中可以正常處理paths
中路徑別名的配置,但是並不會改變打包後的程式碼,造成在打包後的程式碼中仍然存在路徑別名配置,看一個經過typescript
編譯後的程式碼:
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); require("./module-alias-register"); var commands_1 = require("@/commands"); var package_json_1 = require("../package.json"); (0, commands_1.run)(package_json_1.version);
這裡是tsconfig.json
的設定內容
"paths": { "@/*": [ "src/*" ] }
可以看到在經過typescript
編譯後的程式碼中,仍然存在@符號,然而當程式碼運行的過程中,例如允許在node
中,require
並不能正常辨識路徑裡的這個符號,導致找不到對應模組而拋出例外。
這也是module-alias
這個庫存的目的。
從官網上看,這個函式庫使用方法只需要兩步,真的已經是極簡狀態了。
1、路徑別名配置:module-alias
支援兩種路徑別名配置方式
在package.json
中增加_moduleAliases
屬性進行配置
"_moduleAliases": { "@": "./src" }
#透過提供的API介面addAlias
、addAliases
、addPath
,增加配置
moduleAlias.addAliases({ '@' : __dirname + './src', });
2、在專案啟動時先導入該庫:require(module-alias/register)
即可,當然選擇使用API方式的需要導入對應的函數進行處理
一般我們都是使用package.json
中配置路徑別名項目入口處require(module-alias/register)
來使用這個函式庫。
module-alias
透過覆寫了全域物件Module
上的方法_resolveFilename
來實現路徑別名的轉換,簡單來說就是透過攔截原生的_resolveFilename
方法調用,進行路徑別名的轉換,當獲取到檔案的真實路徑後,再調用原聲的_resolveFilename
方法。
下面是其原始程式碼,基本上分為兩部分:路徑別名轉換原生_resolveFilename
呼叫
var oldResolveFilename = Module._resolveFilename Module._resolveFilename = function (request, parentModule, isMain, options) { for (var i = moduleAliasNames.length; i-- > 0;) { var alias = moduleAliasNames[i] if (isPathMatchesAlias(request, alias)) { var aliasTarget = moduleAliases[alias] // Custom function handler if (typeof moduleAliases[alias] === 'function') { var fromPath = parentModule.filename aliasTarget = moduleAliases[alias](fromPath, request, alias) if (!aliasTarget || typeof aliasTarget !== 'string') { throw new Error('[module-alias] Expecting custom handler function to return path.') } } request = nodePath.join(aliasTarget, request.substr(alias.length)) // Only use the first match break } } return oldResolveFilename.call(this, request, parentModule, isMain, options) }
看似簡單的背後,往往也會踩坑
一般我們會在node
專案中使用module-alias
函式庫,因為node
專案一般會從typescript
轉換成js
程式碼,但是往往不會進行打包處理,因為node
專案中一般也確實不需要打包,顯得有些冗餘。這時候就需要module-alias
上場了。
但這個專案有點不一般,我們在專案中使用了多層程式碼組織方式,最外層有全域的package.json
, 內層套件有自己的 package.json
, 簡單說是使用了monorepo
的程式碼組織方式,問題也就是由此而來。
module-alias無法正常解析在package.json中配置的路徑別名
剛開始確實沒想到是多層專案組織方式的問題,官網對module-alias/register
使用有一段說明:
#但是當時確實也是沒有註意到這塊說明,要不然也不會踩這個坑了,下次看使用說明要仔細了,不過這麼長的使用說明,大概率還是不會看的這麼仔細。 。 。畢竟看起來這麼簡單的使用方法,好像似乎是不會出什麼問題的吧
既然踩坑了,就有必要了解一下踩坑的原因,避免反复踩坑才好。可以详细了解下module-alias
中init
方法的实现。为了节省篇幅,省略了部分细节
function init (options) { // 省略了部分内容 var candidatePackagePaths if (options.base) { candidatePackagePaths = [nodePath.resolve(options.base.replace(/\/package\.json$/, ''))] } else { // There is probably 99% chance that the project root directory in located // above the node_modules directory, // Or that package.json is in the node process' current working directory (when // running a package manager script, e.g. `yarn start` / `npm run start`) // 重点看这里!!! candidatePackagePaths = [nodePath.join(__dirname, '../..'), process.cwd()] } var npmPackage, base for (var i in candidatePackagePaths) { try { base = candidatePackagePaths[i] npmPackage = require(nodePath.join(base, 'package.json')) break } catch (e) { // noop } } // 省略了部分内容 var aliases = npmPackage._moduleAliases || {} for (var alias in aliases) { if (aliases[alias][0] !== '/') { aliases[alias] = nodePath.join(base, aliases[alias]) } } // 省略了部分内容 }
可以看重点部分,如果我们没有给base参数,module-alias
默认会从../../
目录和当前目录下找寻package.json
文件,而且../..
目录下的package.json
文件的优先级比当前目录下的优先级还要高,这里的优先级设置似乎和正常的优先级逻辑有点差别,一般都会让当前目录的优先级比较高才比较符合正常逻辑,所以会导致加载的不是当前目录下的package.json
文件,而导致找不到路径别名配置而出错。
关于这点似乎有不少人踩坑了,还有人提了issues,但是似乎暂时并没有人回应。
通过API方式注册路径别名,或者手动调用init
方法,传入base参数,指定package.json
文件.
似乎只有踩坑了,才会更深入的了解
更多node相关知识,请访问:nodejs 教程!!
以上是深入了解node.js中的module-alias(分享一些避坑方法)的詳細內容。更多資訊請關注PHP中文網其他相關文章!