4.2 KiB
| id | ticket | title | created | tags | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| LSN-0055 | multi-frontend-provider-contract | Static frontend providers before plugin architecture | 2026-07-15 |
|
Context
Prometeu needed a multi-frontend boundary without turning the compiler or Studio into a dynamic plugin platform. Before this work, shared code could ask the registry for frontend specs or phase services, and PBS was registered directly as the default language. That worked for a single frontend, but it made the next frontend harder because common code could still depend on PBS-specific construction details.
The durable ownership rule is now: common compiler and Studio code select a frontend by languageId, then consume a provider contract. PBS remains the first and only real provider, but it is no longer the shape of the shared abstraction.
Key Decisions
FrontendProvider is the common registration unit
What: Each registered frontend is represented by a FrontendProvider with:
specification(), for the static frontend contract andlanguageId;compiler(), for compiler-facing frontend execution;languageService(), as an optional editor-facing capability.
Why: This groups the frontend identity, compiler entrypoint, and optional tooling capability without forcing every frontend to implement Studio/editor services.
Trade-offs: The provider is intentionally small. It does not solve dynamic discovery, plugin installation, external loading, or all future language-service APIs. Those are separate architectural decisions.
Registration is explicit
What: Frontend registration is static and composition-root-owned. The application composition path bootstraps the default provider set, and the registry resolves providers by languageId.
Why: Explicit registration keeps dependencies visible and testable. It lets composition know about PBS while preventing common compiler and Studio consumers from directly constructing PBS services.
Trade-offs: Adding a new in-repository frontend still requires a code change in composition. That is acceptable because this decision optimizes for repository-internal multi-frontend readiness, not external plugin extensibility.
PBS is a provider, not the shared model
What: PBS is wrapped by PBSFrontendProvider. Shared build and Studio consumers obtain frontend behavior through FrontendRegistryService.require(languageId) or provider-derived listings.
Why: PBS remains the correctness baseline, but it must not become the exclusive owner of compiler pipeline semantics.
Trade-offs: PBS-specific tests may still instantiate PBSFrontendPhaseService directly because they test PBS internals. Common modules should not.
Patterns and Algorithms
Use this path for common compiler execution:
- Resolve the project language from the manifest or default provider.
- Resolve
FrontendProviderbylanguageId. - Use
provider.specification()for static metadata. - Use
provider.compiler()for frontend compilation. - Use
provider.languageService()only when a tooling consumer needs optional editor services.
Use this path for Studio language catalogs:
- List providers from the registry.
- Derive templates from
provider.specification(). - Do not hardcode PBS templates in Studio catalog code.
Pitfalls
- Do not add reflection, classpath scanning, external JAR loading, or runtime plugin installation to solve repository-internal frontend registration.
- Do not make
languageService()mandatory. Compilation and editor assistance are separate capabilities. - Do not instantiate
PBSFrontendPhaseServicefrom common build, dependency, Studio, or app code. - Do not use PBS as a fallback for unknown
languageId. Unknown languages must fail explicitly. - Do not move frontend semantic ownership into Studio just because Studio consumes provider metadata.
Takeaways
- Static providers are enough to prepare for multiple in-repository frontends.
- The registry boundary is provider-based, not PBS-based.
- Composition may know which frontends exist; common consumers should only know
FrontendProvider. - Optional editor capabilities keep compiler readiness independent from Studio feature depth.