lars
webmobiledatenbankendevopsarchitektur
hello (at) larskoelpin.de

TypeScript Path mapping in Node Applikationen

September 02, 2022
typescript

In TypeScript SPA-Projekten basierend auf vite wird häufig auf TypeScript Path-Aliases gesetzt. Path-aliases ermöglichen es dem Entwickler, den häufig verhassten relativen import zu umgehen. Es liegt nahe, dass es auch für Serverseitige Applikationen ohne Weiteres funktioniert. Leider nicht, wie es sicht herausstellt.

Anstatt klassische relative Imports zu verwenden, wird häufig die TypeScript Konfiguration dahingehend angepasst, bestimmte Symbole auf absolute Pfade (relativ zum “basePath”) aufzulösen. Eine solche TypeScript Konfiguration sieht in der Regel so aus:

{
  compilerOptions:{
    "module": "commonjs",
    "paths": {
       "@": "src/**"
      }
  }

}

Absolute Imports in den Modulen selbst werden dann häufig durch das angegebene Symbol umgesetzt.

// Bar.ts: src/baz/bar/bum/Bar.ts
// Foo.ts: src/bar/Foo

// Bar.ts
import Foo from '@/bar/Foo';

Wird dieser Code durch den TS-Compiler kompiliert, könnte man erwarten, dass dieser die Pfade entsprechend der Konfiguration auflöst.

// Bar.js: dist/baz/bar/bum/Bar.js
const Foo = require("../../../bar/Foo")

Würde man den Code also mit NodeJS ausführen,

node dist/baz/bar/bum/Bar.js

sollte die Applikation ganz normal ausgeführt werden können.

Leider Falsch. Denn leider ist die Welt nicht immer so, wie man sie erwartet. Anstatt, dass TypeScript nämlich Code kompiliert, der die Pfade auflöst, kompiliert der TypeScript-Compiler folgenden Code

const Foo = require("@/bar/Foo")

Das Mapping aus der tsconfig.json hat auf den kompilierten Code also keine Auswirkung. Sollen absolute imports genutzt werden, muss der kompilierte Code deshalb nochmals editiert werden (z.B. durch Tools wie tspath). Path aliases sind deshalb für Applikationen ohne weiteres Tooling wie beispielsweise loader nur begrenzt sinnvoll.

Wozu dann also das Path-Mapping, wenn es augenscheinlich keinen Einfluss hat? Das Path Mapping hat im Grunde zwei Funktionen. Zum Einen ist der Code ist überhaupt kompilierbar, da TypeScript dem @-Symbol auf ein echten Modul-Import auflösen kann. Zum Anderen dient das Path-Mapping als API für das weitere Tooling (wie beispielsweise vite). Dieses kann die imports entsprechend mithilfe dessen auflösen.

Quelle: https://github.com/microsoft/TypeScript/issues/10866