溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

node.js中的module-alias怎么用

發(fā)布時(shí)間:2021-12-20 11:35:31 來源:億速云 閱讀:307 作者:小新 欄目:web開發(fā)

這篇文章主要為大家展示了“node.js中的module-alias怎么用”,內(nèi)容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“node.js中的module-alias怎么用”這篇文章吧。

首先有必要介紹一下module-alias是什么,這里有其官網(wǎng)鏈接(官網(wǎng)地址 https://github.com/ilearnio/module-alias)。

簡單點(diǎn)說,module-alias提供了在node環(huán)境下的路徑別名功能。一般前端開發(fā)可能會(huì)比較熟悉webpackalias配置、typescriptpaths配置等,這些都是提供了陸軍別名的功能。路徑別名在代碼開發(fā)過程中是yyds,不然你看到這種../../../../xx路徑時(shí),是肯定會(huì)抓狂的。

使用webpack打包的項(xiàng)目webpack本身會(huì)處理源代碼中路徑別名的配置到打包后代碼的轉(zhuǎn)換過程,但是如果單純使用typescript進(jìn)行編譯的項(xiàng)目,雖然typescript在編譯過程中可以正常處理paths中路徑別名的配置,但是并不會(huì)改變打包后的代碼,造成在打包后的代碼中仍然存在路徑別名配置,看一個(gè)經(jīng)過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的配置內(nèi)容

"paths": {
  "@/*": [
    "src/*"
  ]
}

可以看到在經(jīng)過typescript編譯后的代碼中,仍然存在@符號(hào),然而當(dāng)代碼運(yùn)行的過程中,比如允許在node中,require并不能正常識(shí)別路徑里的這個(gè)符號(hào),導(dǎo)致找不到相應(yīng)模塊而拋出異常。

這也是module-alias這個(gè)庫存在的目的。

module-alias介紹

從官網(wǎng)上看,這個(gè)庫使用方法只需要兩步,真的已經(jīng)是極簡狀態(tài)了。

1、路徑別名配置:module-alias支持兩種路徑別名配置方式

  • package.json中增加_moduleAliases屬性進(jìn)行配置

    "_moduleAliases": {
        "@": "./src"
    }
  • 通過提供的API接口addAliasaddAliases、addPath,增加配置

    moduleAlias.addAliases({
      '@'  : __dirname + './src',
    });

2、在項(xiàng)目啟動(dòng)時(shí)首先導(dǎo)入該庫:require(module-alias/register)即可,當(dāng)然選擇使用API方式的需要導(dǎo)入對(duì)應(yīng)的函數(shù)進(jìn)行處理

一般我們都是使用package.json中配置路徑別名 + 項(xiàng)目入口處require(module-alias/register)來使用這個(gè)庫。

module-alias原理介紹

module-alias通過覆寫了全局對(duì)象Module上的方法_resolveFilename來實(shí)現(xiàn)路徑別名的轉(zhuǎn)換,簡單來說就是通過攔截原生的_resolveFilename方法調(diào)用,進(jìn)行路徑別名的轉(zhuǎn)換,當(dāng)獲取到文件的真實(shí)路徑后,再調(diào)用原聲的_resolveFilename方法。

下面是其源代碼,基本上分為兩部分:路徑別名轉(zhuǎn)換+原生_resolveFilename調(diào)用

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)
}

看似簡單的背后,往往也會(huì)踩坑

module-alias踩坑

一般我們會(huì)在node項(xiàng)目中使用module-alias庫,因?yàn)?code>node項(xiàng)目一般會(huì)從typescript轉(zhuǎn)換成js代碼,但是往往并不會(huì)進(jìn)行打包處理,因?yàn)?code>node項(xiàng)目中一般也確實(shí)不需要打包,顯得有些冗余。這時(shí)候就需要module-alias上場了。

但是這個(gè)項(xiàng)目有點(diǎn)不一般,我們在項(xiàng)目中使用了多層代碼組織方式,最外層有全局的package.json, 內(nèi)層包有自己的package.json, 簡單說是使用了monorepo的代碼組織方式,問題也就是由此而來。

module-alias無法正常解析在package.json中配置的路徑別名

剛開始確實(shí)沒想到是多層項(xiàng)目組織方式的問題,官網(wǎng)對(duì)module-alias/register使用有一段說明:

node.js中的module-alias怎么用

但是當(dāng)時(shí)確實(shí)也是沒有注意到這塊說明,要不然也不會(huì)踩這個(gè)坑了,下次看使用說明要仔細(xì)了,不過這么長的使用說明,大概率還是不會(huì)看的這么仔細(xì)。。。畢竟看起來這么簡單的使用方法,好像似乎是不會(huì)出什么問題的吧

module-alias/register流程

既然踩坑了,就有必要了解一下踩坑的原因,避免反復(fù)踩坑才好??梢栽敿?xì)了解下module-aliasinit方法的實(shí)現(xiàn)。為了節(jié)省篇幅,省略了部分細(xì)節(jié)

function init (options) {
  // 省略了部分內(nèi)容
  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`)
    // 重點(diǎn)看這里?。。?
    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 }
  }
  // 省略了部分內(nèi)容
  var aliases = npmPackage._moduleAliases || {}
  for (var alias in aliases) {
    if (aliases[alias][0] !== '/') {
      aliases[alias] = nodePath.join(base, aliases[alias])
    }
  }
  // 省略了部分內(nèi)容
}

可以看重點(diǎn)部分,如果我們沒有給base參數(shù),module-alias默認(rèn)會(huì)從../../目錄和當(dāng)前目錄下找尋package.json文件,而且../..目錄下的package.json文件的優(yōu)先級(jí)比當(dāng)前目錄下的優(yōu)先級(jí)還要高,這里的優(yōu)先級(jí)設(shè)置似乎和正常的優(yōu)先級(jí)邏輯有點(diǎn)差別,一般都會(huì)讓當(dāng)前目錄的優(yōu)先級(jí)比較高才比較符合正常邏輯,所以會(huì)導(dǎo)致加載的不是當(dāng)前目錄下的package.json文件,而導(dǎo)致找不到路徑別名配置而出錯(cuò)。

關(guān)于這點(diǎn)似乎有不少人踩坑了,還有人提了issues,但是似乎暫時(shí)并沒有人回應(yīng)。

解決辦法

通過API方式注冊路徑別名,或者手動(dòng)調(diào)用init方法,傳入base參數(shù),指定package.json文件.

以上是“node.js中的module-alias怎么用”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI