feat: add plugin-aware component discovery - #524
Open
Mohamed Mansour (mohamedmansour) wants to merge 3 commits into
Open
feat: add plugin-aware component discovery#524Mohamed Mansour (mohamedmansour) wants to merge 3 commits into
Mohamed Mansour (mohamedmansour) wants to merge 3 commits into
Conversation
Keep default component discovery filename-based and metadata-free. Resolve FAST manifest declarations through converted template-webui assets while preserving ordinary HTML fallback, scoped package lookup, and actionable errors. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Mohamed Mansour (mohamedmansour)
added this pull request to stack #526
September 11, 2026 04:40
Mohamed Mansour (mohamedmansour)
requested review from
Bang Lee (Qusic),
atul (atulkatti),
Jane Chu (janechu) and
mcritzjam
and
a lite review from Copilot
September 11, 2026 04:58
Copilot started reviewing on behalf of
Mohamed Mansour (mohamedmansour)
September 11, 2026 05:01
View session
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved critical and moderate findings affect cache safety, package-path validation, and FAST metadata handling.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds plugin-aware component discovery, separating native filename discovery from FAST manifest-based discovery.
Changes:
- Adds catalog scanning, package/scope resolution, and metadata-aware caching.
- Restricts FAST discovery to converted template assets with fallback support.
- Updates documentation, tests, fixtures, and plugin contracts.
File summaries
| File | Reviewed change |
|---|---|
docs/guide/concepts/components/index.md |
Documents native package discovery. |
docs/guide/cli/index.md |
Updates CLI discovery guidance. |
docs/ai.md |
Adds component discovery guidance. |
DESIGN.md |
Defines discovery contracts and behavior. |
crates/webui/src/tests/fast.rs |
Adds FAST integration coverage. |
crates/webui-discovery/tests/scopes.rs |
Tests scoped resolution and fallbacks. |
crates/webui-discovery/tests/metadata.rs |
Tests metadata isolation and caching. |
crates/webui-discovery/tests/catalog.rs |
Tests catalog and FAST asset discovery. |
crates/webui-discovery/src/plugin/mod.rs |
Defines the plugin contract and native discovery. |
crates/webui-discovery/src/plugin/fast/tests.rs |
Adds FAST unit coverage. |
crates/webui-discovery/src/plugin/fast/README.md |
Documents FAST discovery. |
crates/webui-discovery/src/plugin/fast/mod.rs |
Implements FAST-specific discovery. |
crates/webui-discovery/src/npm.rs |
Refactors package resolution and metadata handling. |
crates/webui-discovery/src/lib.rs |
Registers discovery modules. |
crates/webui-discovery/src/catalog.rs |
Implements filename-based catalog scanning. |
crates/webui-discovery/src/cache.rs |
Supports optional metadata fingerprints. |
crates/webui-discovery/README.md |
Documents discovery conventions. |
crates/webui-cli/src/commands/build.rs |
Updates discovery fixtures. |
.gitignore |
Ignores macOS metadata files. |
Review details
Suppressed comments (5)
crates/webui-discovery/README.md:32
- The new public API/behavior leaves
docs/guide/concepts/plugins/index.mddescribing the removed.template.htmlFAST layout and the oldDiscoveryPlugintrait; its example lacksrequires_package_metadataandsupports_package. Developers following that canonical guide will implement or author against a contract this PR no longer accepts. Update that public guide alongside this change.
Plugin-specific behavior is documented in the [FAST discovery guide](src/plugin/fast/README.md).
crates/webui-discovery/src/catalog.rs:71
- These dependencies are enumerated only from HTML files that already exist. Because
DiscoveryCache::fingerprinthashes only this returned list, adding a new<component-name>.html(or nested directory) leaves the list and fingerprint unchanged, so an old cache entry is returned and the new component is invisible until another tracked file changes. Include a deterministic catalog-membership input (or otherwise invalidate when the catalog directory changes) before caching discovery results.
pub(crate) fn cache_files(root: &Path) -> Result<Vec<PathBuf>> {
cache_files_matching(root, |_| true)
}
pub(crate) fn cache_files_matching(
root: &Path,
include: impl Fn(&Path) -> bool,
) -> Result<Vec<PathBuf>> {
let mut files = Vec::new();
for template in templates(root) {
let template = template?;
if !include(&template) {
continue;
}
for extension in ["css", "ts", "js"] {
files.push(template.with_extension(extension));
}
files.push(template);
crates/webui-discovery/src/catalog.rs:118
has_sibling_scriptonly checkstry_exists(), so a directory named<tag>.tsor<tag>.jsis treated as authored even though it is not a sibling script file. In npm discovery these same paths are also fingerprinted andfs::readthen fails on the directory, so a non-file sidecar either changes ownership or breaks discovery; require the candidates to be regular files while preserving metadata errors.
is_client_owned: has_sibling_script(&template)?,
crates/webui-discovery/src/plugin/fast/mod.rs:127
- This branch treats every
customElementsmanifest with no parsed declarations as an ordinary fallback, butdeclarations()returns an empty list for malformed shapes such as a missing or non-arraymodulesfield. That lets an invalid FAST manifest build successfully when an ordinary HTML file exists, contrary to the documented contract that malformed metadata is an error; distinguish a valid empty inventory from malformed metadata before taking this fallback.
docs/guide/concepts/components/index.md:210 - This behavior change leaves
docs/guide/concepts/plugins/index.md:152-166describing FAST files and CEM mappings with the rejected.template.htmlsuffix. That page is linked from the component guide, so FAST package authors can still follow stale instructions and select the raw variant that this PR explicitly rejects; update the plugin guide to the.template-webui.htmland current export/fallback rules.
Install the package into `node_modules/`. Default WebUI discovery derives the
component name from each hyphenated `<component-name>.html` filename, exactly as
for local components. It scans the package's `components/` directory when present,
otherwise the package root. Nested directories are supported; a directory does
- Files reviewed: 18/19 changed files
- Comments generated: 6
- Review effort level: Lite
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Stream dependency fingerprints through a reused bounded buffer, validate npm source identifiers before filesystem lookup, and align the discovery documentation with plugin-selected cache inputs. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: bf3fdbed-b6e0-4b3e-8b29-667f44831c4e
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Component discovery should follow the selected plugin without making filename-only applications pay for FAST metadata work. This separates the default filesystem convention from FAST's manifest-driven discovery and makes npm package/scope resolution predictable.
Changes
*.template-webui.htmlassets. Raw*.template.htmlfiles are not accepted as a substitute; ordinary<component-name>.htmlapp components remain supported.plugin/mod.rsand FAST-specific behavior and documentation underplugin/fast.Validation
cargo xtask check.This is the base layer of the split. WebUI Press content mode is the separate dependent PR #525.