首页 > 解决方案 > Leaflet 在通过 CDN 使用而不是通过 npm pakcage 使用时呈现 Windy 地图

问题描述

我通过 CDN 在 React 中使用LeafletWindy,效果很好:

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

反应组件:

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);
    });
};

但是我希望能够使用传单 npm 包,而不是 CDN。当我导入包时,它已定义但 Windy 抛出错误:

libBoot.js:3 传单库丢失

在 index.js 中:

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

反应组件:

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);
    });
};

关于在线设置的信息很少,因为 Windy 服从 Leaflet,而 Leaflet 服从 Windy。Leaflet 快速入门指南或他们的 github 中没有信息。

使用Leaflet npm 包完成这项工作的正确方法是什么

标签: javascriptreactjsleaflet

解决方案


Leaflet library is missing ”错误仅仅是由于这些JS库的加载顺序:

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

在脚本开头加载 Leaflet 库,然后从 URL 加载 Windy API 库https://api.windy.com/assets/map-forecast/libBoot.js

  • 当您<script>自己在 HTML 页面中明确编写标签(通过 CDN 加载它们)时,您首先正确加载 Leaflet,然后是 Windy
  • 但是当您使用importLeaflet 时,webpack(这是您使用 React 时的默认构建引擎)将其与您的应用程序代码捆绑在一起,并且默认情况下它会将<script>标签最后插入<body>HTML 页面的最后,因此使其Windy 之后加载(然后抛出错误消息)
  • 当您重新引入<script>标签以从文件夹中加载 Leaflet 时node_modules,我猜您先将其放回原处(即在 Windy 的标签之前);但是,这仅在开发中有效,因为该node_modules文件夹在生产中不可用。

对您来说最简单的解决方案是如果 Windy 库可以从本地文件(或 npm 包)而不是从其 URL(/CDN)加载:在这种情况下,您只需import在 Leaflet 之后加载它,webpack 会将它们捆绑在那个命令。

然而,Windy 可能会根据其位置本身执行一些魔法,例如加载 CSS:

Leaflet CSS 会自动加载。

虽然可以解决 CSS 的这种行为,但它很可能对其他东西也有一些魔力(例如访问它的数据和层)。

因此,如果我们假设我们必须从 CDN 加载 Windy,但是(无论出于何种原因)我们已经完全准备好从 npm 加载 Leaflet(而不是从 CDN 加载,我们知道它工作正常且容易),我们必须找到一种方法以某种方式强制 webpack 加载顺序。

我们现在显然已经跳出了 webpack 主要用例,因为在这种特定情况下,我们仍然希望捆绑 Leaflet,但是从 URL 和Leaflet之后加载 Windy ,但显然是在我们的应用程序代码之前。

我看到至少 2 种可能的(显然是 hacky)解决方案:

  • 在我们的应用程序代码中动态生成<script>W​​indy 的标签;这确保它在 Leaflet 之后加载;但是我们必须延迟执行依赖于 Windy 的应用程序部分(例如,通过将其包装在 a 中setTimeout,理想情况下检查 Windy 现在是否可用,因为它的加载延迟可能会有所不同)
  • 在我们的代码中使用一些 webpack 插件到importWindy,但实际上 webpack 仍然从 URL 加载它:例如使用具有特定配置的dynamic-cdn来指定 URL;不确定仍然有正确的加载顺序是否容易,因为它可能无法识别对 Leaflet 的依赖关系。

尽管如此,在这种情况下,我们可能仍然质疑从 npm 加载 Leaflet 的需要(因为在 Windy 之前从 CDN 加载它是轻而易举的事)。

鉴于any你必须为 Windy 做演员,我看到你实际上使用了 TypeScript。因此,您可能希望有 Leaflet 类型可用,这在您import(并且已经安装@types/leaflet)时几乎很自然地出现,给您的印象是必须从 npm 加载它才能使这些类型工作。在这种情况下,我们可以利用类型和实际运行时代码是两个独立的东西这一事实。在这种情况下,您仍然可以import在代码中使用 Leaflet 并从其类型中受益,但指示 webpack 不应捆绑它;您将使其在外部可用,通常是因为您从 CDN 加载。见外物webpack 的选项。这样,您就可以两全其美:您可以自由地以自己的方式加载 Leaflet,在 Windy 之前显式加载,并且仍然具有 Leaflet 类型。


推荐阅读