Leaflet.markercluster icon indicating copy to clipboard operation
Leaflet.markercluster copied to clipboard

Does not work with ES6 imports for leaflet

Open pke opened this issue 6 years ago • 30 comments

It seems this plugin makes the assumption that L is still exported globally. However using leaflet the ES6 way with direct imports like import { map } from "leaflet/src/map/Map"

does not expose a L global anymore. So trying to include this plugins MarkerClusterGroup fails cause of this definition.

export var MarkerClusterGroup = L.MarkerClusterGroup = L.FeatureGroup.extend({

The correct way would be to write this like this:

import { FeatureGroup } from "leaflet/src/layer/FeatureGroup"
export var MarkerClusterGroup = FeatureGroup.extend({

pke avatar Feb 21 '18 16:02 pke

works fine for me if you just import all of it...

import 'leaflet/dist/leaflet.css' import 'leaflet/dist/leaflet' import 'leaflet-draw' import 'leaflet-draw/dist/leaflet.draw.css' import 'leaflet.markercluster' import 'leaflet.markercluster/dist/MarkerCluster.css'

kgrosvenor avatar Mar 13 '18 17:03 kgrosvenor

Yes but then you throw away all the benefits of ES6 modules. Which is to load only what you really need.

pke avatar Mar 13 '18 17:03 pke

If you find a solution let me know, what modules does this work with so far on leaflet?

kgrosvenor avatar Mar 13 '18 17:03 kgrosvenor

Yeah, I'm interested in this proper solution as well...

I've taken from the above and was able to get it working, although, as mentioned without the benefit of ES6 and selectively loading what was needed.

// Import CSS from Leaflet and plugins.
import 'leaflet/dist/leaflet.css';
import 'leaflet.markercluster/dist/MarkerCluster.css';
import 'leaflet.markercluster/dist/MarkerCluster.Default.css';

// Import images directly that got missed via the CSS imports above.
import 'leaflet/dist/images/marker-icon-2x.png';
import 'leaflet/dist/images/marker-shadow.png';

// Import JS from Leaflet and plugins.
import 'leaflet/dist/leaflet';
import 'leaflet.markercluster/dist/leaflet.markercluster';
import 'leaflet.gridlayer.googlemutant/Leaflet.GoogleMutant';

Related PRs and discussions for Leaflet:

  • https://github.com/Leaflet/Leaflet/pull/5620
  • https://github.com/Leaflet/Leaflet/pull/6021

I'd love to figure out how to use the correct, minimalistic ES6 way with my custom Leaflet setup. The only plugins I'm using are markercluster, because who wouldn't use it?! and the Google maps layer.

If I use: import * as L from 'leaflet'; instead of import 'leaflet/dist/leaflet';, I get TypeError: L.markerClusterGroup is not a function.

himerus avatar Mar 22 '18 00:03 himerus

Hi @himerus,

By curiosity, please what is your build engine, version, and what are the Leaflet and Leaflet.markercluster versions you are using?

ghybs avatar Mar 24 '18 04:03 ghybs

@ghybs,

I too have the same problem as @himerus.

import * as L from 'leaflet';instead of import 'leaflet/dist/leaflet';, I get TypeError: L.markerClusterGroup is not a function.

but if I use

import 'leaflet/dist/leaflet';

I got error 'L' is not defined no-undef

I'm using maven to build Leaflet 1.3.1 Leaflet.markercluster 1.3.0

azrin1972 avatar Mar 25 '18 07:03 azrin1972

Same as above mentioned by @azrin1972 . Only difference in my setup is I'm using Webpack.

The 'L' is not defined no-undef is coming from eslint. The TypeError: L.markerClusterGroup is not a function is a fatal error that stops MarkerCluster from working.

himerus avatar Mar 25 '18 11:03 himerus

Hi,

Thank you @azrin1972 and @himerus for the details of your setup.

Very strange, I have no issue at all with webpack, either with import * as L from 'leaflet' or just import 'leaflet': https://github.com/ghybs/test-mcg-import-webpack (ignoring the ESLint warning for now)

  • webpack 4.2.0
  • Leaflet 1.3.1
  • Leaflet.markercluster 1.3.0

ghybs avatar Mar 26 '18 16:03 ghybs

I have the same issue. only happens with leaflet 1.3.1 but not with 1.3.0. Uncaught ReferenceError: L is not defined Using anuglar-cli (which uses webpack) and using import * as L from "leaflet" in various places in the code. Project can be found here if it can help: https://github.com/IsraelHikingMap/Site/tree/master/IsraelHiking.Web

HarelM avatar Mar 27 '18 22:03 HarelM

My mistake, I was using a branch version of leaflet: https://github.com/va2ron1/Leaflet which doesn't have the oldL defined and so marker cluster crashes (I think). Not sure if this is a part of leaflet next release or the branch...

HarelM avatar Mar 28 '18 20:03 HarelM

Right under the imports, I have used this to declare L.

const L = window['L'];

dallasclymer avatar Jul 12 '18 18:07 dallasclymer

I'm using

"leaflet": "^1.3.1",
"leaflet.markercluster": "^1.3.0"

and

"@types/leaflet": "^1.2.6",
"@types/leaflet-markercluster": "^1.0.3"

The following worked for me:

import 'leaflet';
import 'leaflet.markercluster';

const L = window['L'];

severinbeauvais avatar Jul 17 '18 22:07 severinbeauvais

Make things working on leaflet-src.esm.js and without window.L:

  • Leaflet.markercluster-1.3.0
  • leaflet-1.3.2 (NOT 1.3.3 or 1.3.1), see leaflet#6239
  • Need some shims using import/export loaders:
import Leaflet from 'leaflet'
import MarkerClusterGroup from 'imports-loader?L=leaflet!exports-loader?L.MarkerClusterGroup!./node_modules/leaflet.markercluster/dist/leaflet.markercluster.js'

// Create cluster:
val mcg = new MarkerClusterGroup(...);
Leaflet.addLayer(mcg);

Solution based on earlier crunch (L<=1.3.1).

helllamer avatar Aug 02 '18 09:08 helllamer

I'm using webpack to bundle my project. When I put leaflet and leaflet.markerclusterer together in the vendor bundle I don't have this issue anymore. Maybe helpful for people using this with webpack!

markomalis avatar Sep 17 '18 09:09 markomalis

Hi, I'm still unable to load markercluster in my project. what I'm trying to do is to add markercluster to https://github.com/thingsboard/thingsboard. Really need some help on how to solve this. it uses webpack 1.13.2. and I cannot use webpack 4 - I'm getting error compiling it.

I've tried all the solution here and still getting the same issue

azrin1972 avatar Oct 07 '18 13:10 azrin1972

Finally found the solution

instead of using import * as L from 'leaflet'

I use

import L from 'leaflet'

some reading http://www.thedreaming.org/2017/04/28/es6-imports-babel/

azrin1972 avatar Nov 12 '18 14:11 azrin1972

Ran into this issue while trying to use Markercluster in a web component based PWA (no packaging involved yet, just dev server). I can import all the leaflet modules like this:

import { TileLayer } from 'leaflet/src/layer/tile'
import { GeoJSON } from 'leaflet/src/layer'
import { CircleMarker } from 'leaflet/src/layer/vector'
import { Marker, Icon, DivIcon } from 'leaflet/src/layer/marker'

but import { MarkerClusterGroup } from 'leaflet.markercluster/src' results in ReferenceError: L is not defined None of the workarounds mentioned here works for me.

rednil avatar Dec 05 '18 14:12 rednil

A guess the way to solve this is to stop depending on window.L in all the files, and instead do ES import, like leaflet/leaflet does. It would be a pretty great step forward.

kontrollanten avatar Feb 27 '19 21:02 kontrollanten

@danzel What do you say about this? Shall we try to make this package independent on global L and instead use ES6 imports?

kontrollanten avatar Mar 03 '19 19:03 kontrollanten

We follow what leaflet recommends for plugins (AFAIK). https://github.com/Leaflet/Leaflet/blob/master/PLUGIN-GUIDE.md

If we want to change this, probably fire up an issue on the leaflet tracker for discussion. Would be good to improve this support.

danzel avatar Mar 05 '19 20:03 danzel

I can't see anything in their recommendations against this, we'll still bundle the plugin so it'll work as before for those who're using the UMD version

kontrollanten avatar Mar 05 '19 22:03 kontrollanten

Coming back here after 2 years I'd have thought this issue to be resolved. It seems its still not possible to properly import leaflet and this plugin. I am going to open a new PR over at leaflet to suggest a 2.0 release and intentionally breaking all the plugins depending on a global 'L' var. It seems otherwise we can not get any plugin owner to move forward to packages.

pke avatar Jan 07 '20 08:01 pke

I've made PR #984 that should fix this few days ago, I'd like some backup.

Basically in source files L is used as global and it leaked to the bundle. I've configured rollup to feed L variable from UMD require - which works as well with global L outside the bundle.

And it's ok with guidelines: https://github.com/Leaflet/Leaflet/blob/master/PLUGIN-GUIDE.md#module-loaders

m1gu3l avatar Jan 23 '20 08:01 m1gu3l

import * as L from "leaflet"; import * as L1 from "leaflet.markercluster"; ... var markers = new L1.MarkerClusterGroup();

Hope it works for you guys

AliBayatpour avatar Nov 22 '20 15:11 AliBayatpour

import * as L from "leaflet"; import * as L1 from "leaflet.markercluster"; ... var markers = new L1.MarkerClusterGroup();

Hope it works for you guys

this gives me :

Uncaught TypeError: t is undefined
    <anonymous> /webcomponents/leafletmap/leaflet/leaflet.js:5
    <anonymous> /webcomponents/leafletmap/leaflet/leaflet.js:5

daslicht avatar Dec 04 '20 17:12 daslicht

just in case anybody runs into the same situation I had here: I tried to go from;

import "leaflet";
import "leaflet.markercluster";

...
let mcluster = L.markerClusterGroup({ chunkedLoading: true });

to:

import { Map, Marker,  } from "leaflet";
import { MarkerClusterGroup } from "leaflet.markercluster/src";

...
let mcluster = MarkerClusterGroup({ chunkedLoading: true });

I banged my head against a wall until I realized I had to call it with new:

let mcluster = new MarkerClusterGroup({ chunkedLoading: true });

andreasnuesslein avatar Dec 24 '20 00:12 andreasnuesslein

I guess this still has not been fixed?

lukebouch avatar Mar 23 '22 18:03 lukebouch

Might be able to work around this by adding to webpack.config.js under exports.plugins:

      new webpack.ProvidePlugin({
        L: 'leaflet',
        'window.L': 'leaflet',
      }),

jacobweber avatar May 30 '22 23:05 jacobweber

since we're posting hotfixs. I've got a Vue app in Quasar 2. Before the Vue app is initialized:

import * as L from "leaflet/dist/leaflet-src.esm.js"
globalThis.L = L

in a component then:

  async mounted() {
    const { MarkerClusterGroup } = await import('leaflet.markercluster')
    console.log(this.$options.name, this.projects, MarkerClusterGroup)
  }

disarticulate avatar Jul 29 '22 12:07 disarticulate

I was having a similar problem using leaflet in Vite: No matching export in "node_modules/leaflet/dist/leaflet-src.esm.js" for import "toLatLngBounds"

Using import 'leaflet/dist/leaflet'; instead import L from 'leaflet'; or import 'leaflet'; worked for me.

willianspraciano avatar Oct 03 '22 17:10 willianspraciano