doxa-maps/plugin-designs/stack-demo/stack-demo.vue
doxa-maps-88655c70 5725f5b9d9
Some checks are pending
build-gate / build (push) Waiting to run
Let a stacked composite find its siblings in either tree
stack-demo rendered two empty sections in dev. Its sibling bundles were addressed with
a tree-relative path, which the browser resolves against the document URL, so no host
and no attribute can redirect it — correct in the built tree, a 404 in dev. Measured:
the dev entry answers 200 while the path the relative form resolves to answers 404. The
sources now resolve at runtime, so the same file is right in both trees, and the
production branch compiles away to the string it replaces.

That was the third place this defect appeared. Both capability-5 shells carried the same
hardcoded paths and were cured the same way, and each instance was found separately
after the previous one was fixed — because a literal parent-directory path reads as
correct in review and is invisible to a gate that only ever checks the built tree.

Removing the 404 was not enough: the sections were still empty with zero failed
requests. The shared layout injected each bundle with a classic script, and a classic
script pointed at a dev ES module fires its load handler successfully and only then
throws, so the promise resolved while the tag never registered and the wait for
definition quietly timed out. A load handler cannot detect that.

The module rule now lives in the shared layout rather than in a fourth private copy of
the same loader, so the two other composites that inject through it are covered too.
Verified after: both elements define, sixty-six facet rows and twenty-four cards on
stack-demo and on dashboard-plus-grid, zero failed requests on each.
2026-09-22 15:37:41 +00:00

89 lines
4.8 KiB
Vue

<script setup>
/**
* stack-demo.vue — Capability-4 composite demonstrating the shared StackLayout (scroll-stack).
*
* @element stack-demo
* @description Groups TWO independent elements TOP-TO-BOTTOM so you can embed the pair on a page and
* SCROLL down through all of it (the doxa-life / nuxtinator page-flow model), instead of switching
* between them with tabs. Section 1 = the rich <research-dashboard-map> (facets + map + charts +
* table); section 2 = the cap-2 <people-groups-grid> (live pray.doxa.life). Each renders at its
* NATURAL height; the host page scrolls.
*
* This is the STACK counterpart to big-picture (which TABS/couples). Both reuse the shared library
* layouts in library/layouts/. StackLayout mounts each section's `element` eagerly (all visible to
* scroll) via the same element/src/attrs contract VerticalTabsLayout uses.
*/
import StackLayout from '@map/layouts/StackLayout.vue'
// The two elements to stack. `src` is TREE-RELATIVE at build; the leaf pages resolve it against the
// bundle tree root. Both elements ship their own bundles in the same catalog.
// ── WHERE A SIBLING BUNDLE LIVES DEPENDS ON WHICH TREE IS SERVING ────────────────────────────
// A tree-relative src is resolved by the BROWSER against the document URL, so no attribute and no
// host can redirect it — which makes it correct in exactly one tree and a 404 in the other.
// BUILT: this leaf is served two levels deep (doxa-maps/stack-demo/stack-demo/index.html), so a
// sibling bundle is '../../<bundle>/<bundle>.js'.
// DEV: the dev server serves SOURCE, and a bundle's entry is '/plugin-designs/<bundle>/index.js'.
// MEASURED 2026-09-22 against the running dev server:
// GET /plugin-designs/research-dashboard/index.js ........... 200
// GET /research-dashboard/research-dashboard.js ............. 404 <- what '../../' resolves to
// So stack-demo took 2 x 404 and rendered empty sections in dev, with no console error and no failed
// mount — the sections simply never got their element. Confirmed PRE-EXISTING and reproducible on this
// bundle's own standalone leaf, independent of any composite that nests it.
//
// ★ THIS IS THE THIRD PLACE THIS EXACT DEFECT APPEARED. plugin-studio and doxa-maps-spa both carried
// hardcoded tree-relative paths and both were cured the same way: resolve at RUNTIME from something
// that knows which tree is serving, rather than baking one tree's shape into a string. Each instance
// was found separately, after the previous one was "fixed", because a literal '../..' looks correct
// in review and is invisible to a gate that only ever checks the built tree (check:composite-srcs
// PASSES on this file today, for precisely that reason).
//
// import.meta.env.DEV is statically replaced at build time, so the production branch is the only one
// that survives into the IIFE — the built output is byte-identical to the hardcoded form it replaces.
const bundleSrc = (bundle, file) =>
import.meta.env.DEV ? `/plugin-designs/${bundle}/index.js` : `../../${bundle}/${file}.js`
const sections = [
{
key: 'dashboard',
title: 'Research Dashboard',
sub: 'facets · map · charts · table (live)',
element: 'research-dashboard-map',
src: bundleSrc('research-dashboard', 'research-dashboard'),
// ★ REQUIRED, and its absence was a live defect (found + fixed 2026-09-22). research-dashboard's
// entry mounts ProfileLoader, which reads profile-config.profile to choose WHICH .vue to load.
// With none, the element still mounted at its full 844px and still reported its tag — so every
// structural check said "present" — while ProfileLoader rendered "missing or invalid
// profile-config prop" where the dashboard should be. The grid section below was fine, which is
// what made it survive: half the page worked.
// Shape copied verbatim from this bundle's own generated leaf (its BASE_CONFIG), so the nested
// and standalone mounts ask for the identical thing. Now gated by check:composite-srcs.
attrs: {
'profile-config': JSON.stringify({
profile: 'research-dashboard',
dataSource: 'pray-tools',
instanceId: 'stack-demo-research-dashboard',
assetsBase: '../../assets'
})
}
},
{
key: 'grid',
title: 'People Groups',
sub: 'the full searchable list (live)',
element: 'people-groups-grid',
src: bundleSrc('people-groups-grid', 'people-groups-grid')
}
]
</script>
<template>
<StackLayout title="Stacked view" :sections="sections">
<template #meta>scroll ↓</template>
</StackLayout>
</template>
<style>
/* stack-demo is a thin composition: the shell + its scroll behaviour live in the shared StackLayout
(which self-injects its own shadow CSS). Nothing to add here beyond making the host fill width. */
:host { display:block; width:100%; }
</style>