mapbox-gl-js icon indicating copy to clipboard operation
mapbox-gl-js copied to clipboard

Provide a ESM module build

Open pdesjardins90 opened this issue 6 years ago • 29 comments

I'm trying to use the library for the first time and the quickstart tutorial example for basic installation doesn't work as expected.

Importing the library like so:

import mapboxgl from 'mapbox-gl'

Throws the error:

Uncaught SyntaxError: The requested module 'node_modules/mapbox-gl/dist/mapbox-gl.js' does not provide an export named 'default'

mapbox-gl-js version: 1.2.1

browser: Chrome

Steps to Trigger Behavior

  1. yarn add mapbox-gl
  2. In a module: import mapboxgl from 'mapbox-gl'
  3. Just open the page with chrome

Link to Demonstration

Can't provide a JSBin since it needs to be installed as an npm package. I basically just followed your quickstart documentation here with the module bundler option

Expected Behavior

When loading the page, there should be no error in the console and the library could be used normally as stated in the docs.

Actual Behavior

When loading the page, I get the error described above.

pdesjardins90 avatar Aug 22 '19 15:08 pdesjardins90

@pdesjardins90 can you set up a sample repo or a gist reproducing this? Are you using any bundlers like Webpack / Parcel for the page?

mourner avatar Aug 22 '19 16:08 mourner

I've setup a sample repo ~here~

I'm using es-dev-server to serve the index at localhost:8080 and convert bare module specifiers to relative path specifiers (that the browser can understand)

I've tried writing the import as a relative path in case it had something to do with the import path rewrite but I still got the error

pdesjardins90 avatar Aug 22 '19 19:08 pdesjardins90

@pdesjardins90 what does it say if you do import * as mapboxgl from 'mapbox-gl'?

mourner avatar Aug 22 '19 19:08 mourner

It's then an empty symbol, if I try to do:

mapboxgl.accessToken = 'some-token'

It will refuse to do so because it will consider it a new property assignment into a non-extensible object

pdesjardins90 avatar Aug 22 '19 19:08 pdesjardins90

I think the issue here is that "Module bundler" in the docs refers to importing mapbox-gl in JS files that get bundled afterwards (e.g. with Webpack, Rollup, Parcel), not to importing the mapbox-gl build as a module in the browser directly — it's a UMD build, not a module one.

mourner avatar Aug 22 '19 20:08 mourner

Is there any hope you'll offer a way to use native ES module? All the bundlers you mentioned support them

pdesjardins90 avatar Aug 22 '19 20:08 pdesjardins90

All the bundlers also support UMD. Using ES modules in browsers directly is still rare, but we definitely want to explore that at some point. Related: #6391

mourner avatar Aug 23 '19 12:08 mourner

I agree that using ES modules directly in the browser is still rare, I also understand that UMD builds are supported by bundlers and that the amount of work/gain from such a refactor might not be tempting at all for the moment.

I read around a bit and it seems that the future-proof way of doing things for a library would be to expose native ES modules only and let users decide how they want to bundle and transpile it (if they want to) in their app.

What's your general opinion on that as a library maintainer? Would it work for mapbox specifically?

pdesjardins90 avatar Aug 23 '19 13:08 pdesjardins90

Just ran into the same issue @pdesjardins90.

I expect that all node modules will eventually adopt esm and leave it up to applications to determine packaging. As a short-term workaround, I cloned mapbox-gl-gs and changed its rollup format to "esm." The resulting (vendored) JS loads successfully into es-dev-server.

hunterloftis avatar Sep 09 '19 03:09 hunterloftis

I use this sort of rollup fragment for all my runtime dependencies that have not supplied an es6 module:

    {
        input: 'node_modules/mapbox-gl/dist/mapbox-gl-unminified.js',
        output: {
            file: 'dist/mapbox-gl.esm.js',
            format: 'esm',
        },
        plugins: [commonjs()],
    },

I just tried this and it seems to work .. it least imports without error:

            import mapbox from '../dist/mapbox-gl.esm.js'

Would mapbox mind adding that to their workflow? Tossing in terser solves the minified version:

    {
        input: 'node_modules/mapbox-gl/dist/mapbox-gl-unminified.js',
        output: {
            file: 'dist/mapbox-gl.esm.min.js',
            format: 'esm',
        },
        plugins: [terser(), commonjs()],
    },

Results:

-rw-r--r--@  1 owen  staff   1.5M May 16 16:35 mapbox-gl.esm.js
-rw-r--r--@  1 owen  staff   744K May 16 16:35 mapbox-gl.esm.min.js

backspaces avatar May 16 '20 22:05 backspaces

To be complete, here's what you would need.

First, a config file, rollup.mapbox.js:

import commonjs from 'rollup-plugin-commonjs'
import { terser } from 'rollup-plugin-terser'

export default [
    {
        input: 'node_modules/mapbox-gl/dist/mapbox-gl-unminified.js',
        output: {
            file: 'dist/mapbox-gl.esm.js',
            format: 'esm',
        },
        plugins: [commonjs()],
    },
    {
        input: 'node_modules/mapbox-gl/dist/mapbox-gl-unminified.js',
        output: {
            file: 'dist/mapbox-gl.esm.min.js',
            format: 'esm',
        },
        plugins: [terser(), commonjs()],
    },
]

Then run it, possibly in a package.json run script:

rollup -c rollup.mapbox.js

Naturally you'd have to change a few paths, but this is all that's needed! YaY!

backspaces avatar May 16 '20 23:05 backspaces

Sorry to be noisy, but I completed my study of mapboxgl, both code and css, as modules.

I took the above and ran it in a demo showing the USA counties which I originally imported mapboxgl via <script> tags; now converted to the rollup->es6 above. Works.

I also made a module installing the css. This may seem silly but our code base avoids having the .html manage dependencies. We once found over 20% of them no longer used!

Everything works fine.

backspaces avatar May 17 '20 22:05 backspaces

Would https://github.com/mapbox/mapbox-gl-js/issues/8676#issuecomment-529287673 be accepted as a PR?

I found that StencilJS isn't able to successfully parse mapbox.Map as a type due to the ESM problem described above.

ericclemmons avatar Jul 23 '20 03:07 ericclemmons

Please provide at least the ES module optionally.

comatory avatar Feb 15 '21 08:02 comatory

Using skypack works, they perform module transforms for you: import mapboxgl from 'https://cdn.skypack.dev/mapbox-gl' It's worth following snowpack/skypack, they are very creative and perform the esm conversion locally for you.

On Mon, Feb 15, 2021 at 1:49 AM Ondrej Synacek [email protected] wrote:

Please provide at least the ES module optionally.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/mapbox/mapbox-gl-js/issues/8676#issuecomment-779062764, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAA6LTUN2GM6PEQ66524T6DS7DNYDANCNFSM4IOWGZTQ .

backspaces avatar Feb 15 '21 16:02 backspaces

On Mon Feb 15, 2021 at 5:33 PM CET, Owen Densmore wrote:

Using skypack works, they perform module transforms for you: import mapboxgl from 'https://cdn.skypack.dev/mapbox-gl' It's worth following snowpack/skypack, they are very creative and perform the esm conversion locally for you.

Very cool, did not know about this. Works really well. I wonder if there's a way to include styles via some build that would include CSS-in-JS, it'd be neat to just do that one import and not adding style tag to <head>.[1]

I'm using ES modules for quick experimentations, not production apps so it's really convenient to circumvent build tools and just use it in browser directly.

[1] I'm aware of this not being the best for performance and also it should be agnostic of the environment where the code is being used so it makes sense that JS and CSS would be separated.

comatory avatar Feb 15 '21 16:02 comatory

Actually, there is a skypack issue on this: importing styles. Also data like json. https://github.com/skypackjs/skypack-cdn/issues/107

I currently do this myself two ways

1 - via a general async function. It looks like:

await util.setCssStyle(
    'https://cdn.skypack.dev/mapbox-gl/dist/mapbox-gl.css'
)

Here's the code:

export async function setCssStyle(url) {
    const response = await fetch(url)
    if (!response.ok) throw Error(`Not found: ${url}`)
    const css = await response.text()
    document.head.innerHTML += `<style>${css}</style>`
}

The second way is via a "wrapper" cli which takes the css text and outputs a module which wraps the actual css and installs it in <head> for you. The wrapper works like this:

function processData(data) {
    data = `document.head.innerHTML += \`
<style>
${data}
</style>\``
    return data
}

This will be much simpler when top level async arrives. Chrome's next major release will include it.

But lets hope the github issue is resolved with yet another nifty solution from the skypack team!

backspaces avatar Feb 15 '21 17:02 backspaces

Import maps is enabled by default with chromium based browsers, please provide an esm build of mapbox-gl, I think many people like me would like to try a bundle free development.

beginor avatar Jun 13 '21 09:06 beginor

Can we also get a working official esm build for the cdn as well? It's 2023 and many people would like to just do

import mapboxgl from 'https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.js';

benatshippabo avatar Feb 13 '23 18:02 benatshippabo

Would also like this functionality.

ersk avatar May 02 '23 10:05 ersk

painfully stubbed my toe. autsch

wibed avatar May 04 '23 08:05 wibed

Any update? Temporary I use /* eslint-disable import/default, import/no-named-as-default-member */ as workaround

szulcus avatar Aug 07 '23 11:08 szulcus

All the bundlers also support UMD. Using ES modules in browsers directly is still rare, but we definitely want to explore that at some point. Related: #6391

Using ES modules in browsers directly would no longer be considered rare.

marksteward avatar Aug 24 '23 17:08 marksteward

+1

Igoryoka avatar Jul 10 '24 21:07 Igoryoka

greetings, where are we at with this esm build. is it a yes or should we move on to leaflet? thanks

yosiasz avatar Jul 11 '24 17:07 yosiasz

+1

navidemad avatar Jul 11 '24 21:07 navidemad

The +1s aren't very helpful. Try esm.sh as a workaround for now:

<script type="importmap">
{
  "imports": {
    "mapbox-gl": "https://esm.sh/[email protected]"
  }
}
</script>
...
<script type="module">
import mapboxgl from 'mapbox-gl';

mapboxgl.accessToken = '...';
const map = new mapboxgl.Map({
  container: 'map',
  center: [0, 51.5],
  zoom: 9
});

</script>

marksteward avatar Jul 11 '24 22:07 marksteward

so why still doesn't it supported? I can't deploy it with the sveltekit + svelte 5.

No such module "server/entries/pages/mapbox-gl". imported from "server/entries/pages/_page.svelte.js"

DongwonTTuna avatar Mar 22 '25 02:03 DongwonTTuna

Hey everyone,

We've just published GL JS v3.17.0-beta.1 with experimental ESM support. You can now use Mapbox GL JS as a native ES module directly in the browser—no bundler required. We'd appreciate your feedback as we continue developing this.

Using the ESM build via CDN

<!DOCTYPE html>
<html>
<head>
    <link href="https://api.mapbox.com/mapbox-gl-js/v3.17.0-beta.1/mapbox-gl.css" rel="stylesheet">
</head>
<body>
    <div id="map" style="width: 100%; height: 100vh;"></div>

    <script type="module">
        import mapboxgl from 'https://api.mapbox.com/mapbox-gl-js/v3.17.0-beta.1/esm-min/mapbox-gl.js';

        mapboxgl.accessToken = 'YOUR_MAPBOX_TOKEN';
        
        const map = new mapboxgl.Map({
            container: 'map',
            center: [-122.42, 37.78],
            zoom: 12
        });
    </script>
</body>
</html>

Using the ESM build via NPM

For now, you'll need to use a direct path import. We plan to make the default import work in a future releases.

import mapboxgl from 'mapbox-gl/dist/esm-min/mapbox-gl.js';

mapboxgl.accessToken = 'YOUR_MAPBOX_TOKEN';

const map = new mapboxgl.Map({
    container: 'map',
    center: [-122.42, 37.78],
    zoom: 12
});

Note: The current ESM build uses code splitting with three modules (mapbox-gl.js, shared.js, and worker.js) but does not yet support proper tree shaking. This is something we plan to work on in future iterations.

Please share your feedback on what works well and what doesn't. This will help us determine the best path forward for ESM support in GL JS.

stepankuzmin avatar Nov 07 '25 11:11 stepankuzmin