主站和子系统各引一份 Leaflet,地图对象认不出来
子系统单独跑正常,嵌进主站后地图能显示,调用 map.remove() 却报“不是函数”。
现象
主站用 CDN 引入了 Leaflet 1.7.1,子系统打包时又带了一份 1.9.4。
两者都挂到 window.L,后加载的覆盖先加载的。运行时报:
Uncaught TypeError: map.remove is not a function
at MapPanel.destroy (MapPanel.vue:88)
Uncaught TypeError: layer.addTo is not a function
地图本身能渲染,说明 L.map 可用;但由另一份库创建的图层,
与当前 window.L 的类不匹配,方法自然找不到。
原因
Leaflet 是 UMD 包,通过 window.L 暴露。两份副本各自定义一套类,
instanceof L.Layer 在不同副本之间为 false。
map.remove() 内部会检查图层实例的类,跨副本时判断失败。
同理,L.Icon.Default 的图标路径也会被后加载的副本覆盖,
表现为主站标记图标突然变化。
排查过程
- 在控制台比较两份库的版本:
L.version与打包进来的版本。 - 搜索 HTML 中的
leaflet.js引用与package.json中的依赖。 - 用
L.Layer === otherL.Layer验证是否为同一份实现。
console.log('global L', window.L && window.L.version);
console.log('bundle L', importedL.version);
console.log('同一个类?', window.L.Map === importedL.Map); // false
解决方案
只保留一份。主站已有 Leaflet 时,子系统通过 externals 把它指向全局变量, 不再打包副本:
// vite.config.js
export default {
build: {
rollupOptions: {
external: ['leaflet'],
output: {
globals: { leaflet: 'L' }
}
}
}
};
用 webpack 时配置 externals,效果相同:
module.exports = {
externals: {
leaflet: 'L'
}
};
反过来,如果子系统是独立打包、不依赖主站,则把主站的全局引用去掉, 统一用 npm 依赖,并在入口显式挂载一次:
import * as L from 'leaflet';
window.L = L; // 只在确认没有其他副本时挂载
var map = L.map('map').setView([39.907, 116.391], 11);
多个系统必须共存时,不要共用 window,把地图模块放进 iframe
或独立的 Web Worker 之外的沙箱容器,各自持有自己的 L:
var scope = { L: myLeaflet };
scope.L.map('sub-map').setView([39.907, 116.391], 11);
验证
window.L.Map === importedL.Map 为 true。
map.remove() 正常执行,页面卸载时地图实例被销毁。
主站与子系统的标记图标样式一致,不再被覆盖。
先数副本:在控制台执行 L.version 与打包版本对比。
两份库共存时,报错通常不是“方法不存在”,而是“类型判断失败”,
容易误判成业务代码问题。
经纬志(2026)。《主站和子系统各引一份 Leaflet,地图对象认不出来》。https://www.jingweizhi.com/cookbook/global-variable-conflict.html(访问日期 2026-11-03)。