Refreshing on the Client
In the last lesson the host embedded the remote and it just worked — because that fetch happened on the server, before the page reached the browser. Now we want a Refresh button that re-fetches the remote without reloading the whole page.
That hits a wall: from the browser, the host page can’t reach the remote’s port directly — the two apps only see each other on the server, inside their shared environment. So we route the request through the host instead, a pattern called a backend-for-frontend (BFF). The host exposes its own route that fetches the remote and passes the HTML back:
export async function GET() { const res = await fetch("http://localhost:3001/fragment"); return new Response(await res.text(), { headers: { "Content-Type": "text/html" }, });}That handler is already in place. Now <micro-frame> points at /notice — a path on the
host itself, which the browser can always reach. To re-fetch, we change the src: add a
counter to the URL and bump it on each click.
You’ll also notice a small cleanFetch helper wired onto the tag with fetch=cleanFetch.
That’s a preview-only workaround and already provided for you: this StackBlitz preview
injects its own runtime <script> into fetched HTML, which would error if it ran a second time
when the notice is re-inserted. cleanFetch strips that injected script and keeps the remote’s
own. Outside StackBlitz you don’t need it — leave it in here and move on.
Heads up — this file is Class API, on purpose.
@micro-frame/markois a Marko 5 library (that’s why Part 10 runs on a Marko 5 template), and its tags can only be driven from Marko 5’s Class API — not from the Marko 6 Tags API you’ve used so far. So the reactive code here looks a little different: aclass { ... }block holds component state inthis.state, methods on the class are event handlers, andon-click("refresh")wires the button to therefreshmethod (instead of<let>andonClick).
Wire it up (the cleanFetch helper and the <micro-frame> are already there):
- Add a
class {}block above the page withonCreate() { this.state = { nonce: 0 }; }and arefresh() { this.state.nonce++; }method. - Add a
<button on-click("refresh")>Refresh</button>. - Change the
srcfrom"/notice"to`/notice?v=${state.nonce}`so every click builds a new URL.
Click Refresh and watch the timestamp in the notice change: the remote re-rendered, was fetched fresh through the host, and swapped into the page on the client — no full reload. The × keeps working after each refresh, too.
- Installing the host app
- Installing the remote app
- Building the remote, then starting both apps