Anleitung

react-map-gl mit MapLibre

react-map-gl verpackt MapLibre GL JS in React-Komponenten: die Karte, Marker, Popups, Controls, Quellen und Layer. Eine Kartenkomponente mit einer Stil-URL, einem Marker und 3D-Gelände, die Einrichtung, die MapLibre 6 mit Vite und Next.js braucht, und wohin der Schlüssel gehört. Getestet mit react-map-gl 8.1.3, MapLibre GL JS 6.13.0, React 19.3 und Vite 8.

npm install react-map-gl maplibre-gl
import Map from "react-map-gl/maplibre";
import "maplibre-gl/dist/maplibre-gl.css";

export default function MapView() {
  return (
    <Map
      initialViewState={{ longitude: 8.54, latitude: 47.37, zoom: 12 }}
      style={{ width: "100%", height: 480 }}
      mapStyle="https://api.overpass.ch/v1/IHR_SCHLÜSSEL/maps/styles/light.json"
    />
  );
}
Mit Vite ergänzen Sie die Zeilen mit setWorkerUrl unten, sonst bleibt die Karte leer.

Eine Karte mit Marker, Popup und 3D-Gelände

Diese Komponente lief in einem Build mit Vite. Sie zeigt den Stil Outdoor geneigt über dem Matterhorn, mit Gelände, einem Marker und seinem Popup:

import { useState } from "react";
import Map, { NavigationControl, Marker, Popup, Source } from "react-map-gl/maplibre";
import { setWorkerUrl } from "maplibre-gl";
import workerUrl from "maplibre-gl/dist/maplibre-gl-worker.mjs?worker&url";
import "maplibre-gl/dist/maplibre-gl.css";

setWorkerUrl(workerUrl); // MapLibre 6 mit Vite: einmal, vor der ersten Karte

const KEY = import.meta.env.VITE_OVERPASS_KEY;
const MAPS = `https://api.overpass.ch/v1/${KEY}/maps`;

export default function MapView() {
  const [open, setOpen] = useState(true);
  return (
    <Map
      initialViewState={{ longitude: 7.6586, latitude: 45.9763, zoom: 12, pitch: 60, bearing: -100 }}
      style={{ width: "100%", height: 480 }}
      mapStyle={`${MAPS}/styles/outdoor.json?lang=de`}
      maxPitch={85}
      terrain={{ source: "terrain-3d", exaggeration: 1.2 }}
    >
      <Source id="terrain-3d" type="raster-dem" url={`${MAPS}/terrain.json`} />
      <NavigationControl visualizePitch />
      <Marker longitude={7.7491} latitude={46.0207} color="#d0312d" onClick={() => setOpen(true)} />
      {open && (
        <Popup longitude={7.7491} latitude={46.0207} anchor="bottom" offset={36} onClose={() => setOpen(false)}>
          Zermatt
        </Popup>
      )}
    </Map>
  );
}
  • Importieren Sie aus react-map-gl/maplibre. Es lädt maplibre-gl selbst und funktioniert mit den ES-Modulen von MapLibre 6. Das Paket @vis.gl/react-maplibre hat dieselben Komponenten ohne den Teil für Mapbox.
  • mapStyle nimmt die Stil-URL. Ändern Sie sie, wechselt der Stil, zum Beispiel von light zu dark mit dem Design Ihrer App.
  • terrain verweist mit ihrer ID auf eine Quelle raster-dem. Das Kind Source fügt diese Quelle hinzu. Für 3D ohne Code hängen Sie terrain=1 an die Stil-URL; dieser Stil enthält schon eine Quelle terrain-3d.
  • Für eigene Daten verwenden Sie <Source type="geojson" data={…}> mit einem Kind <Layer>.

Die Worker-URL

MapLibre liest Kacheln in einem Web Worker. Mit einem Bundler findet MapLibre 6 die Worker-Datei nicht selbst: Die Karte bleibt leer, und die Konsole zeigt «Worker failed to load. Check that the worker URL is correct.» Das haben wir gesehen, bevor wir den Aufruf ergänzt haben.

  • Vite (getestet): import workerUrl from "maplibre-gl/dist/maplibre-gl-worker.mjs?worker&url" und setWorkerUrl(workerUrl), wie oben.
  • Next.js 15 und neuer, mit Turbopack oder webpack: Die Dokumentation von MapLibre nennt setWorkerUrl(new URL("maplibre-gl/dist/maplibre-gl-worker.mjs", import.meta.url).toString()) in einer Datei, die mit "use client" beginnt. Für Next.js 14 sagt sie, die Worker-Datei nach public/ zu kopieren und diesen Pfad zu übergeben.

Die Karte braucht den Browser; setzen Sie sie in Next.js also in eine Client-Komponente. Mit Server-Rendering wird der Container auf dem Server gerendert, und die Karte startet im Browser.

Der Schlüssel

Die Stil-URL enthält Ihren Schlüssel, und der Browser sieht ihn. Legen Sie ihn in eine Umgebungsvariable, damit er nicht in Ihrem Repository landet:

# .env.local (Vite: Präfix VITE_; Next.js: Präfix NEXT_PUBLIC_)
VITE_OVERPASS_KEY=IHR_SCHLÜSSEL

Erstellen Sie dann in Ihrem Dashboard einen Schlüssel vom Typ «Nur Karten», mit Ihrer Website und localhost:5173 (Vite) oder localhost:3000 (Next.js) als erlaubten Referern. Ein solcher Schlüssel funktioniert nur für Kacheln und Stile, und andere Websites werden abgewiesen.

Kacheln

react-map-gl ändert nichts an der Zählung: Jede Vektor-, Gelände- oder Höhenlinienkachel, die MapLibre lädt, zählt als eine Kartenkachel, und Stile und Schriften sind kostenlos. In 3D lädt die Karte Kacheln bis zum Horizont; die Anleitung zu 3D-Gelände hat Zahlen. Jedes Konto enthält 100'000 Kacheln im Monat.