CRUMB a card from devarno-cloud

Vite Glob Bundle-Time Data Loading

meridian intermediate 5 min read

ELI5

Instead of opening a file drawer every time someone asks for a recipe, the kitchen tapes every recipe to the wall before the restaurant opens. Once service starts, cooks read the wall — they never touch the drawer.

Technical Deep Dive

src/lib/units.ts and src/lib/doctrines.ts use Vite’s import.meta.glob to bundle workspace YAML at build time. There is no runtime filesystem access — important because the Vercel adapter runs in a server runtime where the source tree is not present.

Glob Patterns Used

const unitYamlFiles = import.meta.glob<{ default: string }>(
"../../../../packages/units/**/*.yaml",
{ query: "?raw", eager: true }
);
const councilYamlFiles = import.meta.glob<{ default: string }>(
"../../../../councils/*/council.yaml",
{ query: "?raw", eager: true }
);
const spritePngFiles = import.meta.glob<{ default: string }>(
"../../../../councils/*/sprites/*.png",
{ query: "?url", eager: true }
);
const spriteSvgFiles = import.meta.glob<{ default: string }>(
"../../../../councils/*/sprites/*.svg",
{ query: "?raw", eager: true }
);

Build-Time Wiring

flowchart LR
SRC[packages/units/**/*.yaml<br/>councils/**/sprites/*<br/>.opencode/doctrines/*.doctrine.md] --> VITE[Vite import.meta.glob<br/>eager:true]
VITE -->|?raw| TEXT[bundled string modules]
VITE -->|?url| ASSET[fingerprinted asset URLs]
TEXT --> PARSE[parseUnit / parseCouncil / parseDoctrineFile]
ASSET --> SPRITE[ResolvedVisual content]
PARSE --> LOADER[loadAllUnits / loadAllCouncils]
SPRITE --> LOADER
LOADER --> PAGE[Astro pages and API endpoints]

Query Flag Semantics

FlagResult
?rawThe file’s text content is inlined as the module default export
?urlA fingerprinted asset URL string is the default export

PNGs use ?url because they should be served as binary assets through Astro’s asset pipeline. SVGs use ?raw because ResolvedVisual.content carries the SVG markup itself for inlining into the orbital renderer.

Eager vs Lazy

eager: true resolves every match at module-import time, producing synchronous access. Lazy globs return functions returning Promises — fine for code-splitting routes, wrong for data that every page depends on. The orchestrator’s metric and graph builders treat loadAllUnits() as synchronous; lazy loading would cascade await through buildOrbitalData, buildGraphData, computeProtocolMetrics.

Key Terms

  • import.meta.glob → Vite primitive for compile-time directory matching.
  • ?raw → Vite query suffix returning the raw text of the matched file.
  • ?url → Vite query suffix returning a public asset URL (with content hashing).
  • Workspace YAML → Source of truth for units, councils, doctrines; lives outside apps/meridian/src.

Q&A

Q: What if a new unit YAML is added after astro build runs? A: It is invisible until the next build. Bundling is at build time; Vercel deploys are immutable, so a redeploy is required.

Q: Why not just fs.readdirSync at module init? A: Astro on Vercel runs server functions where the workspace tree is not present at runtime. The function bundle only contains what Vite included — if it was not globbed, it does not exist on the server.

Q: Why are large external deps like yjs, zod, blake3-wasm listed as external? A: Same file (astro.config.mjs) — keeping them external avoids bundling them twice and lets the runtime resolve the npm copy. Globbing covers source data, externalisation covers npm dependencies.

Examples

Adding a new council:

  1. Drop councils/<name>/council.yaml and any sprites into the workspace.
  2. The next astro build re-evaluates the globs; the council appears in loadAllCouncils(), in buildOrbitalData, and on /councils/<name>/.
  3. No code change in meridian itself — the glob pattern already matched the new path.

neighbors on the map