Skip to content

Derive the Layout manifest instead of asking for it twice - #3

Closed
pathscale wants to merge 1 commit into
masterfrom
fix/derive-the-layout-manifest
Closed

Derive the Layout manifest instead of asking for it twice#3
pathscale wants to merge 1 commit into
masterfrom
fix/derive-the-layout-manifest

Conversation

@pathscale

Copy link
Copy Markdown
Owner

layouts.library.json required an exports array naming every public component. That list is the same information as the package's own entry files, written a second time by hand, so it could only ever drift from them.

It did, and silently.

A library renamed eleven components across its source, its recipes and its barrel, rebuilt from a wiped dist, and the manifest still carried the old names, because nothing had told the list. The application compiler validates against that manifest, so consumers would have been told <Alert> was not a component while <Callout>, which no longer existed, resolved fine. The same list had also never heard about two components added that morning.

The failure has no signal. Everything typechecks, the library builds, the manifest is written, and the wrong names are in it.

What it does now

The names come from the package's own exports map. Each target under the output directory maps back to its source entry, and the exported value names are read from there. Source rather than built output, because the manifest is emitted alongside a build rather than after one, so a bundler that has not run yet leaves nothing to parse. The built file is the fallback for a package laid out differently.

Excluded: types, because a type is not a component, and SCREAMING_SNAKE, because a package exporting FLAVORS beside Flavor is exporting a value rather than a component.

Measured against the library that hit this

hand-declared 173
derived 187
declared but not derived 0

The fourteen extras are all genuinely exported and were simply missing from the list, including the two components added that morning.

Consumers delete the exports array. The rest of the config, mode, source, output and lint, is unaffected.

Suites: library 8, application 14, runtime 145, transform crate 58, all passing.

`layouts.library.json` required an `exports` array naming every public
component. That list is the same information as the package's own entry files,
written a second time by hand, so it could only ever drift from them.

It did, and silently. A library renamed eleven components across its source,
its recipes and its barrel, rebuilt from a wiped `dist`, and the manifest still
carried the old names, because nothing had told the list. The application
compiler validates against that manifest, so consumers would have been told the
new names were not components while the old ones, which no longer existed,
resolved fine. The same list had also never heard about two components added
that morning.

The names now come from the package's own `exports` map: each target under the
output directory maps back to its source entry, and the exported value names are
read from there. Source rather than built output, because the manifest is
emitted alongside a build rather than after one.

Types are excluded, because a type is not a component, and SCREAMING_SNAKE is
excluded, because a package that exports `FLAVORS` beside `Flavor` is exporting
a value rather than a component.

On the library this was found in: 173 hand-declared, 187 derived, every declared
name present and the fourteen extras all genuinely exported.
@pathscale

Copy link
Copy Markdown
Owner Author

Wrong approach, closing rather than iterating on it.

This patched the escape hatch to guess component names by parsing the barrel with a regex, when the documented design is that the compiler discovers them from the source. Test-UI is the reference and it has no layouts.library.json at all: convention-based discovery, and every manifest entry is kind: "generated" carrying its recipe, its Layout and its exports, so the application compiler can actually verify the join.

What I produced instead was 187 names of kind: "embedded", which validateComponent returns early on and checks nothing about, and the list included FormContext, ToastQueue and I18nProvider because a regex over export {} cannot tell a component from a context.

Reopening against the real question: why the consuming library is on mode: "source" at all, and what emitSourceManifest should derive if it stays.

@pathscale pathscale closed this Aug 14, 2026
@pathscale
pathscale deleted the fix/derive-the-layout-manifest branch August 14, 2026 06:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant