javascriptreactjsleaflet

Leaflet renders Windy map when used via CDN but not via npm package


I am using Leaflet with Windy in React via CDN which works fine:

in index.js:

<script src="https://unpkg.com/leaflet@1.4.0/dist/leaflet.js"></script>
<script src="https://api.windy.com/assets/map-forecast/libBoot.js"></script>

React component:

export const renderMap = (): void => {
    const options = {
        key: 'xyz',
        lat: 41.3,
        lon: 2.1,
        zoom: 10,
    };
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    (window as any).windyInit(options, (windyAPI: any) => {
        const { map } = windyAPI;
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        (window as any).L.popup()
            .setLatLng([41.3, 2.1])
            .setContent(':)')
            .openOn(map);
    });
};

However I want to be able to use the leaflet npm package, not the CDN. When I import the package, it is defined but Windy throws the error:

libBoot.js:3 Leaflet library is missing

in index.js:

<script src="https://api.windy.com/assets/map-forecast/libBoot.js"></script>

React component:

import L from 'leaflet';

export const renderMap = (): void => {
    console.log('L', L); // defined - object is present
    const options = {
        key: 'xyz',
        lat: 41.3,
        lon: 2.1,
        zoom: 10,
    };
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    (window as any).windyInit(options, (windyAPI: any) => {
        const { map } = windyAPI;
        L.popup()
            .setLatLng([41.3, 2.1])
            .setContent(':)')
            .openOn(map);
    });
};

There is very little information on setting this up online because Windy defers to Leaflet, and Leaflet defers to Windy. There is no information in the Leaflet quick start guide or in their github.

What is the correct way to make this work using the Leaflet npm package


Solution

  • The "Leaflet library is missing" error is simply due to the loading order of these JS libraries:

    https://github.com/windycom/API/tree/master/hello-world#hello-world

    Load the Leaflet library at the beginning of your script and after that the Windy API library from URL https://api.windy.com/assets/map-forecast/libBoot.js.

    The easiest solution for you would have been if Windy library could be loaded from a local file (or npm package) instead of from its URL (/ CDN): in that case, you would simply import it after Leaflet, and webpack will bundle them in that order.

    However it is likely that Windy performs some magic itself based on its location, e.g. to load CSS:

    The Leaflet CSS is loaded automatically.

    While it would be possible to workaround this behaviour for CSS, it is likely it also does some magic for other stuff (e.g. access to its data and layers).

    So if we assume we must load Windy from CDN, but (for whatever reason) we are absolutely ready to still get the headache of loading Leaflet from npm (instead of from CDN as well, which we know works fine and easily), the we have to find a way to force webpack load order somehow.

    We are now clearly stepping outside of webpack main use case, because in this specific situation, we still want Leaflet to be bundled, but load Windy from URL and after Leaflet, but obviously before our app code.

    I see at least 2 possible (obviously hacky) solutions:

    All that being said, we may still question the need to load Leaflet from npm in this case (since loading it from CDN before Windy is a breeze).

    Given the casts to any you have to do for Windy, I see that you actually use TypeScript. Therefore you may want to have Leaflet typings available, which come almost naturally when you import it (and have installed @types/leaflet), giving you the impression that it must be loaded from npm for these typings to work. In that case, we can leverage the fact that the types and the actual runtime code are 2 separate things. In this case, you can still import Leaflet in your code and benefit from its type, but instruct webpack that it should not be bundled; that you will make it available externally, typically because you load from CDN. See the externals option of webpack. That way, you get the best of both worlds: you have the liberty of loading Leaflet your way, here explicitly before Windy, and still have Leaflet typings.