Hono: whole-file .mx (alpha)
A plain .mx file on the Hono host is the whole component. There is no function to write: MX emits the default-exported function component, and export interface Input becomes its props type.
Alpha. .hono.mx is the form to start with when you build with Vite. Whole-file .mx is the one a Bun server can import directly, which is why it is documented here.
export interface Input {
items: string[];
}
<main>
<h1>${input.items.length} items</h1>
<ul>
<for|item| of=input.items><li>${item}</li></for>
</ul>
</main>
A Bun server, no bundler
# bunfig.toml
preload = ["@mxlang/hono/bun"]
import { Hono } from "hono";
import App from "./App.mx";
const app = new Hono();
app.get("/", async (c) => c.html(await App({ items: ["alpha", "beta"] }).toString()));
The loader compiles .mx to TSX and each compiled file carries its own @jsxImportSource hono/jsx pragma, so the template needs no JSX configuration. Two limits:
- It declines region files (
.hono.mx); those need the Vite plugin. - A hand-written
.tsxbeside it has no pragma, so the project’s owntsconfig.jsonmust setjsxImportSource: "hono/jsx". Run the script under a different project’s tsconfig and Bun silently picks the wrong JSX runtime for that file.
In the template
- Props are
input:input.items. - Hooks go in
<const>(<const/state=useState(0)/>), which becomes a statement in the component body.staticis module scope and must not call a hook. import,staticandexportare hoisted to the module.- Marko’s stateful tags are errors that name the
hono/jsxhook to use:useState,useEffect,useId.
Selecting the host
A whole-file .mx has no host in its name, so package.json says which one compiles it: "mx": { "host": "hono" }. A project whose only @mxlang/* host or target package is this one may leave the field out; with @mxlang/html installed too, say which. mx.target: "hono-jsx" selects Hono too; if both are given and disagree, the tools report target-host-mismatch.
Everything in What MX compiles to applies. examples/hono-app is a complete app on this route.