Skip to content

maplibre-gl v6 blocked: plugin ecosystem still ships v5-era builds #1489

Description

@giswqs

maplibre-gl v6 cannot land until the plugin ecosystem ships v6-compatible builds. Tracking what has to happen first, so the next Dependabot bump (#1482) is not re-attempted blind.

Why it is blocked

MapLibre v6 is an ESM-only distribution with no default export and no CJS build (the UMD and maplibre-gl-csp bundles are gone). See the v5 → v6 migration guide.

Three separate breakages result, and only the third is ours to fix:

1. Third-party packages ship dist compiled against v5's default export

import maplibregl from "maplibre-gl" is a hard bundling error against v6 ("default" is not exported by maplibre-gl.mjs). These 11 installed packages still do it in their published dist/:

opengeos-owned (9) — need a namespace-import migration + rebuild + release:

  • maplibre-gl-3d-tiles
  • maplibre-gl-components
  • maplibre-gl-duckdb
  • maplibre-gl-geo-editor
  • maplibre-gl-geoagent
  • maplibre-gl-overture-maps
  • maplibre-gl-raster
  • maplibre-gl-streetview
  • maplibre-gl-swipe

external (2) — we can only wait or shim:

  • @esri/maplibre-arcgis
  • @geoman-io/maplibre-geoman-free

Note maplibre-gl-raster uses the mixed form import maplibregl, { Popup } from "maplibre-gl", so a scan that only looks for the bare default import will miss it.

Re-check with:

grep -rlE 'import +[A-Za-z_$][A-Za-z0-9_$]* *(,[^;]*)? *from *["'"'"']maplibre-gl["'"'"']|require\( *["'"'"']maplibre-gl["'"'"'] *\)' \
  --include='*.js' --include='*.mjs' --include='*.cjs' \
  node_modules/maplibre-gl-* node_modules/@esri/maplibre-arcgis node_modules/@geoman-io/*

2. v6 dropped CJS, which breaks the Node test suite

Those packages are dual-published, and their .cjs entries require("maplibre-gl"). v6's exports map has only types and import conditions, so CJS resolution fails outright:

Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: No "exports" main defined in node_modules/maplibre-gl/package.json

npm run test:frontend fails 29 tests on this. A Vite-level shim cannot help — node --test does not go through Vite.

3. GeoLibre patches the MapLibre namespace (ours to fix)

packages/map/src/globe-popup-occlusion.ts installs globe-occlusion behavior by assigning over the namespace:

api.Popup = GeoLibrePopup;   // map-controller.ts calls installGlobePopupOcclusion(maplibregl)

Under v5's mutable CJS/UMD default export this worked. A v6 ESM namespace object is getter-only, so it throws at boot:

TypeError: Cannot set property Popup of #<Object> which has only a getter

The app never mounts the map canvas — 22 of 23 e2e tests fail. This needs a different mechanism (the patch exists so third-party plugins constructing new maplibregl.Popup() also get occlusion, so simply exporting a GeoLibrePopup for our own call sites is a behavior change worth deciding on deliberately).

What is already done

A local wip branch carries the GeoLibre-side migration, verified with tsc -b clean, eslint 0 errors, and a successful vite build:

  • Dedupe to a single copy. The Dependabot lockfile resolved both 5.24.0 (hoisted, to satisfy @maplibre/maplibre-gl-directions' ^5.0.0 peer — there is no v6-compatible release of it) and 6.0.0 (nested in the three workspaces that declare it), so Map was a different nominal type across package boundaries. That is what the original CI errors (Argument of type 'SwipeControl' is not assignable to parameter of type 'IControl') actually were — not an API change. Fixed with a root overrides entry.
  • 33 files migrated to import * as maplibregl from "maplibre-gl".
  • v6's tightened typing: set/getPaintProperty and set/getLayoutProperty are now generic over keyof AllPaintProperties / keyof AllLayoutProperties, and Map#on/off's catch-all overload narrowed from type: string to type: keyof MapEventType (which breaks binding third-party events such as Geoman's gm:*). Added packages/map/src/dynamic-style-property.ts so the unavoidable casts for runtime-computed property names live in one documented place.

Suggested order

  1. Migrate + release the 9 opengeos packages (namespace imports, rebuild, verify the .cjs entry no longer requires maplibre-gl).
  2. Rework globe-popup-occlusion.ts off namespace patching.
  3. Wait on / track @esri/maplibre-arcgis and @geoman-io/maplibre-geoman-free. @maplibre/maplibre-gl-directions also still pins maplibre-gl@^5.0.0 as a peer.
  4. Re-run the bump and re-check the frontend + e2e suites, not just the build — the build passes with a shim while the app is completely broken at runtime, so a green build alone proves nothing here.

Until then, maplibre-gl should stay on 5.x and Dependabot bumps to v6 should be closed with a pointer to this issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestupstream issueAn issue caused by an upstream package or libarry

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions