Leaflet / Leaflet.markercluster

Marker Clustering plugin for Leaflet
MIT License
3.93k stars 995 forks source link

Does not work with ES6 imports for leaflet #874

Open pke opened 6 years ago

pke commented 6 years ago

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({
kgrosvenor commented 6 years ago

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'

pke commented 6 years ago

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

kgrosvenor commented 6 years ago

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

himerus commented 6 years ago

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:

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.

ghybs commented 6 years ago

Hi @himerus,

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

azrin1972 commented 6 years ago

@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

himerus commented 6 years ago

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.

ghybs commented 6 years ago

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)

HarelM commented 6 years ago

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 commented 6 years ago

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...

dallasclymer commented 6 years ago

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

const L = window['L'];

severinbeauvais commented 6 years ago

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'];
helllamer commented 6 years ago

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

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


Solution based on [earlier crunch (L<=1.3.1)](https://github.com/Leaflet/Leaflet.markercluster/issues/441#issuecomment-333181382).
markomalis commented 5 years ago

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!

azrin1972 commented 5 years ago

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 commented 5 years ago

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/

rednil commented 5 years ago

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.

kontrollanten commented 5 years ago

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 commented 5 years ago

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

danzel commented 5 years ago

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.

kontrollanten commented 5 years ago

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

pke commented 4 years ago

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.

m1gu3l commented 4 years ago

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

AliBayatpour commented 3 years ago

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

Hope it works for you guys

daslicht commented 3 years ago

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
andreasnuesslein commented 3 years ago

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 });
lukebouch commented 2 years ago

I guess this still has not been fixed?

jacobweber commented 2 years ago

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

      new webpack.ProvidePlugin({
        L: 'leaflet',
        'window.L': 'leaflet',
      }),
disarticulate commented 2 years ago

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)
  }
willianspraciano commented 1 year ago

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.