You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by jl...@apache.org on 2026/10/16 20:15:33 UTC
(superset) 01/01: fix(deck.gl): set maplibre-gl 6's worker URL so vector basemaps load
This is an automated email from the ASF dual-hosted git repository.
sadpandajoe pushed a commit to branch ultraset-deckgl-maplibre-worker-url-unset
in repository https://gitbox.apache.org/repos/asf/superset.git
commit 2fb69bebb0d3c1e6d2eccf6435766d8bd9a7a4c0
Author: Joe Li <47...@users.noreply.github.com>
AuthorDate: Fri Oct 16 20:15:19 2026 +0000
fix(deck.gl): set maplibre-gl 6's worker URL so vector basemaps load
maplibre-gl 6 derives its worker URL from `import.meta.url`, which webpack
rewrites to a build-time file:// path, so the worker URL resolves to "" and
no vector tiles are ever requested. #44042 fixed this for
plugin-chart-point-cluster-map only; preset-chart-deckgl never called
setWorkerUrl(), leaving Carto/OpenFreeMap basemaps blank on deck.gl charts.
Point maplibre-gl at the worker asset CopyPlugin already emits, before the
first MapLibre map mounts, mirroring the point-cluster-map fix.
Fixes #45373
Co-Authored-By: Claude Opus 5.5 <no...@anthropic.com>
---
.../src/CategoricalDeckGLContainer.test.tsx | 6 +++++
.../src/DeckGLContainer.test.tsx | 28 ++++++++++++++++++++++
.../preset-chart-deckgl/src/DeckGLContainer.tsx | 11 +++++++++
.../preset-chart-deckgl/src/layers/Arc/Arc.test.ts | 6 +++++
.../plugins/preset-chart-deckgl/types/global.d.ts | 23 ++++++++++++++++++
5 files changed, 74 insertions(+)
diff --git a/superset-frontend/plugins/preset-chart-deckgl/src/CategoricalDeckGLContainer.test.tsx b/superset-frontend/plugins/preset-chart-deckgl/src/CategoricalDeckGLContainer.test.tsx
index 199f8a9be5a..f27c9106ce7 100644
--- a/superset-frontend/plugins/preset-chart-deckgl/src/CategoricalDeckGLContainer.test.tsx
+++ b/superset-frontend/plugins/preset-chart-deckgl/src/CategoricalDeckGLContainer.test.tsx
@@ -21,6 +21,12 @@ import { getCategories } from './CategoricalDeckGLContainer';
import { addColorToFeatures } from './utils/addColor';
import { COLOR_SCHEME_TYPES } from './utilities/utils';
+// maplibre-gl 6 is ESM-only, so jest can't resolve it; DeckGLContainer.tsx
+// calls setWorkerUrl() on it at import time.
+jest.mock('maplibre-gl', () => ({ setWorkerUrl: jest.fn() }), {
+ virtual: true,
+});
+
// Record every (label, sliceId) pair the categorical color scale is asked to
// resolve, so we can assert the legend and point-color paths key the scale on
// the same slice id.
diff --git a/superset-frontend/plugins/preset-chart-deckgl/src/DeckGLContainer.test.tsx b/superset-frontend/plugins/preset-chart-deckgl/src/DeckGLContainer.test.tsx
index ddc66e81645..ee6951f465e 100644
--- a/superset-frontend/plugins/preset-chart-deckgl/src/DeckGLContainer.test.tsx
+++ b/superset-frontend/plugins/preset-chart-deckgl/src/DeckGLContainer.test.tsx
@@ -27,8 +27,21 @@ import {
OSM_TILE_STYLE_URL,
} from '@superset-ui/core/utils/mapStyles';
import mapboxgl from 'mapbox-gl';
+import * as maplibregl from 'maplibre-gl';
import { DeckGLContainer, DeckGLContainerHandle } from './DeckGLContainer';
+// maplibre-gl 6 is an ESM-only package with no "require"/"default" export
+// condition, so jest's (CJS-based) resolver can't locate the real module to
+// mock over it by name; { virtual: true } skips that resolution step. The
+// jest.fn() is created inline because DeckGLContainer.tsx calls
+// maplibregl.setWorkerUrl() at import time, before any hoisted `const`
+// declared here would be initialized.
+jest.mock(
+ 'maplibre-gl',
+ () => ({ __esModule: true, setWorkerUrl: jest.fn() }),
+ { virtual: true },
+);
+
jest.mock('react-map-gl/maplibre', () => ({
Map: ({
children,
@@ -130,6 +143,12 @@ const renderContainer = (
</ThemeProvider>,
);
+// Snapshot the import-time calls before afterEach's jest.clearAllMocks()
+// wipes them.
+const setWorkerUrlCallsAtImport = [
+ ...jest.mocked(maplibregl.setWorkerUrl).mock.calls,
+];
+
afterEach(() => {
jest.useRealTimers();
jest.clearAllMocks();
@@ -139,6 +158,15 @@ afterEach(() => {
});
});
+test('DeckGLContainer points maplibre-gl at the CopyPlugin-emitted worker asset before any map can mount', () => {
+ // maplibre-gl 6 derives its worker URL from `import.meta.url`, which
+ // webpack rewrites to a build-time path that fails maplibre's `^https?:`
+ // check, so vector tiles never load unless setWorkerUrl() is called first.
+ expect(setWorkerUrlCallsAtImport).toEqual([
+ ['/static/assets/maplibre-gl-worker.mjs'],
+ ]);
+});
+
test('DeckGLContainer converts OSM raster tile templates into MapLibre style objects', () => {
renderContainer({ mapProvider: 'maplibre', mapStyle: OSM_TILE_STYLE_URL });
diff --git a/superset-frontend/plugins/preset-chart-deckgl/src/DeckGLContainer.tsx b/superset-frontend/plugins/preset-chart-deckgl/src/DeckGLContainer.tsx
index e49d547ea77..0bfcc85f1eb 100644
--- a/superset-frontend/plugins/preset-chart-deckgl/src/DeckGLContainer.tsx
+++ b/superset-frontend/plugins/preset-chart-deckgl/src/DeckGLContainer.tsx
@@ -31,6 +31,7 @@ import { isEqual } from 'lodash-es';
import { Map as MapLibreMap } from 'react-map-gl/maplibre';
import { Map as MapboxMap } from 'react-map-gl/mapbox';
import mapboxgl from 'mapbox-gl';
+import * as maplibregl from 'maplibre-gl';
import type { Layer } from '@deck.gl/core';
import { JsonObject, JsonValue, usePrevious } from '@superset-ui/core';
import {
@@ -46,6 +47,16 @@ import Tooltip, { TooltipProps } from './components/Tooltip';
import 'maplibre-gl/dist/maplibre-gl.css';
import { Viewport } from './utils/fitViewport';
+// maplibre-gl 6's ESM-only build derives its worker URL from
+// `import.meta.url`, which our (non-ESM-output) webpack bundle rewrites to
+// a build-time path that doesn't match maplibre's `^https?:` check, so
+// `WORKER_URL` silently resolves to `''` and vector tiles never load. Point
+// it at the copy CopyPlugin emits alongside the rest of our static assets
+// (see webpack.config.js), using the runtime-configurable public path so
+// this also works behind an APPLICATION_ROOT prefix. This must run before
+// the first MapLibre map mounts.
+maplibregl.setWorkerUrl(`${__webpack_public_path__}maplibre-gl-worker.mjs`);
+
const TICK = 250; // milliseconds
const DEFAULT_MAP_STYLE =
diff --git a/superset-frontend/plugins/preset-chart-deckgl/src/layers/Arc/Arc.test.ts b/superset-frontend/plugins/preset-chart-deckgl/src/layers/Arc/Arc.test.ts
index ca369d48bce..8a4331aaa81 100644
--- a/superset-frontend/plugins/preset-chart-deckgl/src/layers/Arc/Arc.test.ts
+++ b/superset-frontend/plugins/preset-chart-deckgl/src/layers/Arc/Arc.test.ts
@@ -19,6 +19,12 @@
import { COLOR_SCHEME_TYPES } from '../../utilities/utils';
import { getLayer } from './Arc';
+// maplibre-gl 6 is ESM-only, so jest can't resolve it; DeckGLContainer.tsx
+// (pulled in via factory.tsx) calls setWorkerUrl() on it at import time.
+jest.mock('maplibre-gl', () => ({ setWorkerUrl: jest.fn() }), {
+ virtual: true,
+});
+
const baseArgs = {
payload: { data: { features: [] } },
setTooltip: () => {},
diff --git a/superset-frontend/plugins/preset-chart-deckgl/types/global.d.ts b/superset-frontend/plugins/preset-chart-deckgl/types/global.d.ts
new file mode 100644
index 00000000000..cf9bb08e6d4
--- /dev/null
+++ b/superset-frontend/plugins/preset-chart-deckgl/types/global.d.ts
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// webpack's runtime-configurable public path, mirroring src/globals.d.ts.
+// Used to point maplibre-gl at its CopyPlugin-emitted worker asset (see
+// DeckGLContainer.tsx) with the correct app-root / reverse-proxy prefix applied.
+declare var __webpack_public_path__: string;