Compiled BML libraries
BML libraries package reusable components with their compiled Kotlin, client code, styles, assets
and public types. Applications consume their binary dependencies; original sources are attachments
for editing and navigation. The Bosca Design Library supplies shared
web components through io.bosca:bml-design.
Consume a library
Declare the Gradle dependency using the version selected for the application:
dependencies {
implementation("com.example:widgets:$widgetsVersion")
}
Use the configured Bosca artifact repository for Bosca libraries and select an available release
with matching BML tooling. Within the Bosca workspace, the Design Library dependency is
implementation(project(":bml:bml-design")).
Create src/main/bml/imports.bml once:
<import library="com.example:widgets" />
Every page and local component under that BML source root, including nested directories, can use
the library's exported tags directly. An import names group:artifact; Gradle selects the version.
Adding the dependency alone does not import its tags. The root imports file accepts imports,
comments and whitespace.
A file can also declare a top-level import before its page or component. File-local imports combine with root imports. For an optional alias:
<import library="com.example:widgets" as="widgets" />
<page route="/">
<html lang="en">
<body><widgets:notice>Saved preferences</widgets:notice></body>
</html>
</page>
An unaliased import exposes short tags such as <notice>. An aliased import exposes only qualified
tags such as <widgets:notice>. Importing the same library both ways shares its component identity
and assets; instances keep their ordinary independent state.
Names and native elements
Local components take precedence over unprefixed library exports. Two different unaliased libraries
exporting the same tag produce a diagnostic; give one an alias. Imports expose only explicitly
exported components, while private helper components remain part of the compiled implementation.
Protected BML syntax such as page and island retains its meaning.
An imported button replaces unqualified <button> calls. Use <html:button> for the native
element, including inside a component that implements button. svg: likewise selects native SVG.
For example, after importing the Design Library:
<button primary>Save</button>
<html:button type="button">Native button</html:button>
Use attribute forwarding to pass additional native attributes through a component. Props, projected children and declarative events keep their BML contracts across the binary dependency.
Produce a library
Apply the BML Gradle plugin to a Kotlin library project and configure its public exports:
bml {
packageName.set("example.widgets.generated")
library {
exports.set(listOf("notice"))
}
}
The project's group and artifact name define its import identity. Put BML components under
src/main/bml, ordinary Kotlin in its Kotlin source set, and client assets under src/main/client.
For example:
<component tag="notice">
<p class="notice" role="status" {...attrs}><slot /></p>
</component>
Keep routable pages, messages and the application plugin in a separate application project. The
library's binary JAR carries its compiled renderers, manifest and reachable client/resource
contracts. Its sources JAR includes original BML, Kotlin and authored client sources. Gradle's
bmlValidateLibrary checks the binary/source contract and is wired into check and library JAR
validation. Maven publication validation checks the actual publication archives as well.
Applications use generated aggregate registries for their selected components and dependencies. BML Server composes those components and their library providers; callers do not manually register every imported renderer. The application owns its document, routes, authentication, data, forms and actions.
Styles, assets and public client types
Library styles and client assets participate in the existing BML asset pipeline. Component reachability selects implementation assets: importing the Design Library module does not add its source viewer or JSON editor implementation to a page that only renders basic controls. Fonts and resources are packaged and served from the consuming application's origin.
When application code imports the same npm ESM dependencies as a compiled library, the bundler
can reuse the library's compiled modules. Reuse requires matching source bytes, package metadata,
static dependency resolution and bundler version. Different versions or modified dependency graphs
keep their own implementations. Libraries remain self-contained for consumers without those npm
packages. Pages without matching application dependencies retain their ordinary library entries.
Library binaries retain environment conditions until the consuming build selects development or
production behavior. Production emits one entry per page with content-hashed shared modules, so
common engines download once across pages. A page still loads only its reachable components;
this adds no public helper imports or component props. bmlMetrics includes the entry's full static
module closure in its first-load figures.
Packaged asset responses use the indexed content digest for conditional requests before loading a body. Response bytes are verified and cached within the active application generation; a reload uses its new inventory and cache. Unknown paths remain unavailable.
The Design Library's CSS variables let applications set colors, fonts, spacing, radii, focus and editor presentation in their own CSS, globally or on a themed container. The application still chooses its document font, reset and layout.
Publish type-only client event contracts with library client declarations. The consuming linker extracts these declarations from the binary for TypeScript checks; a producer checkout is unnecessary. Keep search and save transport in application adapters. Library localization contributes component strings to the consuming application's existing catalog and locale policy.
Develop and navigate
Run the consuming application's bmlDev. Editable direct and transitive BML project libraries
participate in Gradle's input graph: Kotlin, BML, client helpers, CSS, resources, assets, exports and
root imports rebuild the consumer. Successful builds load a new generation in the running server;
failed builds leave the last good generation serving. Framework and ordinary JVM dependency
changes require a restart. See hot reload.
The IntelliJ plugin combines root/file-local imports with the current module's dependency manifests. Component completion and Go to Declaration support short and aliased tags, including opening, closing and self-closing uses. Project dependencies navigate to original BML sources; published dependencies use their own matching attached sources. Embedded Kotlin can navigate to the library's original model source. Download matching sources through Gradle or attach them in Project Structure when the IDE reports they are missing or mismatched. Metadata completion remains available without source attachments. Editing imports invalidates bindings without compiling the consumer.
Multiline component tags use the same gutter and Collapse/Expand actions as native tags, including when viewing original BML in read-only library source archives.