Skip to content

Commit 6c4a8e7

Browse files
Fix dynamic imports in UMD
GitOrigin-RevId: dacaeec1fe093b17fed150df7d80dcf11f51f70d
1 parent 4e476ec commit 6c4a8e7

24 files changed

Lines changed: 159 additions & 111 deletions

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ jobs:
5151
- run: npm run test-build
5252
- run: xvfb-run -a npm run test-esm
5353
- run: xvfb-run -a npm run test-csp
54-
- run: npm run build -w vite-build-test
55-
- run: npm run build -w webpack-build-test
54+
- run: xvfb-run -a npm test -w vite-build-test
55+
- run: xvfb-run -a npm test -w webpack-build-test
5656
- run: npm run test -w typescript-build-test
5757
- run: npm run build -w @mapbox/mapbox-gl-pmtiles-provider
5858
- run: npm run size

eslint.config.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,9 @@ const IGNORED_PATHS = [
6666
'./test/integration/tiles/**/*',
6767
'./test/integration/tilesets/**/*',
6868
'./test/integration/lib/operation-handlers.js',
69-
'./test/build/vite/**/*',
70-
'./test/build/webpack/**/*',
69+
'./test/build/{vite,webpack}/**/*',
70+
'./test/build/scenarios/**/*',
71+
'./test/build/browser-check.cjs',
7172
'./test/build/typings/**/*',
7273
'./test/build/style-spec.test.js',
7374
];

package-lock.json

Lines changed: 0 additions & 52 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rollup.config.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ function buildType(build: string, minified: string) {
2727
const outputFile = buildType(BUILD, MINIFY);
2828

2929
const bundlePreludeSource = fs.readFileSync(fileURLToPath(new URL('./rollup/bundle_prelude.js', import.meta.url)), 'utf8');
30-
const bundlePrelude = production ? transformSync(bundlePreludeSource, {target: browserslistToEsbuild(), minify: true}).code : bundlePreludeSource;
30+
// Not minified: it would strip the import() ignore comments that stop downstream bundlers rewriting the worker's import().
31+
const bundlePrelude = production ? transformSync(bundlePreludeSource, {target: browserslistToEsbuild()}).code : bundlePreludeSource;
3132

3233
function preserveDynamicImport(): Plugin {
3334
return {
@@ -38,7 +39,7 @@ function preserveDynamicImport(): Plugin {
3839
return false;
3940
},
4041
renderDynamicImport() {
41-
return {left: 'import(', right: ')'};
42+
return {left: 'self.__mapboxImport(', right: ')'};
4243
}
4344
};
4445
}

rollup/bundle_prelude.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020

2121
let shared, worker, mapboxgl;
2222

23+
// Use `self` to avoid mangling by downstream minifier
24+
if (typeof self !== 'undefined') self.__mapboxImport = (u) => import(/* webpackIgnore: true */ /* @vite-ignore */ u);
25+
2326
function define(_, chunk) {
2427
if (!shared) {
2528
shared = chunk;
@@ -33,6 +36,7 @@ function define(_, chunk) {
3336
const workerBundleString =
3437
"self.onerror = function() { console.error('An error occurred while parsing the WebWorker bundle. This is most likely due to improper transpilation by Babel; please see https://docs.mapbox.com/mapbox-gl-js/guides/install/#transpiling'); }; " +
3538
"var sharedChunk = {}; " +
39+
"self.__mapboxImport = (u) => import(u); " +
3640
"(" + shared + ")(undefined, sharedChunk); " +
3741
"(" + worker + ")(undefined, sharedChunk); " +
3842
"self.onerror = null;";

test/build/browser-check.cjs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
const test = require('node:test');
2+
const assert = require('node:assert/strict');
3+
const http = require('node:http');
4+
const path = require('node:path');
5+
const serveStatic = require('serve-static');
6+
const {chromium} = require('playwright');
7+
8+
const TILES = path.join(__dirname, '..', 'integration', 'tiles');
9+
const PROVIDER_DIST = path.join(__dirname, '..', '..', 'plugins', 'mapbox-gl-pmtiles-provider', 'dist');
10+
11+
function serve(root) {
12+
const middlewares = [serveStatic(root), serveStatic(PROVIDER_DIST), serveStatic(TILES)];
13+
return http.createServer((req, res) => {
14+
const notFound = () => { res.writeHead(404); res.end(); };
15+
const middleware = middlewares.reduceRight((next, serve) => () => serve(req, res, next), notFound);
16+
middleware();
17+
});
18+
}
19+
20+
async function expectNoErrors(browser, port, file) {
21+
const tab = await browser.newPage();
22+
try {
23+
const errors = [];
24+
tab.on('pageerror', (e) => errors.push(e.message));
25+
tab.on('console', (m) => { if (m.type() === 'error') errors.push(m.text()); });
26+
await tab.goto(`http://localhost:${port}/${file}`);
27+
const gotTiles = await tab.waitForResponse((r) => r.url().endsWith('.pmtiles'), {timeout: 8000}).then(() => true, () => false);
28+
// A broken worker import surfaces just after the .pmtiles fetch; let it flush.
29+
await tab.waitForTimeout(100);
30+
assert.deepEqual(errors, []);
31+
assert.ok(gotTiles, 'page produced no .pmtiles request within 8s');
32+
} finally {
33+
try { await tab.close(); } catch { /* a crashed tab must not mask the assertion */ }
34+
}
35+
}
36+
37+
function testPages({label, root, files}) {
38+
let browser, server, port;
39+
test.before(async () => {
40+
server = serve(root);
41+
await new Promise((resolve) => server.listen(0, resolve));
42+
({port} = server.address());
43+
try {
44+
// CI installs full chromium via `playwright install --no-shell`; match vitest.config.base.ts.
45+
browser = await chromium.launch({channel: process.env.CI === 'true' ? 'chromium' : 'chrome'});
46+
} catch (e) {
47+
throw new Error(`Chromium failed to launch (is Playwright installed? in CI, run under xvfb): ${e.message}`);
48+
}
49+
});
50+
test.after(async () => {
51+
if (browser) await browser.close();
52+
if (server) await new Promise((resolve) => server.close(resolve));
53+
});
54+
for (const file of files) {
55+
const name = file.replace('.html', '');
56+
test(`${label}-${name} build loads a PMTiles source without errors`, {timeout: 15000}, () => expectNoErrors(browser, port, file));
57+
}
58+
}
59+
60+
module.exports = {testPages};
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import * as mapboxgl from 'mapbox-gl/esm';
2+
3+
mapboxgl.addTileProvider('pmtiles', `${location.origin}/mapbox-gl-pmtiles-provider.js`);
4+
5+
const map = new mapboxgl.Map({
6+
container: 'map',
7+
testMode: true,
8+
style: {version: 8, sources: {}, layers: []}
9+
});
10+
11+
map.on('load', () => {
12+
map.addSource('pmtiles', {type: 'vector', url: `${location.origin}/vector.pmtiles`});
13+
});
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import mapboxgl from 'mapbox-gl';
2+
3+
mapboxgl.addTileProvider('pmtiles', `${location.origin}/mapbox-gl-pmtiles-provider.js`);
4+
5+
const map = new mapboxgl.Map({
6+
container: 'map',
7+
testMode: true,
8+
style: {version: 8, sources: {}, layers: []}
9+
});
10+
11+
map.on('load', () => {
12+
map.addSource('pmtiles', {type: 'vector', url: `${location.origin}/vector.pmtiles`});
13+
});

test/build/vite/esm.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
<html lang="en">
33
<head>
44
<meta charset="UTF-8" />
5+
<link rel="icon" href="data:," />
56
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
67
<title>Vite + Mapbox GL JS (ESM)</title>
78
<style>
@@ -11,6 +12,6 @@
1112
</head>
1213
<body>
1314
<div id="map"></div>
14-
<script type="module" src="/esm.js"></script>
15+
<script type="module" src="../scenarios/pmtiles-esm.js"></script>
1516
</body>
1617
</html>

test/build/vite/esm.js

Lines changed: 0 additions & 9 deletions
This file was deleted.

0 commit comments

Comments
 (0)