Best viewed on desktop Mobile Friendly tutorial coming soon!

The mount() API

Every app so far has run through marko-run: the server renders your templates to HTML, ships it, and the browser takes over. This one has no server at all. Marko can render a template entirely in the browser — no SSR, no marko-run, just a plain Vite app that builds to static files a CDN could serve.

The setup is small. index.html has an empty mount point and loads one script:

<div id="app"></div>
<script type="module" src="/src/main.js"></script>

src/main.js is the entry — it imports a .marko template and renders it. And vite.config.js uses the Marko plugin in unlinked mode (marko({ linked: false })): that’s the switch that tells it to build a browser-only bundle instead of the server-plus-client pair marko-run produces.

Mounting the template (your job)

A Marko template compiled for the browser has a .mount() method:

Template.mount(input, node);

It builds the template’s reactive DOM and drops it into node, and input becomes the template’s input. Open src/main.js and mount App into the #app element:

import App from "./app.marko";
App.mount({ name: "Marko" }, document.getElementById("app"));

That’s the whole bootstrap. Save, and the preview springs to life — the heading and a working counter, rendered client-side, with no HTML ever coming from a server. The { name: "Marko" } you passed is the template’s input; the counter’s reactivity works exactly as it does everywhere else in Marko.

That’s Marko with no server: a template, a mount point, and one .mount() call — the same components and reactivity you already know, rendered entirely in the browser.

Powered by WebContainers Built with TutorialKit Built with ❤️ by defunkt-dev
Files
Preparing Environment
  • Installing dependencies
  • Starting dev server