doxa-maps/plugin-designs/plugin-studio/index.js
Doxa Maps d0939c0492 library: one embedScript for the app shells, replacing four private copies
DEDUP-AUDIT.md (measured today: 253 files, 31 cross-plugin duplicate clusters,
622 duplicated lines) ranks this tenth by raw cost and first by suitability. It
is the only cluster where the copies are identical in code, close over nothing,
and sit in two plugins with one owner between them.

loadScriptOnce (13 lines) and whenTagDefined (11) were byte-identical between
doxa-maps-spa and plugin-studio. deriveTreeBase (9) differed by ONE COMMENT LINE
and not one character of code -- drift in the documentation of a shared function,
which is its own argument for having one copy.

They are one concern, not three: load a bundle's script once, wait for its custom
element to register, and work out the tree base to load it from. That is what a
capability-5 app shell does to nest another plugin, and both plugins here ARE the
capability-5 shells. Any future shell needs the same three.

Verbatim move: no parameterisation, no behaviour change, callers import instead
of declaring. The comments travel with the code because each records a
measurement -- particularly the one explaining why onload is not a usable success
signal for a dev-server ES module.

ONE BEHAVIOUR CHANGE, AND IT IS AN IMPROVEMENT: the _loaded cache is now shared.
Two shells on one page previously kept separate caches and each loaded the same
bundle; the second now reuses the first's promise.

deriveTreeBase reads document.currentScript, so it is only valid AT MODULE
EVALUATION TIME. The call sites did not move -- both entries still call it at
module top level -- and the library file documents the constraint, because a
later call silently returns '' and every nested bundle URL would break.

Verified: both bundles build; each built file contains all three functions
exactly once and still derives currentScript; check:sri, check:series-isolation,
check:studio-rail and check:capability-derived all PASS.

library/utils/embedScript.js is the build owner's under rule 5B. The
plugin-designs and public/ changes are in the same commit because they import it
-- landing them apart breaks the build in between.
2026-09-28 07:07:33 +00:00

54 lines
2.8 KiB
JavaScript

/**
* plugin-studio / index.js — Bundle entry (Capability-5 nested-mfe-spa / app-shell).
*
* ONE folder -> ONE bundle -> ONE custom element: <plugin-studio>.
*
* <plugin-studio> is the DEVELOPER STUDIO of the whole DX-maps system: a vertical-tab layout whose
* sidebar is the composability ladder grouped by CAPABILITY (5 -> 1); each row nests that element
* (token-free elements mounted directly by their real tag; map elements nested as their own SPA in
* a lazy iframe) with its embed snippet. It is the spot to SEE every plugin element work and review
* it. See plugin-studio.vue for the full why.
*
* ★ WHY AN ELEMENT (not an index.html page): every plugin in this system is a compiled Vue custom
* element so it supports all five deployment methods and can compose. The studio is a plugin, so
* it is a real element too. A page could only be iframed and could never be nested as a tab of
* another cap-5 shell.
*
* ★ ONE-SHOT-DEFINE SAFETY: the ONLY tag this bundle registers is <plugin-studio>. It NEVER
* imports another plugin's components and NEVER re-registers a tag another bundle owns. The
* nested elements register their own tags when THEIR IIFE loads (direct-mount rows) or run in
* their own document (iframe rows). So loading this bundle beside any other can never collide.
*
* ★ TREE BASE: to find each element's built .js / leaf page + the manifest, the shell needs the
* built tree's root URL. We derive it HERE, at IIFE load, from this script's own URL
* (.../doxa-maps/plugin-studio/plugin-studio.js) -> two levels up = the tree root. Provided to
* the Vue app; a host can override with tree-base="" or profile-config.treeBase.
*
* Usage from a host page (direct-JS, deploy-method-3):
* <script src="/doxa-maps/plugin-studio/plugin-studio.js"></script>
* <plugin-studio></plugin-studio>
* <!-- or pin the tree explicitly: -->
* <plugin-studio tree-base="https://your-host/doxa-maps"></plugin-studio>
*/
import { defineCustomElement } from 'vue'
import PluginStudio from './plugin-studio.vue'
import { deriveTreeBase } from '@map/utils/embedScript.js'
// Capture the running <script>'s own URL synchronously at IIFE load, BEFORE any async runs, so
// document.currentScript is still this bundle's tag. Derive the tree root = two levels up
// (.../doxa-maps/plugin-studio/plugin-studio.js -> .../doxa-maps/). Guarded for non-browser.
const TREE_BASE = deriveTreeBase()
const PluginStudioElement = defineCustomElement(PluginStudio, {
configureApp(app) {
// Hand the derived tree root to the component (props/attrs still override it).
app.provide('psTreeBase', TREE_BASE)
}
})
if (typeof customElements !== 'undefined' && !customElements.get('plugin-studio')) {
customElements.define('plugin-studio', PluginStudioElement)
}
export default PluginStudioElement