For the full repository layout, commands, authored files, application configuration, and failure examples, start with Getting started.
This work implements the first half of the two-stage Layouts pipeline:
A = user-authored Layout UI source
B = solid-layouts library compiler
C = npm-ready Layout UI bundle
A + B -> C
The application build is a separate stage:
C = published Layout UI bundle
D = user-authored Solid application
E = solid-layouts application compiler
F = executable JavaScript and assets
C + D + E -> F
This document focuses on B and the concrete C it produces. The initial E implementation and its Chuzz integration are documented separately.
Test-UI/src contains four components copied from the larger UI migration: Icon, Button, Flex, and Chip. The full authored source is pathscale/ui PR #221; it is A and must be compiled before an application can consume it. Test-UI keeps the proof small enough that all of C can be reviewed directly while exercising multiple public exports, slots, variants, HTML passthrough, and event handlers.
The important source is Test-UI/src/components/icon/Icon.layout.tsx. It intentionally has this shape:
const Icon: Layout<typeof icon, IconProps> = () => {
const width = local.width ?? 24;
return <span {...slot.root} />;
};That is Layout template syntax. local and slot are not defined by ordinary TypeScript or SolidJS, and the zero-parameter function cannot receive them. The authored file is therefore not the package entry and is not copied into C.
The recipe is ordinary static TypeScript. There is no authored package entry in A; B generates the compiler-owned call site that C carries forward:
import { defineComponent } from "solid-layouts/application-boundary";
export const Icon = defineComponent({ recipe: icon, layout: IconLayout });The implementation lives in packages/solid-layouts-oxc, not in UI.
The OXC transform now performs the missing Layout-template rewrite:
- It recognizes
Layout<typeof recipe, Model>declarations. - It accepts authored zero-parameter Layout functions.
- It creates the valid
({ slot, children }, p)signature. - It uses OXC semantic bindings to rewrite only unbound model references.
local,props, andrawPropsbecomep.- Other unbound model values become
p.value. - Imported names, locally bound variables, JavaScript globals,
slot, andchildrenare not incorrectly rewritten. - It rejects Layout functions with an unsupported parameter shape.
The existing static recipe compiler is also part of B. It inserts the _layouts lookup data used by the shared runtime, so recipe selection does not have to rediscover the table for every component instance.
packages/solid-layouts-oxc/library.js is the package-level compiler. It:
- Walks the authored
srcdirectory and discovers*.layout.tsxfiles. - Derives each public component, recipe binding, Layout export, props type, and type exports from authored source.
- Compiles
.layout.tsxto.generated.tsx. - Compiles static
.recipe.tsfiles. - Copies ordinary source and CSS.
- Rejects missing, aliased, or ambiguous recipe/Layout relationships.
- Rejects rendered slots not declared by the recipe.
- Verifies generated files parse as TSX.
- Generates package entries with the application-compiler boundary.
- Emits
layouts.manifest.json. - Emits the npm package metadata for C.
The same operation is available in three forms:
compileLibrary()fromsolid-layouts-oxc/librarypluginSolidLayoutsLibrary()for an Rsbuild/Rslib host- the
solid-layouts-libraryCLI
The authored source is the package contract. Name.layout.tsx, its Layout<typeof recipe, Props> annotation, its relative recipe import, and its NameLayout export contain everything B needs. B derives the join once and emits it into C's generated manifest. It never silently guesses or falls back when the source relationship is incomplete.
layouts.library.json is optional and reserved for nonstandard layouts or adjacent source-mode generation. Test-UI and generated private libraries use convention-based discovery without it.
The inspectable output is Test-UI/bundle.
It contains:
bundle/
package.json
index.ts
types.ts
layouts.manifest.json
components/icon/
Icon.css
Icon.generated.tsx
Icon.recipe.ts
components/button/
Button.css
Button.generated.tsx
Button.recipe.ts
Icon.generated.tsx is valid TSX:
const Icon: Layout<typeof icon, IconProps> = ({ slot, children }, p) => {
const width = p.width ?? 24;
return <span {...slot.root} />;
};The compiled recipe contains _layouts, and B generates index.ts with the defineComponent Layout call site. The call site imports through solid-layouts/application-boundary, which E must resolve. This is deliberate: C is not flattened executable JavaScript, and it cannot silently bypass E. It is the valid, inspectable Layout UI input carried into the second compiler stage.
layouts.manifest.json tells E which public component maps to which entry, recipe, and compiled Layout:
{
"format": "solid-layouts-library-v2",
"package": "@pathscale/test-ui",
"components": {
"Icon": {
"kind": "generated",
"entry": "./index.ts",
"recipe": "./components/icon/Icon.recipe.ts",
"recipeExport": "icon",
"layout": "./components/icon/Icon.generated.tsx",
"layoutExport": "IconLayout"
}
}
}The generated package.json exposes the component entry and the Layout manifest and records the manifest under solidLayouts. That gives the second compiler a deterministic package-level discovery point after an application imports @pathscale/test-ui.
Yes. The local npm tarball is:
Test-UI/artifacts/pathscale-test-ui-0.0.0.tgz
It contains C only. The invalid authored Icon.layout.tsx, compiler configuration, tests, and compiler implementation are not in the tarball.
No package was published. The tarball exists only for local inspection and installation.
From Test-UI:
bun run build:layoutsThat regenerates bundle and packs it into artifacts.
- 54 Rust/OXC tests pass, including the conformance corpus, explicit mode behavior, exact application import matching, and application import rewriting.
- 3 library compiler tests pass: successful Icon and Button output, generated boundary/entry validation, missing-recipe failure, and undeclared-slot failure.
- 9 application compiler tests pass, including multiple C exports, absent exports, missing runtime metadata, mismatched generated call sites, and corrupt, unsupported, or incomplete package metadata.
- 143
solid-layoutsruntime tests pass. - The runtime TypeScript typecheck passes.
- The generated Test-UI package was packed successfully and its tarball contents were inspected.
- Chuzz imports Icon and Button from C and sends both through E; Button replaces the real title-bar and inspector controls rather than only changing an import.
- Chuzz fails when an absent C export is imported and when E is removed.
The second compiler E reads solidLayouts from C's package metadata, loads layouts.manifest.json, follows D's imports, and matches application component references against the exact component records in C. An import with no manifest entry is a hard error. That work belongs to the application compiler and is not put back into UI or mixed into this first-pass package build.
The explicit public entry points, mode boundary, manifest resolution contract, hard failures, and first Chuzz integration are specified in Compiler modes and the Chuzz application integration.