Skip to content

Macros

The import.meta.og surface

One compile-time namespace for the things ogygia can settle at build time. Each call looks like runtime code, but it runs during the build, can see the module graph, and inlines its result. This page covers the rules they share, and each macro has its own page.

On this page

Some of what an app does never changes between requests: which markdown files exist, how a class crosses an island boundary, what a code sample looks like once highlighted, or the nav tree computed from a corpus. That work belongs in the build rather than in every request, and import.meta.og.* is where ogygia puts it.

Everything under import.meta.og is a compile-time construct. It reads like a normal call, but the ogygia Vite plugin rewrites it at build time, before your code runs, and there is no import.meta.og object at runtime. If a construct ever reached the browser without being rewritten, it would throw on its first line rather than half-work.

The family

ConstructTurns into
loader.markdown/folder/json/gita content source for content({ loader })
code(source, lang, meta?)a highlighted snippet, baked to a static region
md(text)a Markdown string, rendered to a static region
regions(glob)a block registry from a folder
asRegion(Comp, options)any imported component (named / barrel) marked a region
wire({ encode, decode })the transportable-codec key on a class
bake(fn)the result of running fn at build, inlined

Why it looks like import.meta.glob

These constructs live on import.meta because they behave like Vite’s own import.meta.glob, which is a call that never runs and that the bundler resolves at build time. Putting them there carries over the intuitions people already have for import.meta.glob: the arguments are literals, you don’t alias the call or pass it around, and the build is what answers. It also gives you a single namespace and a single autocomplete entry, and because ogygia owns the namespace, nothing else can collide with it.

The test for whether something belongs here is literal inputs and a result the build can determine. A runtime wrapper around import.meta.glob is the pattern these constructs replace.

What they share

  • Literal arguments. A glob, a language or a repo spec is a plain string that the build can read. A template literal with ${…} interpolation is a runtime value, so it is a build error that names the offending expression.
  • Detection by parsing. A construct is found by parsing the code rather than by searching its text, so the same words inside a comment or a string are never mistaken for a call.
  • Errors at build time. Misuse fails the build with an [ogygia] message that names the file, the line and the fix, rather than silently doing nothing or surprising you at runtime.
  • No runtime cost. The rewrite happens once, at build time, and what ships is only the result: a source, a region, a registry, a codec key or a constant.

Each construct has its own page with its full contract. If you have content, start with loaders; if you share state across islands, start with wire; and for running something at build and shipping only the answer, see bake.


Each macro above respects one boundary, and the constraints describe the rules.