adminslog/dokus/js-ts/js-ts-dialekte.md

14 KiB
Raw Blame History

Einstieg in JavaScript-Dialekte und TypeScript-Konfiguration

Ziel dieses Dokuments

Diese Anleitung richtet sich an Anfänger, die lernen wollen, wann sie welchen JavaScript-Dialekt (CommonJS vs. ESM) verwenden sollten, wie sie TypeScript korrekt konfigurieren und worauf sie bei modernen Projekten achten müssen.

Inhalt


🔢 Begriffe erklärt

JavaScript-Dialekte (Modulsysteme)

Name Kürzel Typ Verwendung heute
CommonJS CJS require() Ältere Node.js-Projekte
ECMAScript Modules ESM import Browser, moderne Tools
  • CommonJS: Nutzt require() und module.exports. Standard bis Node 12.
  • ESM: Nutzt import/export. Standard im Browser und in Node ab Version 14+.

Was ist TypeScript?

TypeScript ist eine statisch typisierte Obermenge von JavaScript, die zu normalem JS kompiliert wird.


🔍 Wann verwende ich was?

Ziel Modulformat Empfehlung Grund
📅 Moderne Webanwendung ESM Ja Browser erwartet ESM
📄 Node.js CLI-Tool ESM oder CJS Beides möglich ESM zukunftssicher, CJS maximal kompatibel
🔐 Legacy-Node-Integration CJS Ja Viele NPM-Pakete sind CJS-only
🔌 Electron Renderer ESM Ja (Pflicht) Chromium-only, kein CJS
🔁 Vite/Webpack-Projekt ESM Ja Toolchain basiert auf ESM

🔧 TypeScript richtig konfigurieren

Eine vollständige Zusammenfassung zu ESM (ECMAScript Modules) wann du es verwenden kannst, solltest oder musst, sowie alle wesentlichen technischen Eigenschaften. Stil und Umfang entsprechen exakt der vorherigen CommonJS-Zusammenfassung.


📦 Was ist ESM?

ESM (ECMAScript Modules) ist das moderne Modulsystem von JavaScript:

  • verwendet import/export-Syntax
  • wird nativ von allen modernen Browsern und Node.js (ab v14+) unterstützt
  • ist Standard in allen modernen JS-Toolchains (Vite, Webpack, esbuild, etc.)
// ESM-Stil
import fs from 'node:fs/promises';
export function read(path) {
  return fs.readFile(path, 'utf-8');
}

Wann kann/sollte/muss man ESM verwenden?

🟢 Du kannst ESM verwenden, wenn

  • du mit modernen Node.js-Versionen (v16+) arbeitest
  • du ein Frontend-Tool oder ein Browser-kompatibles Projekt baust
  • du Tree-Shaking oder Dynamic import() nutzen willst
  • du Typkonsistenz mit dem Browser willst (gleiche Syntax wie dort)

🟡 Du solltest ESM verwenden, wenn

Situation Grund
🌐 Du entwickelst Webanwendungen mit Vite, Nuxt, Webpack o. ä. Diese Tools basieren auf ESM
💡 Du möchtest moderne Syntax und Tooling nutzen ESM ist Standard
🔄 Du willst import() dynamisch verwenden Nur in ESM verfügbar
📚 Du schreibst eine wiederverwendbare Bibliothek für neue Projekte Zukunftssicherheit
🧩 Du verwendest Deno, Bun oder moderne Plattformen ESM only

🔴 Du musst ESM verwenden, wenn

  • du im Browser arbeitest (ohne Bundler) → dort ist import Pflicht
  • du in Electron-Renderer-Prozessen arbeitest
  • du ein Projekt hast mit "type": "module" und .js-Dateien → dann interpretiert Node sie nur als ESM
  • du ESM-only-Dependencies nutzt (z.B. chalk@5, node-fetch@3)

⚙️ TypeScript-Konfiguration für ESM

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "moduleResolution": "node",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true
  }
}

Und in der package.json:

{
  "type": "module"
}

Wichtig: Ohne "type": "module" behandelt Node deine .js-Dateien nicht als ESM, sondern als CommonJS.


📌 Merkmale von ESM

Merkmal ESM
Import-Syntax import, export
Export-Syntax export default, export {...}
Dateiendung .js .js nur mit "type": "module"
.mjs explizit ESM
__dirname, __filename nicht vorhanden, nur via import.meta.url
Dynamische Imports await import('...')
Tree Shaking möglich
Browser-kompatibel nativ
CommonJS-Interop mit Einschränkungen (createRequire)

⚠️ Besonderheiten und Stolperfallen

Problem Lösung
__dirname/__filename fehlen nutze import.meta.url + fileURLToPath()
require() nicht verfügbar verwende import, oder createRequire()
.js muss beim Import angegeben werden z.B. import './utils.js'
viele alte Pakete sind nicht ESM-kompatibel ggf. CommonJS verwenden

Fazit ESM

ESM ist der offizielle Standard für moderne JavaScript-Entwicklung sowohl im Browser als auch in modernen Node.js-Umgebungen.

Du solltest ESM verwenden, wenn du:

  • neue Projekte startest,
  • moderne Toolchains nutzt,
  • oder langfristige Kompatibilität willst.

In Zweifelsfällen gilt: Wenn du mit aktuellen Tools und Node-Versionen arbeitest, nimm ESM. Nur bei Problemen mit alten Paketen oder Tooling solltest du temporär auf CommonJS zurückfallen.


🌐 CommonJS-Konfiguration CJS (Alternative)

📦 Was ist CommonJS?

CommonJS (CJS) ist das ursprüngliche Modulsystem von Node.js:

  • verwendet require() zum Importieren
  • verwendet module.exports oder exports zum Exportieren
  • keine native Unterstützung für import/export
  • funktioniert nur in Node.js (nicht im Browser ohne Bundler)
// CommonJS-Stil
const fs = require('fs');
module.exports = { read: fs.readFileSync };

Wann kann/sollte/muss man CommonJS verwenden?

🟢 Du kannst CJS verwenden, wenn

  • du ein CLI-Tool oder Node.js-Skript erstellst
  • du maximale Kompatibilität ohne ESM-Komplikationen willst
  • du keine modernen ESM-Features brauchst
  • du auf Build-Tools verzichtest und direkt .js-Dateien startest

🟡 Du solltest CJS verwenden, wenn

Situation Grund
🔄 Du arbeitest mit älteren Node.js-Versionen (z.B. v12 oder v10) ESM ist dort nicht stabil
📦 Du nutzt NPM-Pakete, die kein ESM unterstützen require() wird erwartet
🧪 Du verwendest alte Tools, Tests oder Konfigurationen z.B. alte mocha, gulpfile.js, webpack.config.js
🧱 Du brauchst direkten Zugriff auf __dirname, __filename Diese fehlen in ESM
📜 Du möchtest .js-Dateien ohne .mjs oder type: module nutzen CommonJS macht keine Vorgaben für Dateiendungen

🔴 Du musst CJS verwenden, wenn

  • das Node.js-Modul, das du importieren willst, nur module.exports exportiert (kein ESM-Support)
  • dein Projekt oder Tool nicht mit ESM kompatibel ist (ältere Tooling oder NPM-Module)
  • du require() oder dynamisches Laden (require(dynamicPath)) verwendest, was in ESM nicht geht

⚙️ TypeScript-Konfiguration für CJS

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "CommonJS",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true
  }
}

Und in der package.json:

{
  "type": "commonjs"
}

Hinweis: Das "type"-Feld ist für Node wichtig, nicht für TypeScript.


📌 Merkmale von CommonJS

Merkmal CommonJS
Import-Syntax require()
Export-Syntax module.exports = …
Dateiendung .js (keine .mjs nötig)
Direkt ausführbar Ohne zusätzliche Flags
__dirname, __filename verfügbar
Browserkompatibilität Nur mit Bundler möglich
Dynamische Importe require(dynamicPath)
Tree Shaking nicht möglich

Fazit CommonJS

CommonJS ist stabil, weit verbreitet und maximal kompatibel. Wenn du einfach nur ein Node-Tool oder CLI-Skript baust und keine besonderen Build-Prozesse oder Browser-Kompatibilität brauchst: Nutze CommonJS.

Für moderne ESM-Projekte im Web oder wenn du zukunftssicher entwickeln willst, solltest du auf ESM setzen aber CJS bleibt in vielen Fällen die einfachste und robusteste Wahl.


📄 Fazit: Empfehlungen

  • Neue Projekte: Nutze ESM mit "type": "module"
  • Bestehende Tools nutzen require()? Dann CJS
  • Browser + Node gemeinsam nutzen? ESM-only + klare Trennung von shared/, client/, server/
  • Tooling wie Vite, Nuxt, Webpack? Immer ESM

📁 Dateiendungen in Node.js

Dateiendung Verhalten
.js Hängt von type ab
.mjs Immer ESM
.cjs Immer CommonJS

⚠️ Typische Fehler vermeiden

  • SyntaxError: Cannot use import statement outside a moduletype fehlt in package.json

  • Cannot find module bei relativen Imports.js fehlt am Ende beim ESM-Import

  • __dirname ist not defined → Du nutzt ESM, verwende import.meta.url


🚀 CLI-Build-Tipps (tsc)

npx tsc         # Kompiliert Projekt laut tsconfig.json
chmod +x dist/index.js   # Macht CLI-Datei ausführbar

Header für CLI-Datei:

#!/usr/bin/env node

📍 Weiterführende Themen

  • Dual-Exports für NPM (ESM + CJS gleichzeitig)
  • "exports"-Feld in package.json
  • Tools wie tsup, vite, esbuild als Alternativen zu tsc
  • Einstieg in CLI-Tools: commander, yargs, chalk, ora