ArcGIS JS API 5.0 ESM 双模块系统冲突解决方案

ArcGIS JS API 5.0 ESM 双模块系统冲突解决方案

  • [ArcGIS JS API 5.0 ESM 双模块系统冲突解决方案](#ArcGIS JS API 5.0 ESM 双模块系统冲突解决方案)
    • 一、问题描述
    • 二、问题原因
      • [2.1 核心原因:AMD 与 ESM 模块系统混用](#2.1 核心原因:AMD 与 ESM 模块系统混用)
      • [2.2 具体场景还原](#2.2 具体场景还原)
      • [2.3 为什么 SpatialReference.WGS84 也会出问题](#2.3 为什么 SpatialReference.WGS84 也会出问题)
    • 三、解决过程
      • [第 1 步:尝试修复空间参考实例](#第 1 步:尝试修复空间参考实例)
      • [第 2 步:添加 try-catch 回退](#第 2 步:添加 try-catch 回退)
      • [第 3 步:根治方案------统一为纯 ESM 系统](#第 3 步:根治方案——统一为纯 ESM 系统)
    • 四、解决方案
      • [4.1 核心操作](#4.1 核心操作)
        • [移除 AMD 入口](#移除 AMD 入口)
        • [添加 Import Map](#添加 Import Map)
      • [4.2 修改资源引入方式](#4.2 修改资源引入方式)
      • [4.3 Import Map 的关键作用](#4.3 Import Map 的关键作用)
      • [4.4 完整对比](#4.4 完整对比)

ArcGIS JS API 5.0 ESM 双模块系统冲突解决方案

一、问题描述

在将 ArcGIS JS API 5.0 的测试页面从 AMD($arcgis.import)迁移到 ESM(import ... from '...')引入方式时,页面运行时抛出以下类型检查错误:

复制代码
[@arcgis/core/core/accessorSupport/ensureTypes]
Accessor#set Assigning an instance of 'arcgis.geometry.SpatialReference'
which is not a subclass of 'arcgis.geometry.SpatialReference'

进一步的链式错误还包括:

复制代码
OperatorProject.js:3 Uncaught (in promise) TypeError:
Cannot read properties of null (reading 'hasVCS')

完整错误栈:

复制代码
at OperatorProject.js:3:552630
at Kr (OperatorProject.js:3:553489)
at Object.Qr [as create$3] (OperatorProject.js:3:552446)
at e.createProjectionTransformation (projectionTransformation.js:3:924)
at o.execute (projectOperator.js:3:231)

这些错误的直接表现是:空间参考坐标系对象类型不匹配,投影引擎无法正常工作。


二、问题原因

2.1 核心原因:AMD 与 ESM 模块系统混用

问题的根源在于同一个页面同时存在两套模块加载系统 ,它们各自维护独立的模块缓存,导致同一个逻辑类(如 SpatialReference)产生了两个不同的实例:

复制代码
┌─────────────────────────────────────────────────────┐
│                    浏览器页面                         │
│                                                       │
│  ┌───────────────┐          ┌──────────────────────┐ │
│  │   core.js      │          │  ESM 静态 import     │ │
│  │  (AMD 系统)    │          │                      │ │
│  │                │          │  import Map from     │ │
│  │  $arcgis     │          │  './5.0/         │ │
│  │  .import()     │          │  @arcgis/core/     │ │
│  │                │          │  Map.js'             │ │
│  └───┬────────────┘          └──────────┬───────────┘ │
│      │                                  │              │
│      ▼                                  ▼              │
│  ┌──────────────┐          ┌──────────────────────┐   │
│  │ AMD 缓存      │          │ ESM 模块缓存          │   │
│  │              │          │ (浏览器原生)          │   │
│  │ SpatialRef  │          │ SpatialRef  ←不同实例 │   │
│  │ erence (v1) │          │ erence (v2)           │   │
│  └──────────────┘          └──────────────────────┘   │
│                                                       │
│   v1 !== v2 → instanceof 检查失败 ❌                    │
└─────────────────────────────────────────────────────┘

2.2 具体场景还原

测试页面 contour_demo.html 中的代码结构:

html 复制代码
<!-- 1. 加载 core.js,引入 AMD 模块系统 -->
<script type="module" src="./5.0/core.js"></script>

<!-- 2. HTML 内使用 ESM 静态 import -->
<script type="module">
    import SpatialReference from './5.0/@arcgis/core/geometry/SpatialReference.js';
    // ...
</script>

与此同时,工具类 ContourAnalysis.js 内部:

javascript 复制代码
async init() {
    if (typeof $arcgis !== 'undefined' && $arcgis.import) {
        // ── AMD 路径(因为 core.js 加载了,$arcgis 存在)──
        [SpatialReference] = await $arcgis.import([
            '@arcgis/core/geometry/SpatialReference.js'
        ]);
    } else {
        // ── ESM 路径(永远不会执行)──
        const mods = await import('@arcgis/core/geometry/SpatialReference.js');
        SpatialReference = mods.default;
    }
    this._spatialReference = new SpatialReference({ wkid: 4326 });
}

冲突链路

  1. core.js 加载 → 全局 $arcgis 可用 → ContourAnalysis.init() 走 AMD 路径
  2. AMD 路径获取的 SpatialReference 类 → 存储在 AMD 模块缓存中
  3. 页面 <script type="module">import SpatialReference from ... → 浏览器 ESM 模块缓存中
  4. 两个 SpatialReference不同的类实例
  5. 框架内部 Accessor#set 类型检查通过 instanceof 判断 → 检查失败

2.3 为什么 SpatialReference.WGS84 也会出问题

SpatialReference.WGS84 是一个静态 getter,返回缓存的空间参考实例。由于该类本身来自 AMD 系统,其内部缓存的 WGS84 实例携带的 VCS(垂直坐标系)属性可能为 null,导致投影引擎在调用 createProjectionTransformation() 时读取 hasVCS 失败。


三、解决过程

第 1 步:尝试修复空间参考实例

思路 :不依赖缓存单例 SpatialReference.WGS84,改为新建实例。

复制代码
SpatialReference.WGS84          →  new SpatialReference({ wkid: 4326 })
sr.isWGS84                      →  sr.wkid !== 4326

结果hasVCS 错误依旧。说明问题不在空间参考对象本身,而在投影引擎的模块系统一致性。

第 2 步:添加 try-catch 回退

思路 :在投影调用外层加 try-catch,异常时手动用 Web Mercator 数学公式转换坐标。

javascript 复制代码
try {
    geom = po.execute(geometry, this._spatialReference);
} catch (e) {
    // Web Mercator → WGS84 手动转换
    const R = 20037508.34;
    geom = { rings: geometry.rings.map(r => r.map(p => {
        return [p[0] / R * 180, 180 / Math.PI * (2 * Math.atan(Math.exp(p[1] / R * Math.PI)) - Math.PI / 2), p[2]];
    })) };
}

结果 :绕过了投影引擎的 hasVCS 错误,但紧接着触发了 instanceof 类型检查错误。验证了根因是双模块系统冲突。

第 3 步:根治方案------统一为纯 ESM 系统

思路 :移除 core.js(AMD 入口),使 $arcgis 不可用,强制所有模块走 ESM 路径。

结果:所有错误消失,功能正常运行。手动回退代码也无需触发(纯 ESM 下投影引擎本身工作正常)。


四、解决方案

4.1 核心操作

移除 AMD 入口
diff 复制代码
- <script type="module" src="../../5.0/core.js"></script>
添加 Import Map
html 复制代码
<script type="importmap">
{
    "imports": {
        "@arcgis/core/": "../../5.0/@arcgis/core/"
    }
}
</script>

4.2 修改资源引入方式

$arcgis.import() 调用替换为 ESM 静态 import 语句。

AMD 方式(修改前)

javascript 复制代码
const [Map, SceneView, GraphicsLayer] = await $arcgis.import([
    "@arcgis/core/Map.js",
    "@arcgis/core/views/SceneView.js",
    "@arcgis/core/layers/GraphicsLayer.js",
]);

ESM 方式(修改后)

由于 import map 已将 @arcgis/core/ 映射为 ../../5.0/@arcgis/core/,直接使用裸路径即可:

javascript 复制代码
import Map from '@arcgis/core/Map.js';
import SceneView from '@arcgis/core/views/SceneView.js';
import GraphicsLayer from '@arcgis/core/layers/GraphicsLayer.js';

4.3 Import Map 的关键作用

方面 说明
裸路径解析 工具类内部 import('@arcgis/core/...') 的动态导入依赖 import map 来解析裸模块标识符
模块一致性 静态 import 和动态 import() 通过 import map 解析到同一 URL → 浏览器 ESM 缓存返回同一实例
部署灵活性 无需修改工具类源码中的 @arcgis/core/ 前缀,只需调整 HTML 中的 import map

4.4 完整对比

修改前 修改后
AMD 入口 <script type="module" src="core.js"> 移除
导入方式 await $arcgis.import([...]) import X from '@arcgis/core/X.js'
裸路径解析 依赖 core.js 的 AMD 加载器 Import Map
模块系统 AMD + ESM 混用 ❌ 纯 ESM ✅
模块实例 两套缓存,类不相等 统一缓存,类唯一
投影引擎 hasVCS: null 崩溃 正常工作

相关推荐
中科GIS地理信息培训17 天前
【ArcGIS Pro 3.7新增功能4】增强空间统计中【评估点聚合的图格大小】工具:分析字段和时间间隔
人工智能·算法·arcgis
雪的季节18 天前
GIS 矢量数据格式
arcgis
非科班Java出身GISer18 天前
ArcGIS JS 基础教程(11):飞行定位 goTo
arcgis·arcgis js 飞行定位·arcgis js 定位·arcgis js 各种定位·arcgis js 飞行·arcgis js 定位到对象
我是Superman丶18 天前
前端技术手势识别
arcgis
da-peng-song21 天前
ArcGIS Desktop使用入门(四)——生成经纬度坐标
arcgis·经纬度坐标
da-peng-song21 天前
ArcGIS Desktop使用入门(三)图层右键工具——定义查询
数据库·arcgis·拆分数据·定义查询
星座52821 天前
破解水环境空间分析难题,迈向智慧水环境管理:ArcGIS水质评价、污染预测与洪水监测核心技术揭秘
arcgis·水环境·水文
非科班Java出身GISer22 天前
ArcGIS JS 基础教程(10):Camera 相机控制
arcgis·arcgis js 相机·arcgis js 相机控制·arcgis js 视角控制·arcgis js 飞行定位·arcgis js 定位·arcgis js 各种定位
码语智行23 天前
Shapefile获取空间数据和中心点坐标
java·arcgis