Mit type: 'json' JSON-Dateien ohne fetch() und JSON.parse() importieren
Import Attributes erlauben es, JSON-Dateien direkt als ES-Modul zu importieren, mit einem expliziten type-Hinweis, der aus Sicherheitsgruenden zur Pflicht wurde. Das ersetzt in vielen Faellen fetch() plus JSON.parse() durch eine einzige Zeile.
Inhaltsverzeichnis
- 1. Vom Umweg ueber fetch() zum direkten Import
- 2. Syntax: import ... with { type: 'json' }
- 3. Dynamischer Import mit Attributen
- 4. Der Sicherheitsgedanke hinter dem Type-Attribut
- 5. Vergleich: JSON- und CSS-Module-Attribute
- 6. Browser- und Node.js-Support
- 7. Unterstuetzung in Bundlern und TypeScript
- 8. Wann fetch(), wann Import Attributes?
- 9. Best Practices und Zusammenfassung
- 10. Zusammenfassung
- 11. FAQ
1. Vom Umweg ueber fetch() zum direkten Import
Statische Konfigurationsdaten, Uebersetzungsdateien oder Testfixtures liegen in vielen Projekten als JSON-Datei vor. Bis vor kurzem gab es dafuer im Browser genau einen Standardweg: fetch('./data.json') aufrufen, auf die Response warten, .json() aufrufen und das Ergebnis weiterverarbeiten, alles asynchron und mit eigener Fehlerbehandlung fuer Netzwerk- und Parse-Fehler.
Import Attributes fuehren einen direkten, deklarativen Weg ein: import data from './data.json' with { type: 'json' }. Das Modul-System selbst laedt und parst die Datei, das Ergebnis steht als Standard-Export bereit, ganz ohne manuelles fetch, ohne .json()-Aufruf und ohne die zusaetzliche Promise-Ebene, die reines Konfigurationsladen unnoetig verkompliziert hat.
2. Syntax: import ... with { type: 'json' }
Die Syntax lehnt sich an bestehende Import-Statements an, ergaenzt um die with-Klausel am Ende. Statisch sieht das aus wie import config from './config.json' with { type: 'json' }, wonach config direkt das geparste JavaScript-Objekt enthaelt. Ohne das type-Attribut lehnt die Engine den Import mit einem Fehler ab, selbst wenn die Dateiendung eindeutig .json lautet.
Das Attribut ist bewusst redundant zur Dateiendung, weil sich die Engine nicht auf Dateiendungen verlassen darf: Server koennen JSON-Inhalte unter beliebigen Pfaden ohne .json-Endung ausliefern, und Content-Type-Header sind aus Sicherheitssicht nicht vertrauenswuerdig genug, um allein ueber die Modulart zu entscheiden. Die explizite Angabe im Quellcode ist der eigentliche Vertrauensanker.
import config from './config.json' with { type: 'json' };
console.log(config.apiBaseUrl);
// Ohne with-Klausel: SyntaxError / TypeError, je nach Engine
// import config from './config.json'; // wird abgelehnt
3. Dynamischer Import mit Attributen
Fuer Faelle, in denen der Pfad erst zur Laufzeit feststeht oder das JSON nur bedingt geladen werden soll, funktioniert dieselbe Idee mit dem dynamischen import(). Statt eines Top-Level-Statements wird ein zweites Argumentobjekt an import() uebergeben, dessen with-Eigenschaft wiederum das type-Attribut enthaelt. Das Resultat ist ein Promise, das zu einem Modul-Namespace-Objekt aufloest.
Der eigentliche Datenwert steckt dabei im .default-Property des aufgeloesten Moduls, analog zum Standard-Export bei statischen Imports. Das macht dynamische JSON-Importe zu einer echten Alternative zu fetch() fuer lokal gebuendelte Daten, mit dem Vorteil, dass Build-Tools den Import bereits zur Build-Zeit als Abhaengigkeit erkennen und mitbuendeln koennen.
async function loadLocale(code) {
const module = await import(`./locales/${code}.json`, {
with: { type: 'json' },
});
return module.default;
}
const de = await loadLocale('de');
4. Der Sicherheitsgedanke hinter dem Type-Attribut
Die Pflicht zum expliziten type-Attribut ist keine Formalitaet, sondern eine direkte Reaktion auf ein reales Angriffsszenario. Ohne diesen Zwang koennte ein Angreifer, der Inhalte einer scheinbar harmlosen JSON-Ressource kontrolliert, etwa ueber eine kompromittierte CDN-Antwort oder einen offenen Upload-Endpunkt, versuchen, dort ausfuehrbaren JavaScript-Code statt reinem JSON unterzubringen und ihn ueber einen normalen JS-Import zur Ausfuehrung zu bringen.
Mit dem type-Attribut deklariert der Entwickler explizit, welche Modulart er erwartet, und die Engine erzwingt einen entsprechenden MIME-Type-Check gegen den Server-Response-Header. Weicht der tatsaechliche Content-Type vom erwarteten Typ ab, schlaegt der Import fehl, statt die Datei stillschweigend als Skript zu interpretieren. Historisch hiess dieses Feature 'Import Assertions' mit dem Schluesselwort assert, wurde aber wegen ungewollter Fehler-Semantik zu 'Import Attributes' mit with umbenannt.
5. Vergleich: JSON- und CSS-Module-Attribute
JSON ist nicht der einzige Anwendungsfall fuer Import Attributes, dieselbe Syntax existiert konzeptionell auch fuer CSS-Module ueber type: 'css', wodurch ein Stylesheet als CSSStyleSheet-Objekt statt als Text importiert werden kann. Der Support fuer CSS-Module-Skripte liegt jedoch aktuell deutlich hinter dem fuer JSON-Module, insbesondere ausserhalb von Chromium-basierten Browsern.
Praktisch bedeutet das: JSON-Module ueber with { type: 'json' } lassen sich schon heute breit produktiv einsetzen, waehrend CSS-Module-Skripte eher ein Ausblick auf zukuenftige Bundler- und Framework-Integrationen sind. Wer beide Feature-Familien im Code nutzt, sollte den Support jeweils separat pruefen, statt von einer einheitlichen Verfuegbarkeit auszugehen.
// JSON-Modul, breit unterstuetzt
import theme from './theme.json' with { type: 'json' };
// CSS-Modul, experimentell / eingeschraenkter Support
import sheet from './styles.css' with { type: 'css' };
document.adoptedStyleSheets = [sheet];
6. Browser- und Node.js-Support
Chrome und Edge unterstuetzen statische und dynamische JSON-Import-Attribute seit Version 123 vollstaendig, Node.js zog mit Version 22 nach und liegt seither ebenfalls stabil vor. Bei Safari und Firefox ist der Support zum jetzigen Stand uneinheitlicher: Dynamische Importe mit type: 'json' funktionieren breiter als statische Top-Level-Importe, weshalb sich fuer maximale Kompatibilitaet aktuell der dynamische Weg empfiehlt.
Fuer sicheres Feature-Testen zur Laufzeit eignet sich ein try/catch um einen dynamischen Test-Import, da es keine synchrone Moeglichkeit gibt, die Unterstuetzung ohne tatsaechlichen Import-Versuch zu pruefen. In produktivem Code lohnt sich zusaetzlich ein Fallback auf fetch() plus JSON.parse() fuer Umgebungen, die Import Attributes noch nicht kennen.
async function supportsJsonImportAttributes() {
try {
await import('data:application/json,{}', { with: { type: 'json' } });
return true;
} catch {
return false;
}
}
7. Unterstuetzung in Bundlern und TypeScript
Vite und Webpack unterstuetzen den Import-Attribute-Syntax inzwischen in aktuellen Versionen nativ und loesen die with-Klausel bereits zur Build-Zeit auf, sodass das gebuendelte Ergebnis unabhaengig vom Ziel-Browser funktioniert. TypeScript benoetigt fuer die neue Syntax mindestens Version 5.3, zusammen mit einem passenden module-Target wie 'esnext' oder 'nodenext' in der tsconfig.json.
Wer aeltere Bundler-Versionen einsetzt, sollte vor dem Umstieg pruefen, ob die with-Klausel korrekt geparst wird, da ein reiner Syntaxfehler beim Parsen (nicht erst zur Laufzeit) den kompletten Build abbrechen kann. Ein kurzer isolierter Testimport in einer neuen Datei ist der schnellste Weg, das vor einem groesseren Umbau zu verifizieren.
// tsconfig.json (Ausschnitt)
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "Bundler"
}
}
8. Wann fetch(), wann Import Attributes?
Import Attributes eignen sich fuer JSON, das zur Build-Zeit bekannt ist und mit dem restlichen Code gebuendelt werden soll, etwa Konfigurationsdateien, statische Uebersetzungsdateien oder Testfixtures. Der Vorteil: Build-Tools erkennen die Abhaengigkeit, koennen sie in den Dependency-Graph aufnehmen und gegebenenfalls Tree-Shaking oder Caching-Strategien darauf anwenden, genau wie bei jedem anderen JS-Import.
fetch() bleibt dagegen die richtige Wahl fuer JSON, das erst zur Laufzeit von einem Server geladen wird, das sich zwischen Requests aendert oder das aus Nutzereingaben oder externen APIs stammt. Import Attributes sind kein Ersatz fuer Netzwerk-Requests, sondern eine Vereinfachung fuer den engen Fall lokal mitgelieferter, statischer JSON-Dateien.
// Statisch, zur Build-Zeit bekannt -> Import Attributes
import featureFlags from './feature-flags.json' with { type: 'json' };
// Dynamisch, laufzeitabhaengig -> fetch()
const response = await fetch('/api/user-preferences');
const preferences = await response.json();
9. Best Practices und Zusammenfassung
Import Attributes loesen ein konkretes Problem eleganter, als es fetch() plus JSON.parse() je konnte: statisches JSON wird zu einer normalen Modul-Abhaengigkeit, die vom Build-System verstanden, typgeprueft und mitverfolgt wird. Der Zwang zum expliziten type-Attribut ist dabei kein syntaktischer Ballast, sondern eine bewusste Sicherheitsmassnahme gegen MIME-Type-Verwechslungen.
Fuer produktiven Einsatz empfiehlt sich aktuell ein Blick auf die Zielumgebung: Bei modernem Bundler-Einsatz (Vite, Webpack, aktuelles TypeScript) ist die Syntax bereits gefahrlos nutzbar, bei direktem Browser-Einsatz ohne Build-Schritt lohnt sich vorerst eine Feature-Detection mit Fallback auf fetch(), bis Safari und Firefox beim statischen Import nachgezogen haben.
| Ansatz | Wann sinnvoll | Build-Zeit-Erkennung | Support-Stand |
|---|---|---|---|
| Import Attributes (statisch) | Bekanntes, mitgebuendeltes JSON | Ja | Chrome/Edge/Node stabil, Safari/Firefox teilweise |
| Import Attributes (dynamisch) | Bedingtes Laden von JSON-Modulen | Teilweise | Breiter unterstuetzt als statisch |
| fetch() + JSON.parse() | Laufzeit-/Server-Daten, externe APIs | Nein | Ueberall verfuegbar |
| CSS-Module (type: 'css') | Stylesheets als CSSStyleSheet importieren | Teilweise | Vor allem Chromium-Browser |
Mironsoft
Moderne Browser-APIs, Performance und wartbares JavaScript
JavaScript, das im echten Browser robust bleibt, nicht nur im Tutorial?
Wir prüfen bestehenden Frontend-Code auf veraltete Patterns, unnötige Bibliotheken und Performance-Fallen und ersetzen sie durch moderne, native Browser-APIs, die weniger Bundle-Gewicht und weniger Wartungslast bedeuten.
Code-Review
Veraltete Patterns, unnötige Dependencies und Memory Leaks systematisch aufspüren.
Performance-Optimierung
Bundle-Größe, Ladezeit und Runtime-Performance mit modernen APIs verbessern.
Modernisierung
Native Browser-APIs statt schwerer Bibliotheken gezielt einführen.
10. Zusammenfassung
Import Attributes: Das Wichtigste auf einen Blick
Syntax
import x from './d.json' with { type: 'json' } laedt und parst JSON direkt als Modul, ohne fetch() oder JSON.parse().
Sicherheitsgedanke
Das type-Attribut erzwingt einen MIME-Type-Check und verhindert, dass fremd kontrollierte Ressourcen als Skript statt als Daten interpretiert werden.
Support
Chrome, Edge und Node.js unterstuetzen statische und dynamische JSON-Importe stabil, Safari/Firefox aktuell eher beim dynamischen Weg.
Einsatzgrenze
Nur fuer zur Build-Zeit bekanntes, lokal mitgeliefertes JSON, fuer Laufzeitdaten bleibt fetch() die richtige Wahl.