Best viewed on desktop Mobile Friendly tutorial coming soon!

Streaming from the Remote

🔒 Read-only demo — editing won't change the preview
This lesson is a finished demo. The remote app runs pre-built here — that's what lets the notice's × work in the browser — and a pre-built app can't reflect code edits, so changing the code won't update the preview. Read along and watch it run. To edit the code and see it live, download the lesson and run it locally.
⚠️ If the preview looks stale — reload it
This lesson runs two apps in the preview, and it doesn't always refresh on its own. After you switch lessons, or if the notice's × button stops working, hit reload on the preview — or reload the whole page.

A remote doesn’t have to render all at once. It can stream — send the parts it already has, show a placeholder for the slow parts, and fill them in as they resolve. Because <micro-frame> embeds whatever the remote sends, the host gets that streaming for free: the remote’s placeholder appears, then its real content swaps in — and the host never knows the remote was doing async work.

Marko streams an <await> on its own: wrap the slow part in a <try> with a <@placeholder>, and Marko flushes the placeholder first, then the resolved content. Here’s the remote’s notice doing exactly that (remote/src/routes/fragment/+page.marko):

<try>
<await|deal|=new Promise((resolve) => setTimeout(() => resolve("50% off — ends tonight"), 800))>
<div>${deal}</div>
</await>
<@placeholder>
<div>Loading the latest deal…</div>
</@placeholder>
</try>

(In a real app the promise is an API call; here we fake the delay with a timer.)

On the host side, the <micro-frame> embeds the remote as always — with one change from the earlier lessons: no client-reorder. With client-reorder, the host buffers the remote’s output and drops it in all at once, so you’d never see it stream. Without it, the host paints the remote’s stream in order — so the placeholder shows first, then the deal swaps in.

Watch the Host app preview: the remote’s “Loading the latest deal…” placeholder shows for a beat, then the deal streams in — rendered by the remote, embedded live in the host, which never knew the difference. The notice is still dismissible; its × runs in the browser.

That’s the end of Chapter 1. You’ve embedded a remote, refreshed it from the client, and streamed it — all app federation, all with the remote owning its own render.

Powered by WebContainers Built with TutorialKit Built with ❤️ by defunkt-dev
Files
Preparing Environment
  • Installing the host app
  • Installing the remote app
  • Building the remote, then starting both apps