isMap per profile: a map-less leaf no longer bakes, or preloads, a map engine it never uses
generate-tree decided a single leaf's map-ness as "its own .vue
references an engine OR anything under the BUNDLE's src/ does", so a
map-less profile inherited it from a sibling. regions-dashboard/
regions-list shows a list and no map, but src/RegionCountryMap.vue made
it isMap=true. Its leaf loaded the Mapbox engine for nothing, and since
4a6886d2 its embed snippet also preloaded it.
A leaf's map-ness now follows the RELATIVE imports reachable from its
own .vue, bounded to its bundle, so a map several imports deep
(research-dashboard's DashboardMapPanel) still counts. An explicit
boolean isMap in <profile>.meta.json wins. Composites keep their
separate rule, since they do mount their siblings.
Measured: across all 34 profiles exactly one changed (regions-list,
true -> false). 18 map profiles keep isMap and their preload; 0 non-map
snippets carry one. On a served built tree regions-list makes 0 engine
requests and 0 api.mapbox.com requests and renders its list (673
elements, no errors), where before it downloaded the 1.75 MB engine.
regions-mfe still loads the engine and draws its map. The regenerated
files are only the regions-list leaf, the two manifest copies (still
byte-identical), the staging page and the gallery; check:sri passes.
This commit is contained in:
parent
da8bc790b8
commit
413fa30d19
6 changed files with 56 additions and 18 deletions
|
|
@ -271,6 +271,47 @@ function ownsAMapDeeply(profileDir) {
|
|||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Does THIS PROFILE reach a map through its own import graph?
|
||||
*
|
||||
* ★ PER PROFILE, NOT PER BUNDLE (BUG-FALSE-ISMAP-BAKES-403KB-MAPBOX-INTO-MAPLESS-LEAVES, fixed
|
||||
* 2026-09-25). ownsAMapDeeply() answers "is there a map ANYWHERE under this bundle's src/", and the
|
||||
* single-leaf branch used it for every profile — so a map-less sibling inherited map-ness from the
|
||||
* bundle: regions-dashboard/regions-list shows a list and no map, but src/RegionCountryMap.vue made
|
||||
* it isMap=true. Its leaf then baked the ~400 KB Mapbox engine it never uses, and since 4a6886d2 its
|
||||
* embed snippet also preloaded it. This follows the RELATIVE imports reachable from the profile's
|
||||
* own .vue (bounded to the bundle folder, .vue/.js/.mjs), so research-dashboard — whose map sits
|
||||
* several imports deep in src/components/dashboards/DashboardMapPanel.vue — still resolves true.
|
||||
* An explicit boolean `isMap` in <profile>.meta.json wins over the scan.
|
||||
*/
|
||||
const RELATIVE_IMPORT_RE = /(?:import[^'"`;]*?from\s*|import\s*\(\s*|import\s+)['"`](\.{1,2}\/[^'"`]+)['"`]/g
|
||||
function profileReachesAMap(dir, file) {
|
||||
const seen = new Set()
|
||||
const stack = [join(dir, file)]
|
||||
while (stack.length) {
|
||||
const f = stack.pop()
|
||||
if (seen.has(f)) continue
|
||||
seen.add(f)
|
||||
let src
|
||||
try { src = readFileSync(f, 'utf8') } catch { continue }
|
||||
if (MAP_ENGINE_RE.test(src)) return true
|
||||
for (const m of src.matchAll(RELATIVE_IMPORT_RE)) {
|
||||
const base = resolve(dirname(f), m[1])
|
||||
if (!base.startsWith(dir)) continue // stay inside this bundle
|
||||
for (const cand of [base, base + '.vue', base + '.js', base + '.mjs', join(base, 'index.js')]) {
|
||||
if (NESTED_SCAN_EXT.test(cand) && existsSync(cand) && statSync(cand).isFile()) { stack.push(cand); break }
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
function metaIsMap(dir, profileName) {
|
||||
try {
|
||||
const meta = JSON.parse(readFileSync(join(dir, `${profileName}.meta.json`), 'utf8'))
|
||||
return typeof meta?.isMap === 'boolean' ? meta.isMap : null
|
||||
} catch { return null }
|
||||
}
|
||||
|
||||
/**
|
||||
* Does a cap-4 composite (`nested-elements-mfe`) compose a child that paints a map?
|
||||
*
|
||||
|
|
@ -1206,7 +1247,7 @@ function scanBundles() {
|
|||
? false
|
||||
: profileType === 'nested-elements-mfe'
|
||||
? composesAMapLeaf(dir, profileName, file)
|
||||
: (isMapLeaf(join(dir, file)) || ownsAMapDeeply(dir))
|
||||
: (metaIsMap(dir, profileName) ?? profileReachesAMap(dir, file))
|
||||
|
||||
return {
|
||||
profile: profileName,
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
8
public/doxa-maps/doxa-maps-spa/manifest.json
generated
8
public/doxa-maps/doxa-maps-spa/manifest.json
generated
|
|
@ -837,7 +837,7 @@
|
|||
"bundle": "pplr-data-maps",
|
||||
"scriptUrl": "./pplr-data-maps/pplr-data-maps.js",
|
||||
"output": "doxa-maps/pplr-data-maps/pplr-data-maps.js",
|
||||
"integrity": "sha384-7Fp8ORq9SNmtZLwCG1euRM+dGy6sDgD/+Ts4s1B1WVk8XKuMJpYr3dCjoK80zvJp",
|
||||
"integrity": "sha384-+EOcMT3P42D39HGIjZBbJ6waYI2yJDhNDwNf+8wFruaHqEhdYYa36M+iLIT5fRiH",
|
||||
"elements": [
|
||||
"pplr-data-maps"
|
||||
],
|
||||
|
|
@ -853,7 +853,7 @@
|
|||
"scriptUrl": "./pplr-data-maps/pplr-data-maps.js",
|
||||
"embed": {
|
||||
"iframe": "<iframe src=\"./pplr-data-maps/pplr-data-maps/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
|
||||
"script": "<!-- Mapbox engine, fetched early; remove this line if you set \"provider\":\"maplibre\" -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./pplr-data-maps/pplr-data-maps.js\" integrity=\"sha384-7Fp8ORq9SNmtZLwCG1euRM+dGy6sDgD/+Ts4s1B1WVk8XKuMJpYr3dCjoK80zvJp\" crossorigin=\"anonymous\"></script>\n<pplr-data-maps profile-config='{\"profile\":\"pplr-data-maps\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></pplr-data-maps>"
|
||||
"script": "<!-- Mapbox engine, fetched early; remove this line if you set \"provider\":\"maplibre\" -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./pplr-data-maps/pplr-data-maps.js\" integrity=\"sha384-+EOcMT3P42D39HGIjZBbJ6waYI2yJDhNDwNf+8wFruaHqEhdYYa36M+iLIT5fRiH\" crossorigin=\"anonymous\"></script>\n<pplr-data-maps profile-config='{\"profile\":\"pplr-data-maps\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></pplr-data-maps>"
|
||||
},
|
||||
"bundle": "pplr-data-maps"
|
||||
}
|
||||
|
|
@ -917,12 +917,12 @@
|
|||
"description": "A refactor of DX-life's /regions index page (app/pages/regions/index.vue) into",
|
||||
"element": "regions-dashboard",
|
||||
"type": "single",
|
||||
"isMap": true,
|
||||
"isMap": false,
|
||||
"iframeUrl": "./regions-dashboard/regions-list/index.html",
|
||||
"scriptUrl": "./regions-dashboard/regions-dashboard.js",
|
||||
"embed": {
|
||||
"iframe": "<iframe src=\"./regions-dashboard/regions-list/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
|
||||
"script": "<!-- Mapbox engine, fetched early; remove this line if you set \"provider\":\"maplibre\" -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-bt2/psRmAJTmO9mm3KULoLN7GSzcxwIeOTbVwIvSkMZOqyzaU5pOt7G0r2w8ir9r\" crossorigin=\"anonymous\"></script>\n<regions-dashboard profile-config='{\"profile\":\"regions-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-bt2/psRmAJTmO9mm3KULoLN7GSzcxwIeOTbVwIvSkMZOqyzaU5pOt7G0r2w8ir9r\" crossorigin=\"anonymous\"></script>\n<regions-dashboard profile-config='{\"profile\":\"regions-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
|||
2
public/doxa-maps/index.html
generated
2
public/doxa-maps/index.html
generated
File diff suppressed because one or more lines are too long
4
public/doxa-maps/manifest.json
generated
4
public/doxa-maps/manifest.json
generated
|
|
@ -917,12 +917,12 @@
|
|||
"description": "A refactor of DX-life's /regions index page (app/pages/regions/index.vue) into",
|
||||
"element": "regions-dashboard",
|
||||
"type": "single",
|
||||
"isMap": true,
|
||||
"isMap": false,
|
||||
"iframeUrl": "./regions-dashboard/regions-list/index.html",
|
||||
"scriptUrl": "./regions-dashboard/regions-dashboard.js",
|
||||
"embed": {
|
||||
"iframe": "<iframe src=\"./regions-dashboard/regions-list/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
|
||||
"script": "<!-- Mapbox engine, fetched early; remove this line if you set \"provider\":\"maplibre\" -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-bt2/psRmAJTmO9mm3KULoLN7GSzcxwIeOTbVwIvSkMZOqyzaU5pOt7G0r2w8ir9r\" crossorigin=\"anonymous\"></script>\n<regions-dashboard profile-config='{\"profile\":\"regions-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-bt2/psRmAJTmO9mm3KULoLN7GSzcxwIeOTbVwIvSkMZOqyzaU5pOt7G0r2w8ir9r\" crossorigin=\"anonymous\"></script>\n<regions-dashboard profile-config='{\"profile\":\"regions-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,13 +5,10 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>regions-list · regions-dashboard</title>
|
||||
<link rel="icon" href="data:,">
|
||||
<!-- Mapbox peer loaded ONCE here; the map custom element mounts in this page and
|
||||
uses window.mapboxgl directly (same realm → no cross-realm container errors). -->
|
||||
<link rel="preconnect" href="https://api.mapbox.com" crossorigin />
|
||||
<link href="https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.css" rel="stylesheet" />
|
||||
<link href="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v5.0.0/mapbox-gl-geocoder.css" rel="stylesheet" />
|
||||
<script src="https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js"></script>
|
||||
<script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v5.0.0/mapbox-gl-geocoder.min.js"></script>
|
||||
<!-- NON-MAP leaf (app-shell / composite / grid / card / chart-table): NO map peer.
|
||||
This element draws no map tiles, so it needs no Mapbox/MapLibre engine and MUST NOT
|
||||
gate on a token. Any nested MAP (in a composite/shell) renders in its own iframe leaf,
|
||||
which loads its own map peer + token. A peer here would be dead weight + imply a gate. -->
|
||||
<style>
|
||||
/* BARE full-page map — no chrome. The custom element IS the page, so the
|
||||
browser URL shares the map itself. */
|
||||
|
|
@ -25,7 +22,7 @@
|
|||
</head>
|
||||
<body>
|
||||
<div id="slot"></div>
|
||||
<div id="status">loading token…</div>
|
||||
<div id="status">loading…</div>
|
||||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <regions-dashboard> custom element. -->
|
||||
|
|
@ -48,7 +45,7 @@
|
|||
var BASE_CONFIG = {"pinHint":false,"profile":"regions-list","dataSource":"pray-tools","instanceId":"regions-dashboard-regions-list","assetsBase":"../../assets"};
|
||||
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
|
||||
// the ladder below is skipped entirely and the element mounts immediately.
|
||||
var TOKEN_FREE = false;
|
||||
var TOKEN_FREE = true;
|
||||
// A token-free COMPOSITE still nests plugins, and a nested Mapbox map reads window.MAP_TOKEN
|
||||
// rather than this page's profile-config. With no baked token (the public copy), it must get
|
||||
// one from ?tk= or a pasted token, or be asked for one — see the rungs below.
|
||||
|
|
|
|||
Loading…
Reference in a new issue