Skip to main content

@bedrock-core/ui-compiler

The build-time library the ui-compiler filter runs: a screen component goes in, the JSON UI document a host serves comes out.

This page is for tooling. An addon never imports it — the filter does, and it bundles the compiler out of the project's node_modules rather than its own, so a screen is compiled by the version of the library the addon actually ships. An addon that compiles screens therefore depends on the compiler even though none of it reaches main.js.

The same holds for @bedrock-core/ui-runtime: the pipeline runs inside that bundle, so the filter cannot drift from the library. Every value the emitted JSON UI shares with the runtime — the character table, the layout property, the highest layout key — is read off it for the same reason.

Import​

import { compileFormScreen, compileScreen } from '@bedrock-core/ui-compiler';

The build half of the runtime is a subpath of its own, and supplies everything the compiler takes as input:

import { buildScreenOnce, hostFor, probeLiveness } from '@bedrock-core/ui-runtime/compile';

Compiling one screen​

compileScreen(Screen, { name, namespace? }): CompiledScreen
compileFormScreen(Screen, { name, namespace }): CompiledFormScreen

Both take the component, not the result of calling it: the compiler renders it under its own owner, which is what makes the hooks inside it resolve. compileScreen serves the chest; compileFormScreen serves the action form and the modal, deciding which from the root. Each probes for liveness before anything is baked and returns the served document, face document, compiled entries and allocation data the filter needs.

Compiling an addon​

buildRouter(screens)
formRouter(screens, addon): FormRouting

The addon-level documents: the hooks into vanilla files, and the router holding one gated definition per screen. One addon per call — a router covers one addon, and mixing two is an error.

Exports​

ExportKindDescription
compileScreenfunctionCompiles one container screen
compileFormScreenfunctionCompiles one form screen, action or modal
buildRouterfunctionThe chest hooks and one addon's chest router
formRouterfunctionThe mount insert and one addon's form router
toIrfunctionA built root plus a host's addressing, lowered to IR
faceOffunctionIR to a face document and the faces it shares
fillfunctionA face document plus a host, to the served document
emitfunctionfaceOf then fill, for a caller that wants only the result
facesNamespaceOffunction<addon>_faces, the namespace an addon's shared faces live in
formRouterFileOffunctionPack path of an addon's form router
CHEST_HOSTconstThe chest host: its hooks, canvas, collection and container type
MOUNT_ANCHORconstWhere a compiled chest layout sits: centered both ways
MOUNT_FILEconstPack path of the form mount an addon inserts into
SCREEN_DEFINITIONconstName of the definition the router mounts
BACKDROP_DEFINITIONconstName of the full-screen image mounted behind it
UnsupportedNodeErrorclassThrown for a control with no compiled form

The IR node types, the JSON UI control types, and the result shapes (CompiledScreen, CompiledFormScreen, FaceDocument, ScreenSpec, FormScreenSpec, FormRouting, RoutedScreen, RoutedFormScreen, ToIrOptions, Allocation) are exported as types beside them.

Limits​

Percentages, %c and anchors are not exposed to authors. The layout solver is the one source of geometry and it produces pixel rects against a canvas the host names; JSON UI's relative sizes appear only where the engine has to decide at draw time — a stack sized so hidden rows collapse, a fill inside a box the layout already sized. A screen-relative canvas is a host property, never a prop.

Sharing one parameterized frame between a look's states does not work. A frame resolves caption@$core_content in its own scope, where the variable was never set, so the reference names nothing and the control has no type: the client refuses every caption in the world. Sharing has to happen at the mount, with each consumer carrying the caption name along with the frame.