Import Attributes: JSON-Module mit type: 'json' nativ laden
AI generated
JS
() =>
JavaScript · ES Modules · Import Attributes
Import Attributes: JSON-Module nativ laden
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.

13 Min. Lesezeit Import Attributes JSON-Module ES Modules

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.

11. FAQ: Import Attributes: Das Wichtigste auf einen Blick

1Was bedeutet with { type: 'json' } konkret?
Es ist eine verpflichtende Zusatzangabe beim Import, die der Engine mitteilt, dass die geladene Ressource als JSON geparst werden soll, statt als JavaScript ausgefuehrt zu werden.
2Warum reicht die .json-Dateiendung nicht als Hinweis?
Weil Server JSON-Inhalte unter beliebigen Pfaden ohne .json-Endung ausliefern koennen und Dateiendungen allein kein verlaesslicher Sicherheitsindikator sind, deshalb ist die explizite Angabe im Code Pflicht.
3Was war 'Import Assertions' und wie unterscheidet es sich?
Der Vorlaeufer nutzte das Schluesselwort assert statt with. Er wurde umbenannt, weil assert im Fehlerfall den Import komplett verwerfen sollte, was fuer manche Anwendungsfaelle zu strikt war.
4Funktioniert das auch mit dynamischem import()?
Ja, das zweite Argument von import() nimmt ein Objekt mit einer with-Eigenschaft entgegen, die wiederum type enthaelt, das Ergebnis ist ein Promise auf ein Modul-Namespace-Objekt.
5Wo liegt der eigentliche Datenwert bei dynamischem Import?
Im .default-Property des aufgeloesten Moduls, also const data = (await import(...)).default, analog zum Standard-Export bei statischen Imports.
6Unterstuetzen alle Browser Import Attributes bereits?
Chrome, Edge und Node.js seit 2024 stabil, Safari und Firefox unterstuetzen den dynamischen Weg breiter als den statischen Top-Level-Import, ein direkter Support-Check lohnt sich vor dem produktiven Einsatz.
7Brauche ich einen Polyfill fuer aeltere Umgebungen?
Nein, ein Polyfill fuer Modul-Lade-Syntax ist praktisch nicht moeglich, stattdessen empfiehlt sich Feature-Detection per Testimport mit Fallback auf fetch() plus JSON.parse().
8Erkennen Bundler wie Vite oder Webpack die Syntax?
Aktuelle Versionen beider Tools loesen die with-Klausel bereits zur Build-Zeit auf, sodass das Ergebnis unabhaengig vom Ziel-Browser funktioniert, aeltere Versionen sollten vorab getestet werden.
9Kann ich damit auch remote gehostetes JSON laden?
Technisch ja bei absoluten URLs mit CORS-Freigabe, praktisch ist Import Attributes aber vor allem fuer lokal mitgebuendeltes, zur Build-Zeit bekanntes JSON gedacht, fuer Server-Daten bleibt fetch() sinnvoller.
10Gibt es das Feature auch fuer CSS?
Konzeptionell ja, ueber with { type: 'css' } fuer sogenannte CSS-Module-Skripte, der Support dafuer liegt aber aktuell noch deutlich hinter dem fuer JSON-Module.