Heim > Web-Frontend > js-Tutorial > Erfahren Sie mehr über Modulalias in node.js (teilen Sie einige Fallstricke)

Erfahren Sie mehr über Modulalias in node.js (teilen Sie einige Fallstricke)

青灯夜游
Freigeben: 2021-12-20 11:05:49
nach vorne
5486 Leute haben es durchsucht

Dieser Artikel führt Sie zum Verständnis des Modulalias in node.js, stellt das Prinzip des Modulalias vor und zeigt ein häufiges Problem (Pit) des Modulalias auf. Ich hoffe, dass es für alle hilfreich ist!

Erfahren Sie mehr über Modulalias in node.js (teilen Sie einige Fallstricke)

Zunächst muss vorgestellt werden, was module-alias ist. Hier ist der offizielle Website-Link (offizielle Website-Adresse https://github.com/ilearnio/module-alias). ). module-alias是什么,这里有其官网链接(官网地址 https://github.com/ilearnio/module-alias)。

简单点说,module-alias提供了在node环境下的路径别名功能。一般前端开发可能会比较熟悉webpackalias配置、typescriptpaths配置等,这些都是提供了陆军别名的功能。路径别名在代码开发过程中是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);
Nach dem Login kopieren

这里是tsconfig.json的配置内容

"paths": {
  "@/*": [
    "src/*"
  ]
}
Nach dem Login kopieren

可以看到在经过typescript编译后的代码中,仍然存在@符号,然而当代码运行的过程中,比如允许在node中,require并不能正常识别路径里的这个符号,导致找不到相应模块而抛出异常。

这也是module-alias这个库存在的目的。

module-alias介绍

从官网上看,这个库使用方法只需要两步,真的已经是极简状态了。

1、路径别名配置:module-alias支持两种路径别名配置方式

  • package.json中增加_moduleAliases属性进行配置

    "_moduleAliases": {
        "@": "./src"
    }
    Nach dem Login kopieren
  • 通过提供的API接口addAliasaddAliasesaddPath,增加配置

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

2、在项目启动时首先导入该库:require(module-alias/register)即可,当然选择使用API方式的需要导入对应的函数进行处理

一般我们都是使用package.json中配置路径别名 + 项目入口处require(module-alias/register)来使用这个库。

module-alias原理介绍

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)
}
Nach dem Login kopieren

看似简单的背后,往往也会踩坑

module-alias踩坑

一般我们会在node项目中使用module-alias库,因为node项目一般会从typescript转换成js代码,但是往往并不会进行打包处理,因为node项目中一般也确实不需要打包,显得有些冗余。这时候就需要module-alias上场了。

但是这个项目有点不一般,我们在项目中使用了多层代码组织方式,最外层有全局的package.json, 内层包有自己的package.json, 简单说是使用了monorepo的代码组织方式,问题也就是由此而来

module-alias无法正常解析在package.json中配置的路径别名

刚开始确实没想到是多层项目组织方式的问题,官网对module-alias/register

Um es einfach auszudrücken: module-alias stellt die Pfad-Alias-Funktion in der

nodeErfahren Sie mehr über Modulalias in node.js (teilen Sie einige Fallstricke)-Umgebung bereit. Allgemeine Frontend-Entwickler sind möglicherweise mit der alias-Konfiguration von webpack, der paths-Konfiguration von typescript usw. vertraut . Diese werden bereitgestellt. Die Funktion des Armee-Alias ​​wurde hinzugefügt. Der Pfad-Alias ​​ist im Code-Entwicklungsprozess yyds, sonst werden Sie definitiv verrückt, wenn Sie diesen ../../../../xx-Pfad sehen.

Mit webpack gepackte Projekte übernimmt webpack selbst den Konvertierungsprozess von der Konfiguration des Pfadalias im Quellcode zum gepackten Code, aber wenn Sie einfach typescript</ Bei durch Code kompilierten Projekten kann <code>typescript zwar normalerweise die Konfiguration von Pfadaliasen in paths während des Kompilierungsprozesses verarbeiten, dies wird jedoch nicht geändert Daher ist die Pfad-Alias-Konfiguration weiterhin im gepackten Code vorhanden. Schauen Sie sich einen von typescript kompilierten Code an:

function init (options) {
  // 省略了部分内容
  var candidatePackagePaths
  if (options.base) {
    candidatePackagePaths = [nodePath.resolve(options.base.replace(/\/package\.json$/, &#39;&#39;))]
  } 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&#39; current working directory (when
    // running a package manager script, e.g. `yarn start` / `npm run start`)
    // 重点看这里!!!
    candidatePackagePaths = [nodePath.join(__dirname, &#39;../..&#39;), process.cwd()]
  }
  var npmPackage, base
  for (var i in candidatePackagePaths) {
    try {
      base = candidatePackagePaths[i]
      npmPackage = require(nodePath.join(base, &#39;package.json&#39;))
      break
    } catch (e) { // noop }
  }
  // 省略了部分内容
  var aliases = npmPackage._moduleAliases || {}
  for (var alias in aliases) {
    if (aliases[alias][0] !== &#39;/&#39;) {
      aliases[alias] = nodePath.join(base, aliases[alias])
    }
  }
  // 省略了部分内容
}
Nach dem Login kopieren
Nach dem Login kopieren
🎜Hier ist die Konfiguration von tsconfig.json</code > Inhalt🎜rrreee🎜Sie können sehen, dass das @-Symbol immer noch im von <code>typescript kompilierten Code vorhanden ist. Wenn der Code jedoch beispielsweise in node ausgeführt wird, < code>require kann dieses Symbol im Pfad nicht richtig erkennen, was dazu führt, dass das entsprechende Modul gefunden und eine Ausnahme ausgelöst wird. 🎜🎜Dies ist auch der Zweck der module-alias-Bibliothek. 🎜

Modul-Alias-Einführung

🎜Auf der offiziellen Website erfordert die Verwendung dieser Bibliothek nur zwei Schritte und ist wirklich minimalistisch. 🎜🎜1. Pfad-Alias-Konfiguration: module-alias unterstützt zwei Pfad-Alias-Konfigurationsmethoden🎜
  • 🎜Fügen Sie _moduleAliases in <code>package.json hinzu Eigenschaftskonfiguration🎜rrreee
  • 🎜Fügen Sie über die bereitgestellten API-Schnittstellen addAlias, addAliases, addPath hinzu. Konfigurieren Sie 🎜rrreee< /li>
🎜2. Importieren Sie zuerst die Bibliothek, wenn das Projekt startet: require(module-alias/register) Wenn Sie sich für die Verwendung der API-Methode entscheiden, müssen Sie dies natürlich tun Importieren Sie die entsprechende Funktion zur Verarbeitung🎜🎜Im Allgemeinen verwenden wir diese Bibliothek, indem wir den Pfadalias in package.json + require(module-alias/register) am Projekteingang konfigurieren . 🎜

Einführung in das Modul-Alias-Prinzip

🎜module-alias überschreibt das globale Objekt Module Die Methode <code>_resolveFilename wird zum Konvertieren des Pfadalias verwendet, indem der native Methodenaufruf _resolveFilename abgefangen wird Um den tatsächlichen Pfad der Datei zu ermitteln, rufen Sie die ursprüngliche Methode _resolveFilename auf. 🎜🎜Das Folgende ist der Quellcode, der im Wesentlichen in zwei Teile unterteilt ist: Pfad-Alias-Konvertierung + nativer _resolveFilename-Aufruf🎜rrreee
🎜Hinter dem scheinbar Einfachen stecken oft Fallstricke🎜

Module-Alias-Fallstricke

🎜Im Allgemeinen verwenden wir module- im <code>node-Projektalias -Bibliothek, da node-Projekte im Allgemeinen von typescript in js-Code konvertiert werden, häufig jedoch nicht gepackt werden, weil node< /code>-Projekte müssen im Allgemeinen nicht gepackt werden, was etwas überflüssig erscheint. Hier kommt <code>module-alias ins Spiel. 🎜🎜Aber dieses Projekt ist etwas ungewöhnlich. Wir verwenden im Projekt eine mehrschichtige Code-Organisationsmethode. Die äußerste Schicht hat ein globales package.json und das innere Paket hat einen eigenen package.json , vereinfacht gesagt, wird die Code-Organisationsmethode von monorepo verwendet, daher kommt das Problem. 🎜
🎜module-alias kann den in package.json konfigurierten Pfadalias nicht richtig auflösen🎜
🎜Zuerst hatte ich nicht erwartet, dass es ein Problem mit der Art und Weise sein würde, wie mehrschichtige Projekte organisiert sind. Die offizielle Website unterstützt module-alias/register nicht. Es gibt eine Gebrauchsanweisung: 🎜🎜🎜🎜🎜Aber ich habe diese Anleitung damals wirklich nicht beachtet, sonst wäre ich nicht darauf getreten Diese Falle sollten Sie das nächste Mal sorgfältig lesen, aber es ist eine so lange Anleitung, dass Sie sie höchstwahrscheinlich nicht so genau betrachten werden. . . Es scheint doch, dass es mit einer so einfachen Anwendungsmethode keine Probleme geben wird, oder?

module-alias/register流程

既然踩坑了,就有必要了解一下踩坑的原因,避免反复踩坑才好。可以详细了解下module-aliasinit方法的实现。为了节省篇幅,省略了部分细节

function init (options) {
  // 省略了部分内容
  var candidatePackagePaths
  if (options.base) {
    candidatePackagePaths = [nodePath.resolve(options.base.replace(/\/package\.json$/, &#39;&#39;))]
  } 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&#39; current working directory (when
    // running a package manager script, e.g. `yarn start` / `npm run start`)
    // 重点看这里!!!
    candidatePackagePaths = [nodePath.join(__dirname, &#39;../..&#39;), process.cwd()]
  }
  var npmPackage, base
  for (var i in candidatePackagePaths) {
    try {
      base = candidatePackagePaths[i]
      npmPackage = require(nodePath.join(base, &#39;package.json&#39;))
      break
    } catch (e) { // noop }
  }
  // 省略了部分内容
  var aliases = npmPackage._moduleAliases || {}
  for (var alias in aliases) {
    if (aliases[alias][0] !== &#39;/&#39;) {
      aliases[alias] = nodePath.join(base, aliases[alias])
    }
  }
  // 省略了部分内容
}
Nach dem Login kopieren
Nach dem Login kopieren

可以看重点部分,如果我们没有给base参数,module-alias默认会从../../目录和当前目录下找寻package.json文件,而且../..目录下的package.json文件的优先级比当前目录下的优先级还要高,这里的优先级设置似乎和正常的优先级逻辑有点差别,一般都会让当前目录的优先级比较高才比较符合正常逻辑,所以会导致加载的不是当前目录下的package.json文件,而导致找不到路径别名配置而出错。

关于这点似乎有不少人踩坑了,还有人提了issues,但是似乎暂时并没有人回应。

解决办法

通过API方式注册路径别名,或者手动调用init方法,传入base参数,指定package.json文件.

似乎只有踩坑了,才会更深入的了解

更多node相关知识,请访问:nodejs 教程!!

Das obige ist der detaillierte Inhalt vonErfahren Sie mehr über Modulalias in node.js (teilen Sie einige Fallstricke). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:juejin.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage