geoman-io / leaflet-geoman

🍂🗺️ The most powerful leaflet plugin for drawing and editing geometry layers

Home Page:https://geoman.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Lazy loading doesn't work when leaflet is dynamically imported

ariel-salgado opened this issue · comments

I am using Svelte to create a map as a base component, and then add new functionalities by passing other components as children. Trying to reduce the bundle size of the application, I am dynamically importing leaflet, then the rest of the libraries.
The key points are that the children of the base component need to interact with its attributes, such as the map object. That is why you need to set a context.

<script lang="ts">
	import type L from 'leaflet';

	let map: L.Map | undefined;
	let leaflet: typeof L | undefined;

        // Setting context so children can interact with the map object and Leaflet
	setContext(key, {
		getMap: () => map,
		getLeaflet: () => leaflet
	});

        // Dinamically importing Leaflet as the component is mounted in the DOM
	const initMap = (mapContainer) => {
		onMount(async () => {
			leaflet = await import('leaflet');
			await import('leaflet/dist/leaflet.css');
			map = leaflet.map(mapContainer, mapOptions);
		});
	};
</script>

Then the children, in this case a drawing feature powered by leaflet-geoman, can interact with these properties.

<script lang="ts">
	const { getMap, getLeaflet } = getContext(key);

        // Getting the map object from the parent and Leaflet.
	let map = getMap();
	let L = getLeaflet();

	afterUpdate(async () => {
		if (map && !map.pm) {
			await import('@geoman-io/leaflet-geoman-free');
			await import('@geoman-io/leaflet-geoman-free/dist/leaflet-geoman.css');
		}

                // Prints the map object
		console.log(map);

                // Throws error
		L.PM.reInitLayer(map);
	});
</script>

The problem is that when dynamically importing leaflet-geoman, it throws an error. Even importing leaflet-geoman, after the map is mounted in the DOM using the afterUpdate life cycle hook to ensure that the map object is initialized throws the error.

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'reInitLayer')

If I import Leaflet normally (no dynamically) it works fine, but the bundle size grows a lot.
It may seem like a Svelte problem but I have tried this method before with other libraries and I have had no problems.

Reproduction: https://github.com/ariel-salgado/geoman-lazy-bug

System:
  OS: Windows 11 Home
Binaries:
  Node: 20.10.0

I never worked with Svelte but I found out, that Geoman is applied to the window leaflet object after importing.

window.L.PM.reInitLayer(map);
<script lang="ts">
	const { getMap, getLeaflet } = getContext(key);

        // Getting the map object from the parent and Leaflet.
	let map = getMap();
	let L = getLeaflet();

	afterUpdate(async () => {
		if (map && !map.pm) {
			await import('@geoman-io/leaflet-geoman-free');
			await import('@geoman-io/leaflet-geoman-free/dist/leaflet-geoman.css');
		}

                // Prints the map object
		console.log(map);

		window.L.PM.reInitLayer(map);
		map.pm.addControls();
	});
</script>

Maybe this helps you, to get into the right direction.

If you find an solution, please let us know

It works, it would be nice to add this to the documentation if someone encounters the same problem.
Thank you so much.