Bosca / BML

Tooling

From compiler to production

BML is compiled, not interpreted. A Kotlin K2 compiler plugin produces typed page objects, the IDE understands your files, the dev loop reloads the browser for you, and a finished site deploys as one server process.

The compiler

Pages are typed objects

There are no hand-written page classes. The build parses every .bml file and generates a Kotlin render object per page, which the Kotlin compiler compiles alongside the rest of the project. Embedded server Kotlin lowers into the generated code with source maps back to the .bml file, so diagnostics point at the line you wrote.

  • Client <script client> blocks compile to TypeScript and bundle into browser ES modules.
  • The IntelliJ plugin adds file-type support, syntax highlighting, comment toggling, and language injection — Kotlin inside server scripts, interpolation, and bound attributes; TypeScript inside client scripts.
generated page object
// build/generated/bml/kotlin — generated, never hand-written
@BmlPage(route = "/prayers/{id}")
object PrayerPage : BmlPageRenderer {
    override suspend fun render(ctx: RenderContext) {
        // compiled from prayer.bml
    }
}

The dev loop

Save the file. The browser follows.

bosca bml dev watches application sources, rebuilds the affected output, and swaps the new application generation into the running server. The process, port, and active sessions stay put, while the server pushes a live-reload event so the browser follows automatically.

If a build fails, the last good generation keeps serving while the diagnostics point back to the source. Framework or dependency changes still ask for a deliberate restart; ordinary application work stays in the fast loop.

The GraphQL endpoint is configuration, so local development can point at a remote Bosca for real data and the same code runs unchanged once deployed.

the bosca CLI
# scaffold a project
bosca bml init my-site

# generate Kotlin once
bosca bml compile my-site

# rebuild, hot-swap, live-reload
bosca bml dev my-site

Deployment

A site is one process

Hand the generated registries to BmlServer and start it. The server registers each page's route, serves static assets, and hosts the action, contract, and GraphQL proxy endpoints — there is nothing else to run.

  • In production a page downloads at most one merged stylesheet and one merged bundle on top of the global tier — what every page shares is normalized into the global file. Dev serves per-component files so hot reload invalidates one small file at a time.
  • Served CSS/JS carries an ETag; repeat loads answer with a body-less 304.
  • Files under the public directory can opt into a long-lived Cache-Control policy.
Main.kt — wiring a compiled site
BmlServer(
    pages = bml.generated.BmlPages.all,
    components = bml.generated.BmlComponents.all,
    graphqlEndpoint = System.getenv("BML_GRAPHQL_ENDPOINT"),
    publicDir = File("public"),
    globalCss = File("app.css").readText(),
    port = 9092,
).start()

Measurement

Page weight is a build output

The compiler knows exactly which assets each page links — its island bundle, the CSS chunks of the components it renders, the global tier — so the build can price every page. Running bmlMetrics prints each page's first-load payload in raw and gzip bytes and writes a JSON report, so size changes are visible build over build.

For a running site there's bosca bml audit: it fetches a route, discovers the assets the page actually declares, and records real transfer bytes and timing per request. It works against any HTTP site — not just BML — so you can measure a BML deployment against the same pages on another stack.

./gradlew bmlMetrics — the sample site
BML site metrics — first-load payload per page (raw, gzip)

Page           Route             JS               CSS            First load
-------------  ----------------  ---------------  -------------  ----------------
HomePage       /                 3.4 KB (1.6 KB)  564 B (291 B)  3.9 KB (1.9 KB)
CartPage       /cart             3.3 KB (1.6 KB)  55 B (72 B)    3.4 KB (1.6 KB)
DashboardPage  /dashboard        -                -              -
ScenarioPage   /scenario/{mode}  -                508 B (269 B)  508 B (269 B)

JSON report: build/reports/bml/site-metrics.json

Keep exploring

More on BML