From b97c3512ed90b584e0ba7a1cc0340101bb855968 Mon Sep 17 00:00:00 2001 From: Doxa Maps Date: Mon, 28 Sep 2026 19:56:46 +0000 Subject: [PATCH] Release both of the map's window globals, not just the remembered one MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This component publishes two: __rcmMap, the live map instance that pins the whole app at roughly 10 MB a mount, and __rcmBounds. Only the first was ever deleted, so every unmounted map left its bounds behind. The leak that gets fixed is the one you remember; the set is what actually has to be released. Both deletes are now identity-checked, for the reason the people-group grid already needed. Two of these maps can share a page — the regions chooser and a country map — and the second mount overwrites the global, so an unconditional delete on the first one's unmount would strip the second, still-live map's handle with no error anywhere. Clearing a shared global is only safe while you can prove you are the one who set it. One delete per line, so the check reads them as separate statements rather than one. --- .../src/RegionCountryMap.vue | 24 ++++++++++++++++++- public/dx-maps/doxa-maps-spa/manifest.json | 8 +++---- public/dx-maps/manifest.json | 8 +++---- .../region-dashboards/index.html | 2 +- .../regions-dashboard/regions-dashboard.js | 2 +- .../regions-dashboard/regions-list/index.html | 2 +- .../regions-dashboard/regions-mfe/index.html | 2 +- 7 files changed, 35 insertions(+), 13 deletions(-) diff --git a/plugin-designs/regions-dashboard/src/RegionCountryMap.vue b/plugin-designs/regions-dashboard/src/RegionCountryMap.vue index 440df0ae9..f2e641672 100644 --- a/plugin-designs/regions-dashboard/src/RegionCountryMap.vue +++ b/plugin-designs/regions-dashboard/src/RegionCountryMap.vue @@ -715,7 +715,29 @@ function watchResize() { ro.observe(mapContainer.value) } -onBeforeUnmount(() => { if (ro) { try { ro.disconnect() } catch (_) {} } if (popup) popup.remove(); try { delete window.__rcmMap } catch (_) {} destroy() }) +/** + * ★ RELEASE EVERY GLOBAL THIS COMPONENT SETS, AS A SET — not just the one that came to mind. + * + * Two are published: __rcmMap (the live map instance, which pins the whole app — rega measured + * ~10 MB per mount) and __rcmBounds. Only the first was ever deleted, so every unmounted map left + * its bounds behind; the leak that gets fixed is the one you remember, and the set is what the + * check looks for. + * + * ★ AND BOTH DELETES ARE IDENTITY-CHECKED, for the reason the grid already needed: two of these + * maps can share a page — the regions chooser and a country map — and the second mount overwrites + * the global. An unconditional delete on the FIRST one's unmount would then strip the SECOND, + * still-live map's handle, with no error anywhere. Clearing a shared global is only safe while you + * can still prove you are the one who set it. + * + * One delete per line, deliberately: sr's check reads them as separate statements. + */ +onBeforeUnmount(() => { + if (ro) { try { ro.disconnect() } catch (_) {} } + if (popup) popup.remove() + try { if (typeof window !== 'undefined' && window.__rcmMap === map.value) delete window.__rcmMap } catch (_) {} + try { if (typeof window !== 'undefined' && window.__rcmBounds === props.bounds) delete window.__rcmBounds } catch (_) {} + destroy() +}) watch(() => [props.countryCodes, props.bounds, props.center, props.zoom, props.points, props.colorMode, props.highlightRegion], applySubject, { deep: true }) diff --git a/public/dx-maps/doxa-maps-spa/manifest.json b/public/dx-maps/doxa-maps-spa/manifest.json index d7feb7f0a..f8100e5a9 100644 --- a/public/dx-maps/doxa-maps-spa/manifest.json +++ b/public/dx-maps/doxa-maps-spa/manifest.json @@ -1080,7 +1080,7 @@ "bundle": "regions-dashboard", "scriptUrl": "./regions-dashboard/regions-dashboard.js", "output": "dx-maps/regions-dashboard/regions-dashboard.js", - "integrity": "sha384-Y2zDvJvo/WXHjIvwdvxG0ir3G1mdXatHdyi6EvHWdr+/8yTl4D8TxWQtT9TYF5Pz", + "integrity": "sha384-vBU9kwruSBwjsHpUaw/esnUnJQKv2mbVbVLaZFHF2t7O9ZnLmR8r6MrbYATplAPC", "elements": [ "regions-dashboard" ], @@ -1103,7 +1103,7 @@ "scriptUrl": "./regions-dashboard/regions-dashboard.js", "embed": { "iframe": "", - "script": "\n\n\n\n\n" + "script": "\n\n\n\n\n" } }, { @@ -1119,7 +1119,7 @@ "scriptUrl": "./regions-dashboard/regions-dashboard.js", "embed": { "iframe": "", - "script": "\n\n\n" + "script": "\n\n\n" } }, { @@ -1135,7 +1135,7 @@ "scriptUrl": "./regions-dashboard/regions-dashboard.js", "embed": { "iframe": "", - "script": "\n\n\n\n\n" + "script": "\n\n\n\n\n" } } ] diff --git a/public/dx-maps/manifest.json b/public/dx-maps/manifest.json index d7feb7f0a..f8100e5a9 100644 --- a/public/dx-maps/manifest.json +++ b/public/dx-maps/manifest.json @@ -1080,7 +1080,7 @@ "bundle": "regions-dashboard", "scriptUrl": "./regions-dashboard/regions-dashboard.js", "output": "dx-maps/regions-dashboard/regions-dashboard.js", - "integrity": "sha384-Y2zDvJvo/WXHjIvwdvxG0ir3G1mdXatHdyi6EvHWdr+/8yTl4D8TxWQtT9TYF5Pz", + "integrity": "sha384-vBU9kwruSBwjsHpUaw/esnUnJQKv2mbVbVLaZFHF2t7O9ZnLmR8r6MrbYATplAPC", "elements": [ "regions-dashboard" ], @@ -1103,7 +1103,7 @@ "scriptUrl": "./regions-dashboard/regions-dashboard.js", "embed": { "iframe": "", - "script": "\n\n\n\n\n" + "script": "\n\n\n\n\n" } }, { @@ -1119,7 +1119,7 @@ "scriptUrl": "./regions-dashboard/regions-dashboard.js", "embed": { "iframe": "", - "script": "\n\n\n" + "script": "\n\n\n" } }, { @@ -1135,7 +1135,7 @@ "scriptUrl": "./regions-dashboard/regions-dashboard.js", "embed": { "iframe": "", - "script": "\n\n\n\n\n" + "script": "\n\n\n\n\n" } } ] diff --git a/public/dx-maps/regions-dashboard/region-dashboards/index.html b/public/dx-maps/regions-dashboard/region-dashboards/index.html index f634fe911..1986399a8 100644 --- a/public/dx-maps/regions-dashboard/region-dashboards/index.html +++ b/public/dx-maps/regions-dashboard/region-dashboards/index.html @@ -36,7 +36,7 @@ - + - + - +