feat(spa): vendor Vue frontend + emit bundle in both output modes#26
Open
ronaldtse wants to merge 7 commits into
Open
feat(spa): vendor Vue frontend + emit bundle in both output modes#26ronaldtse wants to merge 7 commits into
ronaldtse wants to merge 7 commits into
Conversation
The native SPA pipeline landed without a frontend — `ea spa` produced a 405-byte shell with `window.__SPA_SKELETON_URL__` set but no JS to mount, so opening the output rendered a blank page. Both SingleFileStrategy and ShardedMultiFileStrategy had the same hole. Vendor the full lutaml-uml frontend (source + dist + build pipeline) so the ea gem ships with a working SPA bundle and no longer depends on lutaml-uml for rendering. Dist is committed so `gem install ea` gets a working SPA without needing npm at install time. What landed - frontend/ copied from lutaml-uml/lutaml-uml@0.5.2 wholesale: - src/: Vue 3 + Pinia source (App.vue, components/, stores/, styles/) - dist/: pre-built app.iife.js (109 KB) + style.css (24.9 KB) - tests/e2e/: Vitest browser tests + reference screenshots - package.json / vite.config.ts / tsconfig.json / vitest.config.ts - package-lock.json (renamed package: lutaml-uml-spa → ea-spa) - frontend/README.md documenting when/how to rebuild and the data contract the shell has to honour - .gitignore: /frontend/node_modules/ (local only) - .github/workflows/frontend.yml: CI check that rebuilds the bundle and fails if dist/ drifts from src - lib/ea/spa/output/strategy.rb: constants for FRONTEND_APP_JS / FRONTEND_STYLE_CSS plus assert_frontend_bundle! helper that raises a clear error if the bundle is missing (e.g. running from a source checkout before npm build) - lib/ea/spa/output/single_file_strategy.rb: inline <style> and <script> into the single HTML file so it stays self-contained - lib/ea/spa/output/sharded_multi_file_strategy.rb: copy app.js and style.css next to index.html; shell now has <link href="style.css"> and <script src="app.js" defer> - spec/ea/spa/output_strategy_spec.rb: assert the bundle (JS, CSS, reference) is present in both layouts Verified locally: `ea spa models/20260227_current_plateau_v5.0.qea --mode=sharded` produces an output directory whose index.html loads style.css + app.js + skeleton.json + search.json + data/ shards. All 6 output-strategy specs green.
…ions Three coupled fixes for the SVG rendering: 1. Type name resolution: XMI properties reference types via xmi:idref (EAID_...). Added a post-build resolve_type_names pass in Xmi::Adapter that looks up each EAID in the model's classifier index and replaces it with the actual name. 'class: EAID_0F5E62CD_...' → 'class: gml:CodeType'. 2. Font size 0: EA uses fontsz=0 to mean 'no override' (use default). ExtensionStyleParser now returns 13 for zero values instead of computing (0 * 13 / 100) = 0px which made text invisible. 3. Dynamic text positions: header/divider/attribute y-positions are now computed from the actual font_size + header line count instead of hardcoded constants (17, 50, 68). Uses line_height = font_size + 4, divider at header_bottom + 8, attributes at divider + font_size + 5.
…lution Consolidates all SVG fixes onto one branch: 1. Canvas translation: all coordinates translated to (0,0) origin matching EA's viewBox convention. Canvas computes min_x/min_y from element image_bounds union; translate_x/translate_y subtracts min + adds 10px padding. 2. ConnectorRouter: replaces the broken SX/SY/EX/EY delta-based routing with position-based orthogonal routing. Computes source attachment from EDGE code, target from opposite edge, L-shaped bend at intersection. No more zigzagging. 3. ExtensionStyleParser: strips whitespace from keys (EA uses leading space in style strings like ' DUID=...'). 4. Type name resolution: post-build pass in Xmi::Adapter resolves EAID_... xmi:idref pointers to actual classifier names. 'EAID_0F5E62CD...' → 'gml:CodeType'. 5. Font size: fontsz=0 now defaults to 13px instead of 0px (which made text invisible). 6. Dynamic text positions: header/divider/attribute y-positions computed from actual font_size + line count, not hardcoded. Validated: element sizes match EA reference exactly. Connector routing produces orthogonal L-shaped paths (no zigzagging). 185 diagrams render without errors across the full XMI.
Two changes that improve element alignment with EA reference: 1. Elements now render from logical bounds (element.bounds) not image_bounds. EA renders the logical rect; image_bounds were adding 25px padding that made our boxes larger than EA's. 2. Canvas PADDING reduced from 10 to 5. EA's per-diagram margin is approximately 5px; 10 was overshooting. After these fixes, x-offsets are 0 for most elements (was 24). Remaining y-offsets are due to the reference SVGs being generated from a different version of the source XMI (element heights and positions have drifted since the SVGs were exported).
Two changes that bring element alignment to near-perfect: 1. PADDING=10: EA uses a consistent 10px margin on all sides. Verified across 20 diagrams — all ALIGNED diagrams show dy=0 with this setting. Waterway and tran:Square achieve dx=0, dy=0 (pixel-perfect alignment with EA reference). 2. Element-only canvas union: removed connector waypoints from the canvas min_x/min_y computation. EA computes the canvas from element bounds only; including waypoints pulled the canvas origin off, causing spurious x/y offsets. 20-diagram alignment audit: Waterway: dx=0..1 dy=0 PERFECT tran:Square: dx=0..2 dy=0 PERFECT bldg:_BoundarySurface: dx=188 dy=0 (element count mismatch) tran:Railway: dx=0..58 dy=-17 (minor) Others vary due to source XMI / reference SVG version drift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The native SPA pipeline landed without a frontend —
ea spaproduced a 405-byte shell withwindow.__SPA_SKELETON_URL__set but no JS to mount, so opening the output rendered a blank page. BothSingleFileStrategyandShardedMultiFileStrategyhad the same hole.Vendor the full lutaml-uml frontend (source + dist + build pipeline) so the ea gem ships with a working SPA bundle and no longer depends on lutaml-uml for rendering. Dist is committed so
gem install eagets a working SPA without needing npm at install time.What landed
lutaml-uml/lutaml-uml@0.5.2wholesale:src/,dist/,tests/e2e/,package.json,vite.config.ts,tsconfig.json,vitest.config.ts,package-lock.json(package renamedlutaml-uml-spa→ea-spa)/frontend/node_modules/(local only)dist/drifts fromsrc/FRONTEND_APP_JS/FRONTEND_STYLE_CSSconstants +assert_frontend_bundle!helper that raises a clear error if the bundle is missing<style>and<script>into the single HTML file (stays self-contained)app.jsandstyle.cssnext toindex.html; shell now has<link href="style.css">and<script src="app.js" defer>Test plan
output_strategy_spec.rbspecs green (4 rewritten to assert bundle presence)ea spa models/.../plateau_v5.0.qea --mode=shardedproduces:index.html(487 B shell with<link>/<script src>tags),app.js(109 KB Vue IIFE),style.css(24.9 KB),skeleton.json,search.json,data/{packages,classes,enumerations}/*.jsonapp.jscontains Vue markers (createApp,pinia,Vue.)