Startseite / Artikel / Nodes native Unterstützung für TypeScript: 7 tatsächliche Probleme und Lösungen

Nodes native Unterstützung für TypeScript: 7 tatsächliche Probleme und Lösungen

Erfahren Sie, welche TypeScript-Funktionen durch das eingebaute Typentrennungsverhalten von Node in der Produktion stillschweigend beeinträchtigt werden, sowie die genauen Konfigurationslösungen, die bei Node 22.18+ und 24.x LTS getestet und funktioniert haben.

2809 Wörter

Ein Team, das einen kleinen Express-Dienst migrierte, entschied sich dafür, ts-node wegzulassen und die Anwendung direkt mit node file.ts in der Staging-Umgebung auszuführen. Der Wechsel schien bei lokalen Tests problemlos zu funktionieren, doch bereits am nächsten Arbeitstag zeigten die CI-Pipelines fehlerhafte Builds, einige Entwickler erhielten in ihren Terminals die Fehlermeldung ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX, und ein Hotfix für die Produktion wurde ohne jegliche Typüberprüfung bereitgestellt, da dieses Sicherheitsnetz stillschweigend verschwunden war.

Nodes native Handhabung von TypeScript durch das Entfernen von Typinformationen ist eine solide Funktion. Allerdings umfasst sie einen schmaleren Bereich von TypeScript, als die meisten annehmen, und die Lücken werden erst dann offensichtlich, wenn man sie in der Praxis erlebt. Im Folgenden sind sieben Probleme aufgeführt, die während einer echten Migration auftauchten, zusammen mit den tatsächlich auftretenden Fehlern sowie den nachgewiesenen Lösungen unter Verwendung von Node 22.18+ und 24.x LTS.

Die Theorie versus die Realität

Node führt TypeScript aus, indem es die Typangaben zur Laufzeit entfernt, wobei dabei eine eingebaute Version von swc verwendet wird. Es ruft niemals den TypeScript-Compiler auf. Es gibt keine tsc-Phase. Folglich findet auch keine Typüberprüfung statt, es erfolgt keine Syntaxumwandlung für ältere Zielplattformen, es wird keine Auflösung von Pfadaliasen vorgenommen, es gibt keine Unterstützung für .tsx-Dateien, keine Unterstützung für Dekoratoren, keine Enumerationen und keine Laufzeit-Codegenerierung für Namespaces.

Das Ausführen von node file.ts funktioniert zwar und stellt eine echte Möglichkeit dar, repräsentiert aber nur die minimale Funktionalität und nicht das volle Funktionsset von TypeScript.

1. Meine relativen Importe liefern in der Produktion stumm 404-Fehler

Das Symptom. Alles funktionierte lokal. Doch nach der Bereitstellung scheiterte die Anwendung beim Start mit einem Fehler wie diesem:

Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/srv/app/dist/utils/hash.js'
imported from /srv/app/dist/server.js

Was passiert ist. Das Entfernen von Typangaben beseitigt nur Anmerkungen; alle anderen Token im Dateiinhalt bleiben unberührt, einschließlich der Importpfade. Somit wird eine Quelldatei wie diese:

// src/server.ts
import { hashToken } from "./utils/hash.js";

unverändert weitergeleitet. Während der lokalen Entwicklung war node --experimental-strip-types clever genug, um ./utils/hash.ts zu finden, obwohl die Endung .js angab. Doch der Build-Prozess (Kompilieren mit tsc in eine dist-Ordner) behielt die exakte .js-Endung in der Zeichenkette bei, und es gab keine entsprechende .js-Datei in dist/utils/ – nur .ts-Quellen waren an anderer Stelle kompiliert worden.

Die Lösung. Zwei getrennte Änderungen müssen gemeinsam vorgenommen werden.

Zuerst muss die Import-Endung so festgelegt werden, dass sie mit dem tatsächlichen Dateinamen auf der Festplatte übereinstimmt – das heißt .ts, nicht .js:

// src/server.ts
import { hashToken } from "./utils/hash.ts";

Zweitens muss dem Compiler mitgeteilt werden, dass dies beabsichtigt ist, damit er die Endung während der Ausgabe umwandelt:

{
  "compilerOptions": {
    "noEmit": true,
    "allowImportingTsExtensions": true,
    "rewriteRelativeImportExtensions": true,
    "module": "nodenext",
    "moduleResolution": "nodenext",
    "target": "esnext",
    "verbatimModuleSyntax": true,
    "erasableSyntaxOnly": true
  }
}

Die entscheidende Einstellung ist rewriteRelativeImportExtensions: true; sie wandelt ./utils/hash.ts wieder in ./utils/hash.js um, wenn tsc die Ausgabe erzeugt, sodass das kompilierte JavaScript weiterhin korrekt funktioniert. noEmit: true ist hier nicht optional – ohne diese Einstellung führt allowImportingTsExtensions zu einem TS5096-Fehler. Weitere Details finden Sie in der TypeScript-Dokumentation.

2. Die Hälfte meines Codebases hatte „ungestützte Syntax“

Das Symptom. Ein Entwickler stieß bei seinem allerersten Commit nach dem Umstieg auf diesen Fehler:

TypeError [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]: TypeScript enum declarations are
not supported by Node's type stripping. Convert enums to objects with `as const`
or use a transformer.

Ein anderer rannte mit einem Klassenkonstruktor gegen eine ähnliche Hürde:

TypeError [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]: TypeScript parameter properties
are not supported. Use an explicit field declaration instead.

Was passiert ist. Nodes Engine zur Entfernung von Typinformationen unterstützt absichtlich nur eine begrenzte Kategorie an Syntax: Konstrukte, die vollständig entfernt werden können, ohne das Laufzeitverhalten zu verändern – sogenannte „erasable“-Syntax. Jede TypeScript-Funktion, die tatsächlich JavaScript-Logik zur Laufzeit erzeugt, wird stattdessen mit einer Laufzeitausnahme abgelehnt, anstatt transformiert zu werden.

Die vollständige Liste der nicht unterstützten Konstrukte, entnommen der offiziellen Node TypeScript-Dokumentation, umfasst: enum-Deklarationen, die zu einer String-Union oder einem Objekt mithilfe von as const umgewandelt werden müssen; namespace-Blöcke, die Laufzeitlogik enthalten und deren exportierte Werte in einfache Modul-Exports verschoben werden müssen (Namenräume, die nur Typen enthalten, sind weiterhin zulässig); Parametereigenschaften in Konstruktoren (wie constructor(public x: number)), für die stattdessen eine explizite Felddeklaration erforderlich ist; Import-Aliasse, die beim Import umbenannt werden müssen; Decoratoren, die auf der Parser-Ebene fehlschlagen und nicht polyfillt werden; sowie .tsx-Dateien, da nur die Erweiterungen .ts, .mts und .cts erkannt werden.

Die Lösung. So wird der Enum-Case gelöst:

// before ;  dies at runtime
enum Role { Admin = "admin", User = "user" }

// after ;  works under type stripping AND in tsc
const Role = {
  Admin: "admin",
  User: "user",
} as const;

type Role = (typeof Role)[keyof typeof Role];

Für Decorator ist der sicherste Ansatz, abzuwarten, bis der Parser von Node die TC39-Decorator-Vorschläge nativ unterstützt, bevor man sie verwendet – oder einen Transformer wie swc oder tsc im Pipeline zu behalten, insbesondere für Dateien, die darauf angewiesen sind. Es lohnt sich auch, in tsconfig.json "erasableSyntaxOnly": true zu aktivieren – dadurch weist der Compiler nicht unterstützte Syntax direkt im Editor aus, noch bevor sie den Laufzeitmodus erreicht.

3. Typüberprüfungen finden stumm nicht statt

Das Symptom. Ein Produktionshandler akzeptierte einen null-Wert, obwohl ein string erwartet wurde, und stürzte ab, als .length darauf aufgerufen wurde. Der Unit-Test für diesen Pfad verlief ohne Probleme. Die Variable war als string typisiert, der tatsächliche Wert war jedoch null, und node file.ts führte beides ohne Einwände aus.

app.post("/webhook", (req, res) => {
  const body: string = req.body.payload; // null sneaks in, no one notices
  console.log(body.length);
});

Was passiert ist. Das Typentfernen erfolgt auf rein textlicher Ebene – es konsultiert niemals den Typüberprüfer. Im Ausführungspfad von node wird nicht überprüft, ob die Werte, die durch den Code fließen, zu ihren deklarierten Typen passen.

Dies ist wohl der riskanteste, stille Fehlermodus, der durch den Verzicht auf ts-node entsteht. Ein erfolgreicher Ausführung von node file.ts sagt nichts darüber aus, ob der Code typgerecht ist.

Die Lösung. Führen Sie die Typüberprüfung wieder als separaten, expliziten Schritt ein.

// package.json
{
  "scripts": {
    "dev": "node --watch src/server.ts",
    "typecheck": "tsc --noEmit",
    "lint": "biome check .",
    "ci": "npm run typecheck && npm run lint"
  }
}

Führen Sie tsc --noEmit im Rahmen des CI für jeden Pull Request aus und überlegen Sie, es in Pre-Commit-Hooks zu integrieren, falls das zu Ihrem Workflow passt. Der native Laufzeitumgebung führt den Code aus; tsc ist das Tool, das für die Erkennung von Typfehlern zuständig ist. Diese beiden Aspekte sind nun vollständig voneinander getrennt, und diese Trennung ist im Design von Node beabsichtigt.

Auch lohnt es sich, in tsconfig.json "erasableSyntaxOnly": true zusammen mit "verbatimModuleSyntax": true zu aktivieren. Die erste Einstellung sorgt dafür, dass tsc alles ablehnt, was die Typentrennung nicht bewältigen kann – wodurch Dekoratoren oder Enums bereits zur Kompilierzeit und nicht erst zur Laufzeit erkannt werden. Die zweite Einstellung erzwingt explizite import type-Anweisungen, damit Importe, die nur Typen enthalten, keine übrig gebliebenen Laufzeit-Importanweisungen hinterlassen.

4. Meine Pfadeigenschaften @/utils/* funktionieren nicht mehr

Das Symptom. Ein bekannter Fehler:

Error [ERR_MODULE_NOT_FOUND]: Cannot find module '@/utils/logger'
imported from /srv/app/src/server.ts

Was vor sich ging. Das Feld paths in tsconfig.json dient ausschließlich als Kompatibilitätsmerkmal für TypeScript zur Kompilierzeit – Node selbst hat es nie verstanden. Werkzeuge wie ts-node und tsx berücksichtigten es, weil sie ihre eigene Modulauflösungslogik auf Basis von Node implementierten. Die native Typentrennung tut das nicht; sie überlässt die Auflösung direkt dem Loader von Node.

// tsconfig.json ;  this never worked at runtime, it only worked in your editor
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": { "@/utils/*": ["src/utils/*"] }
  }
}

Die Lösung. Es gibt drei legitime Ansätze, je nachdem, wie Ihre Anwendung bereitgestellt wird.

Option A: Verwenden Sie Nodes eingebaute Subpath-Importe. Entfernen Sie die tsconfig-Pfade vollständig und deklarieren Sie die Zuordnung stattdessen in package.json:

{
  "imports": {
    "#utils/*": "./src/utils/*"
  }
}
// src/server.ts
import { logger } from "#utils/logger.ts";

Dies funktioniert korrekt unter node, unter tsc --noEmit sowie unter vitest, ohne dass irgendwo zusätzliche Konfiguration erforderlich ist. Das vorangestellte # ist eine eigene Konvention von Node, die anzeigt „Dies ist ein interner Alias, kein veröffentlichtes Paket.“ Die Migration bedeutet lediglich eine projektweite Suche und Ersetzung von @/utils/ durch #utils/.

Option B: Auf relative Importe zurückgreifen und mit den ../-Verknüpfungen leben. Das ist umständlich, erfordert aber keine versteckten Tools.

Option C: Ein Pfad-Umwandlungs-Tool beibehalten. Tools wie tsc-alias überschreiben die nach der Kompilierung erzeugte JavaScript-Datei, oder man kann tsx/swc dazu bringen, die Aliase zur Laufzeit zu lösen. Dadurch wird der Build-Schritt wieder eingeführt, den man eigentlich vermeiden wollte, was einen großen Teil des Vorteils von nativem TypeScript schmälert. Das ist kein Weg, den man im Jahr 2026 einschlagen sollte.

5. Die Interoperabilität zwischen CommonJS und ESM hat mich überrascht

Das Symptom. Ein Aufruf von require("openai"), der bisher immer funktioniert hatte, warf plötzlich folgenden Fehler aus:

Error [ERR_REQUIRE_ESM]: require() of ES Module ... openai ... not supported.

Oder in die entgegengesetzte Richtung: Ein Verweis auf eine Datei in einem Verzeichnis ohne Erweiterung funktionierte nicht mehr:

Error [ERR_UNSUPPORTED_DIR_IMPORT]: Directory import ... is not supported
under ESM

Was vor sich ging. Früher wurde Ihre Quelldatei von tsc in eine .js-Datei in dist/ kompiliert, und require() funktionierte wie erwartet. Bei der direkten Ausführung von TypeScript ist es die .ts-Datei selbst, die Node lädt, und Node entscheidet daraufhin, ob sie als CommonJS oder ESM behandelt werden soll, anhand des "type"-Feldes des nächstgelegenen package.json. Wenn dieses Feld den Wert "module" enthält, gelten alle im Scope befindlichen .ts-Dateien als ESM, wodurch alle verbleibenden require()-Aufrufe fehlschlagen. Fehlt dieses Feld (was standardmäßig CommonJS bedeutet), tritt das Gegenteil auf: Der Import einer nur für ESM geeigneten Abhängigkeit scheitert.

Die Lösung. Wählen Sie ein Modulsystem aus und setzen Sie es im gesamten Projekt durch.

Falls Sie von vorne anfangen, setzen Sie in package.json "type": "module" ein, schreiben Sie alles im ESM-Format und reservieren Sie die Erweiterungen .mts/.cts für die seltenen Dateien, die tatsächlich in dem anderen Format sein müssen.

// package.json
{
  "type": "module",
  "engines": { "node": ">=22.18.0" }
}

// src/server.ts
import { readFile } from "node:fs/promises";   // ESM, native
import OpenAI from "openai";                    // pure ESM upstream
const openai = new OpenAI();

Bei einer bereits vorhandenen CommonJS-Codebasis beibehalten Sie "type": "commonjs" (oder lassen Sie das Feld weg) – und vermeiden Sie es, ein reines ESM-Paket aus CommonJS-Code ohne Einsatz eines dynamischen import() zu verwenden. Node 22.12+ unterstützt zwar bereits ein stabiles require(esm), doch die Abhängigkeit davon setzt Sie weiterhin den Gefahren von Doppel-Paketen aus und macht Ihre Build-Prozesse anfällig. Sicherere Optionen sind es, die aufrufende Datei in ESM umzuwandeln oder die Abhängigkeit innerhalb einer async-Funktion mittels dynamischem Import zu verarbeiten.

Es gibt hier eine weitere Falle: Importe aus Verzeichnissen. Unter ESM führt das Schreiben von import x from "./folder" nicht mehr automatisch zu ./folder/index.ts, wie es früher der Fall war. Sie müssen den Dateinamen explizit angeben:

// bad
import { routes } from "./routes";

// good
import { routes } from "./routes/index.ts";

6. Der Überwachungsmodus und das Hot Reloading haben einen Rückschritt gemacht

Das Symptom. Nach dem Wechsel von tsx watch src/server.ts zu node --watch src/server.ts haben sich mehrere Dinge verschlechtert:

  • Neustartgeschwindigkeit – node --watch funktioniert zwar, ist aber deutlich langsamer.
  • Toxisches Reloading bei Änderungen in importierten Dateien außerhalb der Projektwurzel.
  • Die Möglichkeit, einen manuellen Neustart über SIGUSR2 auszulösen.
  • Die farbige Ausgabe sowie die freundliche Aufforderung „Drücken Sie R zum Neustart“.
  • Sensible Standardausschlüsse für node_modules, dist und .test.ts-Dateien.
  • Was vor sich ging. node --watch ist Node’s seit langem vorhandener eingebauter Dateiüberwacher. Dank des Entfernens von Typinformationen funktioniert er nun auch mit .ts-Dateien, war aber nie als vollständige Alternative zu spezialisierten Tools wie tsx watch oder nodemon konzipiert – er ist eher eine grundlegende Funktion.

    Die Lösung. Verwenden Sie node --watch, wenn Sie bei jeder Änderung an einer einzelnen Skriptdatei nur einen Neustart benötigen. Für einen echten Server mit Importketten sowie einen tatsächlichen Entwicklungs- oder Testzyklus sollten Sie weiterhin tsx watch nutzen. Es gibt nichts Falsches daran, tsx weiterhin als Entwicklungs-Tool zu verwenden, selbst nachdem die Produktivausführung auf natives TypeScript verlagert wurde.

    // package.json ;  pragmatic split
    {
      "scripts": {
        "dev": "tsx watch src/server.ts",
        "start": "node --enable-source-maps src/server.ts",
        "start:native": "node src/server.ts"
      }
    }
    

    tsx läuft unter Esbuild und ist deutlich schneller als tsc – laut den eigenen Benchmarks etwa 20 bis 30 Mal schneller – er versteht Pfad-Aliasen standardmäßig und verhält sich wie node --watch, wären dem Überwachungsmodus mehr Produktionsaufmerksamkeit gewidmet worden.

    7. Das Überspringen des Build-Schritts hat das Problem nur verschoben

    Das Symptom. Nachdem angekündigt wurde, dass das Team tsc zugunsten einer nativen Ausführung aufgeben würde, traten fast sofort einige Probleme auf:

    • Die im npm veröffentlichte SDK-Version benötigte .d.ts-Deklarationsdateien für nachfolgende Nutzer. Die native Ausführung von TypeScript erzeugt diese nicht.
    • Das Lambda-Deployment-Ziel erwartete eine CommonJS-Ausgabe, während der Code als ESM geschrieben war.
  • Ein Kollege, der noch auf Node 20.x arbeitet, versuchte, das Paket zu installieren, konnte es aber einfach nicht – die Laufzeitumgebung unterstützte das benötigte Entfernen von Codeabschnitten nicht.
  • Das Docker-Bild wurde größer, da nun rohe .ts-Quelldateien statt kompilierter Ausgabe übertragen wurden.
  • Was passiert ist. Das Entfernen von Codeabschnitten findet in der Laufzeitumgebung statt, nicht während des Kompilierens – das ist schließlich der Sinn dieser Funktion. Sobald Ihr Code jedoch an einem Ort ausgeführt werden muss, der nicht „Node 22 oder neuer, direkt aus Ihrem Repository“, ist, benötigen Sie wieder einen Kompilierungsschritt. Er verschwindet nicht; er wird lediglich in einen anderen Teil des Pipelines verlegt.

    Die Lösung. Seien Sie konkret bezüglich dessen, was Sie tatsächlich übertragen.

    Falls Sie eine Anwendung entwickeln – also einen Dienst, den Sie selbst bereitstellen und ausführen – ist natives TypeScript eine echte Verbesserung. Es gibt keinen Build-Prozess, die Kaltstartzeiten sind kürzer, und der Dockerfile wird einfacher, da Sie einfach COPY src ./src verwenden können, anstatt sich um ein dist/-Verzeichnis kümmern zu müssen.

    # Dockerfile
    FROM node:24-slim
    WORKDIR /app
    COPY package.json package-lock.json ./
    RUN npm ci --omit=dev
    COPY src ./src
    COPY tsconfig.json ./
    CMD ["node", "--enable-source-maps", "src/server.ts"]
    

    Falls Sie eine für npm vorgesehene Bibliothek warten, behalten Sie tsc für den eigentlichen Ausgabevorgang bei. Sie können während der Entwicklung und des Testens gerne natives TypeScript verwenden, doch das veröffentlichte Paket muss weiterhin kompilierte .js-Dateien zusammen mit .d.ts-Dateien enthalten.

    // package.json ;  library case
    {
      "scripts": {
        "dev": "node --watch src/index.ts",
        "build": "tsc",
        "test": "node --test --experimental-strip-types test/*.test.ts"
      }
    }
    

    Falls Ihr Ziel serverlose Umgebungen, Edge-Runtimes oder Nutzer mit Node 20.x sind, benötigen Sie dennoch einen Transpiler – entweder swc oder tsc – der so konfiguriert ist, dass er Inhalte erzeugt, die ältere Runtimes ausführen können. Der Build-Schritt, den Sie für überflüssig hielten, ist dort weiterhin erforderlich.

    Lohnt es sich? Die ehrliche Einschätzung.

    Die native Unterstützung für TypeScript könnte die bedeutendste Verbesserung in Node seit Einführung von async/await sein – doch diese Lobeshymnen gehen mit einer erheblichen Einschränkung einher.

    Es macht Sinn, sie zu übernehmen, wenn Sie:

    • einen selbst verwalteten Service auf Node 22.18+ oder der 24.x LTS-Reihe bereitstellen.
    • bereits sauberen, leicht zu überprüfenden TypeScript-Code schreiben – ohne Enums, ohne Decorator, ausschließlich mit reiner ESM-Syntax.
    • einen CI-Job laufen lassen, der tsc --noEmit verwendet, damit die Typüberprüfung nicht heimlich aus Ihrem Workflow verschwindet.
  • Schnellere Kaltstartzeiten, kompaktere Dockerfiles sowie eine weniger Abhängigkeit in node_modules.
  • Es ist besser, bei tsx oder tsc zu bleiben, wenn Sie:

    • eine Bibliothek veröffentlichen, die für Ihre Nutzer auf älteren Node-Versionen laufen muss.
    • stark von NestJS, TypeORM, class-validator oder anderen Werkzeugen abhängig sind, die auf experimentellen Dekoratoren basieren.
    • Unterstützung für .tsx-Dateien für serverseitig gerenderte React-Komponenten benötigen.
    • von tsconfig-Pfadalias abhängen und noch nicht bereit sind, auf das imports-Feld umzusteigen.
    • bislang noch nicht die Disziplin (oder die richtigen Werkzeuge) haben, um unerwünschte Syntaxelemente aus Ihrem Codebase zu entfernen.

    Die Einstellungen, die dies letztendlich machbar gemacht haben:

    // tsconfig.json
    {
      "compilerOptions": {
        "target": "esnext",
        "module": "nodenext",
        "moduleResolution": "nodenext",
        "noEmit": true,
        "allowImportingTsExtensions": true,
        "rewriteRelativeImportExtensions": true,
        "verbatimModuleSyntax": true,
        "erasableSyntaxOnly": true,
        "strict": true,
        "skipLibCheck": true,
        "isolatedModules": true,
        "resolveJsonModule": true
      },
      "include": ["src/**/*"]
    }
    
    // package.json (snippet)
    {
      "type": "module",
      "engines": { "node": ">=22.18.0" },
      "scripts": {
        "dev": "tsx watch src/server.ts",
        "start": "node --enable-source-maps src/server.ts",
        "typecheck": "tsc --noEmit",
        "test": "node --test --experimental-strip-types 'src/**/*.test.ts'",
        "ci": "npm run typecheck && npm test"
      }
    }
    

    Das ist die gesamte Konfiguration. Kein ts-node in Sicht. Kein tsc im Ausführungspfad der Laufzeit. Kein umfangreiches nodemon.json-Datei. Ein Tool kümmert sich um die Entwicklung, ein anderes um die Typüberprüfung und ein weiteres um den Produktivbetrieb. Um klarzustellen: node_modules ist immer noch genauso überdimensioniert wie zuvor – dieser Aspekt des Node-Ökosystems hat sich seit 2009 nicht verändert.

    Der eigentliche Vorteil besteht nicht darin, dass ts-node aus Ihren Abhängigkeiten entfernt wird. Vielmehr hören Sie auf zu glauben, dass das Entfernen von ts-node auch Ihren Build-Schritt beseitigt. Die native Ausführung von TypeScript ist ein kleinerer, schnellere und transparentere Build-Prozess – doch es bleibt weiterhin ein Build-Prozess. Diese Migration bedeutet keinen Übergang von „einem Build haben“ zu „keinem Build mehr haben“. Es handelt sich vielmehr um einen Übergang von einem Build-Schritt, den man nicht erkennen konnte, zu einem, den man tatsächlich versteht.

    Verwandte Artikel

  • Jest durch den eigenen Test-Runner von Node in Node 24 ersetzen – Eine reale Migrationsanwendung zeigt, wie der integrierte Test-Runner von Node 24 sowie die native TypeScript-Unterstützung die CI-Zeit verkürzen und gleichzeitig vier Abhängigkeiten beseitigen.