如何通过Webpack通过CDN包含ArcGIS Javascript API以与Stimulus一起使用?

问题描述 投票:0回答:1

在ArcGIS javascript API的quick start指南中,它具有以下示例代码:

<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
  <title>ArcGIS API for JavaScript Hello World App</title>
  <style>
    html, body, #viewDiv {
      padding: 0;
      margin: 0;
      height: 100%;
      width: 100%;
    }
  </style>

  <link rel="stylesheet" href="https://js.arcgis.com/4.12/esri/css/main.css">
  <script src="https://js.arcgis.com/4.12/"></script>

  <script>
    require([
      "esri/Map",
      "esri/views/MapView"
    ], function(Map, MapView) {

      var map = new Map({
        basemap: "topo-vector"
      });

      var view = new MapView({
        container: "viewDiv",
        map: map,
        center: [-118.71511,34.09042],
        zoom: 11
      });

    });
  </script>
</head>
<body>
  <div id="viewDiv"></div>
</body>
</html>

这对于简单的网页非常有用。但是,我正在使用Blazor(服务器端),并且我想将(以上)代码封装到Blazor组件中。因此,我遇到了第一个绊脚石-不允许在Blazor组件内添加<script>标签。这是因为控件可以随时动态创建。因此,我认为我可以改用Stimulus解决该问题。

这里是我的Blazor组件(到目前为止)。我有一个名为Map.razor的文件:

<div data-controller="map"></div>

@code {
    protected override bool ShouldRender()
    {
        var allowRefresh = false;

        return allowRefresh;
    }
}

我添加了ShouldRender方法,以便仅将组件呈现一次(添加时)。这就是我想要在Stimulus控制器map-controller.js中实现的目标:

import { Controller } from "stimulus";

import EsriMap from "esri/Map";
import MapView from "esri/views/MapView";

export default class extends Controller {
    connect() {
        var map = new EsriMap({
            basemap: "topo-vector"
        });

        var view = new MapView({
            container: this.element,
            map: map,
            center: [-118.80500, 34.02700], // longitude, latitude
            zoom: 13
        });
    }
}

最初,我尝试添加ArcGIS,以便可以使用Webpack构建它(以便上面的代码可以工作)。但是,我遇到了ArcGIS javascript api和tailwindcss之间的兼容性问题。由于无法调用require('fs'),因此ArcGIS无法编译。

不是解决require('fs')问题(这是我现有的经验),我选择通过CDN引入ArcGIS js。因此,我尝试使用Webpack中的external配置功能来设置ArcGIS。这是我的webpack.js.config文件:

const path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

const bundleFileName = 'holly';
const dirName = 'Holly/wwwroot/dist';

module.exports = (env, argv) => {
    return {
        mode: argv.mode === "production" ? "production" : "development",
        externals: {
            'esrimap': 'esri/Map',
            'mapview': 'esri/views/MapView'
        },
        entry: ['./Holly/wwwroot/js/app.js', './Holly/wwwroot/css/styles.css'],
        output: {
            filename: bundleFileName + '.js',
            path: path.resolve(__dirname, dirName),
            libraryTarget: "umd"
        },
        module: {
            rules: [{
                test: /\.css$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    'postcss-loader'
                ]
            }]
        },
        plugins: [
            new MiniCssExtractPlugin({
                filename: bundleFileName + '.css'
            })
        ]
    };
};

这就是我在刺激控制器中所做的:

import { Controller } from "stimulus";

import EsriMap from "esrimap";
import MapView from "mapview";

export default class extends Controller {
    connect() {
        var map = new EsriMap({
            basemap: "topo-vector"
        });

        var view = new MapView({
            container: this.element,
            map: map,
            center: [-118.80500, 34.02700], // longitude, latitude
            zoom: 13
        });
    }
}

但是,我在浏览器中看到以下异常:

TypeError: esrimap__WEBPACK_IMPORTED_MODULE_1___default.a is not a constructor
    at Controller.connect (map_controller.js:14)
    at Context.connect (context.ts:35)
    at Module.connectContextForScope (module.ts:40)
    at eval (router.ts:109)
    at Array.forEach (<anonymous>)
    at Router.connectModule (router.ts:109)
    at Router.loadDefinition (router.ts:60)
    at eval (application.ts:51)
    at Array.forEach (<anonymous>)
    at Application.load (application.ts:51)

您可能已经猜到了,我已经达到了我的javascript / webpack知识的极限。我对ArcGIS javascript API及其是否支持commonjs做了一些研究。显然,它使用了支持AMD的Dojo。所以我尝试了以下配置:

        externals: [{
            'esrimap': {
                commonjs: 'esri/Map',
                commonjs2: 'esri/Map',
                amd: 'esri/Map'
            },
            'mapview': {
                commonjs: 'esri/views/MapView',
                commonjs2: 'esri/views/MapView',
                amd: 'esri/views/MapView'
            }
        }],

但是我遇到了同样的错误。我已经阅读了Webpack documentation-我尚不清楚应如何配置。我是从根本上做错了吗?

webpack cdn blazor arcgis-js-api stimulusjs
1个回答
0
投票

所以我想我应该用刺激来解决这个问题。

以下是对以上短语前面的问题的回答,忽略了随后的所有内容。一种替代解决方案,即使它不能解决您的完整问题,该解决方案也应能奏效。

创建专用于blazor组件的脚本,并在Pages/_host.cshtmlwwwroot/index.html中呈现或引用它:

<script>
    window.myComponent = { 
      init: function(options) { 
        require([
          "esri/Map",
          "esri/views/MapView"
        ], function(Map, MapView) {

          var map = new Map({
            basemap: "topo-vector"
          });

          var view = new MapView({
            container: options.containerId,
            map: map,
            center: [-118.71511,34.09042],
            zoom: 11
          });

        }); // end require

       } // end init

     }; // end myComponent
  </script>

并通过覆盖async Task OnAfterRenderAsync(bool isFirstRender)在您的组件中调用此脚本。仅在isFirstRender设置为true时调用它。

您可以通过注入IJSRuntime并调用await InvokeAsync("myComponent.init", "container-id")来调用脚本>

这样的东西(未经测试)

@inject IJSRuntime JSRuntime
<div id="@containerId" data-controller="map"></div>

@code {
    private string containerId = Guid.CreateGuid().ToString("n");
    protected override bool ShouldRender()
    {
        var allowRefresh = false;

        return allowRefresh;
    }

    protected override async Task OnAfterRenderAsync(bool isFirstRender) {
      if (isFirstRender){ 
         await JSRuntime.InvokeAsync("myComponent.init", new { containerId: containerId }) 
      }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.