Mendix 是首屈一指的低代码平台,其主要优势之一是其提供的可扩展性。您可以使用 React 来整合酷炫的第三方库并扩展您的应用程序。
这是系列博文中的第 4 篇,之前的博文可以在这里找到: 在以下位置构建小部件 Mendix 使用 React — 第一部分 — 颜色计数器, 在中构建小部件 Mendix 使用 React 第二部分 — 计时器和 在中构建小部件 Mendix 使用 React 第 3 部分 — Kanban.
我们正在构建什么
近期,位于新斯科舍省贝德福德的 伊沃·史都姆 写了一篇关于将现有 ArcGIS 小部件从 Dojo 转换为 React 的博客。
我觉得 从头开始构建 ArcGIS 地图小部件的简单版本.

立即开始
与迄今为止的所有可插入式小部件博客一样,我们首先 搭建我们的小部件 通过运行 yo @mendix/widget arcGISMap 以及 设置测试 Mendix 项目.
让我们开始 安装 npm 包 用于 ArcGIS Javascript API
npm install @arcgis/core
ArcGIS 是一个在线地理信息系统,允许您显示地图并添加图层以显示一系列信息。

为了获得完整的服务 您需要注册并创建访问令牌 但是,为了举出我们这个简单的例子,我们可以不用它。
入门
审查 文件 我们可以更新代码以包含两个文件:
家长
从“react”导入 {ReactElement,createElement};从“。/components/Map”导入{MapComponent};从“。/typings/ArcGISMapBlogProps”导入{ArcGISMapBlogContainerProps};导入“。/ui/ArcGISMapBlog.css”;
导出函数 ArcGISMapBlog(props:ArcGISMapBlogContainerProps):ReactElement {返回; }
还有一个孩子
从“react”导入{ReactElement,createElement,useEffect,useRef};从“导入 Map@arcgis/核心/Map";从"导入MapView@arcgis/核心/views/MapView”;从“导入图例@arcgis/核心/小部件/图例”;
导出接口 MapProps { basemap:字符串; }
导出函数 MapComponent({ basemap }: MapProps): ReactElement { const mapDiv = useRef(null);
useEffect(() => { if (mapDiv.current) { MountMap(basemap); } }, [basemap]);
const MountMap = (basemap: string): MapView => { const legend = new Legend(); const map = new Map({ basemap }); const view = new MapView({ map, center: [0.029, 51.256], // 经度,纬度 zoom: 10, // 缩放级别 container: mapDiv.current as unknown as HTMLDivElement });
legend.view = view; view.ui.add(legend, "bottom-right"); 返回视图; };
返回; }
让我们 还可以从 ArcGIS 导入样式表 为了使我们的小部件看起来美观,请将 UI/{widgetName}.css 更改为:
@import "https://js.arcgis.com/4.24/@arcgis/core/assets/esri/themes/dark/main.css";
现在我们用 npm run build 然后...我们收到一个错误:
[!] 错误:选项“output.file”的值无效 - 构建多个块时,必须使用“output.dir”选项,而不是“output.file”。要内联动态导入,请设置“inlineDynamicImports”选项。
那么我们该如何解决这个问题呢?为了解释清楚,我们需要先退后几步……
JavaScript 简史
下一部分是 Javascript 的简要历史,为解决方案提供背景,如果您不感兴趣,请随意跳过并继续示例
在一开始的时候…
Javascript 由 Brendan Eich 于 1995 年发明,在其发展的最初几年,它主要用于独立的脚本任务。随着 JS 在应用程序中的使用越来越广泛,管理代码变得越来越困难。JS 的使用方式越来越复杂,通常跨多个脚本,这不可避免地会导致函数和名称冲突。
因此,引入了模块概念,这意味着可以在封闭的地方编写代码供内部使用,而不必担心其他地方的冲突,同时也允许开发人员将大型代码库分解为小的独立部分,从而更容易编写和维护。
第一次尝试修复这个问题是 立即调用函数表达式 (IIFE),本质上只是将每个文件包装在一个函数中,将变量和函数保存在文件内,在该范围内而不是全局范围内。
(function() {// Your code }) ();
这种方法仍然存在许多问题,包括缺乏依赖性解析和 全局命名空间的污染.
随着时间的推移,出现了 3 个独立(且相互竞争)的模块规范:
- CommonJS的 — 仍然广泛用于 Node 的服务器端 JS,并且很容易识别
require()以及module.exports句法 - AMD — 异步模块定义,很早就从 CommonJS 中分离出来了。关键区别在于 AMD 允许不相互依赖的模块异步加载(名字就说明了一切!)
- UMD — 通用模块定义,支持其他模块规范以及“旧式”的“全局”变量定义
这一切都非常复杂……所以有一些好消息。自 2015 年 ES6 发布以来, Javascript 语言已支持模块。这给了我们可爱而简单的import 以及 export 我们在代码中一直使用的语法。
那么为什么要讲历史课呢?因为我们在编写代码时需要能够处理所有这些模块类型,这就是打包器的作用所在。
捆绑包
打包工具可以让你 在构建时编译代码, 处理你的依赖项和 提供兼容的连接文件. 常见的解决方案包括 的WebPack (用于 Mendix 8 个小部件)和 卷起 (用于 Mendix 9 个小部件)
这使您可以使用现代 ES6 功能(如果您喜欢,甚至可以使用 Typescript)模块化编写代码,然后生成优化的文件(或一组文件)以提供给浏览器。
这很好,但有些浏览器还不支持 ES6,所以它们无法处理这些编译好的文件。为了解决这个问题 我们可以使用 Transpiler 如 巴贝尔 以可读的格式将其提供给网页。
回到我们的小部件...
Pluggable Widget 框架需要开发 React 组件所需的所有工具 Mendix 应用程序。这包括:
- NPM — 一个包管理器,可轻松安装和管理第三方包
- 卷起 — 捆绑器,可让您模块化地编写代码,然后将其捆绑到小包中
- 巴贝尔 — 转换器,将 JS 转换为旧版浏览器(和 Studio Pro)可以读取的格式
那么我们的错误意味着什么?
[!] 错误:选项“output.file”的值无效 - 构建多个块时,必须使用“output.dir”选项,而不是“output.file”。要内联动态导入,请设置“inlineDynamicImports”选项。
对于每个小部件项目,我们使用@mendix/pluggable-widget-tools 库提供的汇总配置。
可以在以下位置找到: node_modules/@mendix/pluggable-widget-tools/configs.rollup.config.js。
在此配置中,我们 告诉我们的小部件将编译后的 JS 输出到单个文件中。 同时, ArcGIS npm 库 我们正在使用提供 分块动态导入,默认情况下 rollup 希望将文件拆分成单独的文件放到一个目录中.
为了解决这个问题,我们只需要按照错误提示进行操作即可 设置 inlineDynamicImports 选项,它将把所有内容拉到一个文件中。我们可以更改 Pluggable Widgets 库中的 rollup.config.js 文件,但这是一个非常糟糕的想法,因为它不可维护,并且会创建非常难以阅读和调试的代码。幸运的是 Mendix 具有内置功能来设置我们自己的汇总配置.
我们要 创建文件 称为 rollup.config.js 在根小部件目录中。然后我们添加以下 JS 代码来更改小部件的构建方式:
export default args => { const result = args.configDefaultConfig; console.warn ('自定义汇总') return result.map((config) => { config.output.inlineDynamicImports = true console.warn ("设置动态导入") return config; }); };
所以我们跑 npm run build 再次出现新的错误:
严重错误:达到堆限制分配失败 - JavaScript 堆内存不足
事实证明构建过程需要更多内存。我可以通过运行来更新它
导出 NODE_OPTIONS=--max_old_space_size=5120
如果我们重建,那么我们的小部件现在就可以编译。
我们的捆绑器可以帮助我们创建单个文件,以便浏览器可以轻松读取它们。
Rollup 还做了另外一件非常聪明的事情,叫做 摇树:这涉及建立 代码中的依赖树 以及 仅包含实际需要的代码。这在使用大型库时特别有用,可以避免将大量未使用的代码加载到浏览器中。这种树摇动是关键因素之一 Mendix 从 webpack 切换到 rollup Mendix 8和9。
Bundler 还附带了一大堆其他功能,在 Rollup 中,这些功能以插件的形式出现。我在本博客中要做的最后一件事是介绍一个非常常见的用例,即必须修改小部件的 Rollup 配置
提供小部件所需的文件
ArcGIS 通过 内容分发网络(CDN) 。然而可能 你想保留的情况 并在您的小部件中管理这些文件,可能是由于您的组织内部的防火墙设置。幸运的是,ArcGIS Javascript API 使这成为可能。
首先要做的是更新我们的代码, 告诉 API 我们将 本地管理我们的资产。为此,我们只需更新容器组件以包含:
从“导入 esriConfig”@arcgis/核心/config.js”;
导出函数 ArcGISMapBlog(props:ArcGISMapBlogContainerProps):ReactElement { esriConfig.assetsPath =“。/widgets/mendix/arcgismapblog/assets”; 返回; }
接下来,我们需要 更新 我们的 卷起 至 拿起我们 需要来自我们的节点模块和 把它们放在我们的小部件中 mpk。
为了做到这一点,我们可以 使用汇总复制插件 (所有东西都有插件),首先,我们需要安装它
npm i rollup-plugin-copy —save-dev
我们使用 —save-dev 命令,因为它是开发时才需要的依赖项。然后我们将 rollup.config.js 更新为:
从“rollup-plugin-copy”导入副本;导出默认参数=> { const result = args.configDefaultConfig; console.warn ('自定义汇总') return result.map((config) => { config.output.inlineDynamicImports = true console.warn ("设置动态导入") const plugins = config.plugins || [] config.plugins = [...plugins,copy({targets:{src:“node_modules/@arcgis/core/assets”,dest:“dist/tmp/widgets/mendix/arcgismapblog”}]
}), ] 返回配置; }); };
本篇 拿走“资产” ArcGIS npm 包中的文件夹和 将其放入我们的 dist/tmp 文件夹中 这最终会被压缩以创建我们的 mpk。然后当我们运行我们的应用程序时,小部件 mpk 的内容将被提供给 ./widgets/{您的组织名称}/{您的Widget名称}.
为了实际演示,我们来运行命令来构建我们的小部件
npm 运行构建
然后我们可以重新运行我们的应用程序。

如果我们打开部署目录,我们可以看到小部件正在提供资产文件夹,如果我们在 Chrome 开发工具中检查页面源代码,我们可以看到 ArcGIS Web 程序集文件已提供给浏览器,以确保我们的地图正常工作
我们没有更新 CSS 以使用本地文件。为此,我们只需将文件更新为:
@import“ ../assets/esri/themes/dark/main.css”;
简单……有点……
如果你正在使用 9.13.2 或以下版本的可插入式小部件工具 并且你使用的是 Windows,那么你的 字体无法正确导入。rollup.config.js 中需要以下代码来修复导入:
从“postcss-url”导入postcssUrl;
const cssUrlTransform = asset => { const outWidgetDirForwardSlash = outWidgetDir.replace(/\\/g, "/") 返回 asset.url.startsWith(`${assetsDirName}/`) ? `${outWidgetDirForwardSlash}/${asset.url}` : asset.url; }
export default args => { const result = args.configDefaultConfig; console.warn ('自定义汇总') return result.map((config) => { config.output.inlineDynamicImports = true console.warn ("设置动态导入") const plugins = config.plugins || [] config.plugins = [ ...plugins, postcssUrl (cssUrlTransform)
] 返回配置; }); };
然后运行 npm install postcss-url --save-dev 。您的小部件现在将以图标形式呈现。
我们完成了!
ArcGIS API 包含许多令人惊叹的功能,我鼓励您探索它。要查看它可以做什么的一个很好的例子,请查看 Ivo Sturm 的小部件: GitHub – ivosturm/ArcGIS-React:基于 React 的全新改进型 ArcGIS 小部件。我的 ArcGIS 小部件的 repo 可以在这里找到: GitHub – joe-robertson-mx/arcGISMapBlog.