DEV Community

SwiftQuest
SwiftQuest

Posted on

Drawing SwiftUI previews in a browser when SwiftUI only runs on Apple's systems

I've been building a SwiftUI course that runs in the browser, and the hard part was obvious from day one: Apple's SwiftUI only exists on Apple platforms, and the learner's code compiles and runs on Linux servers. Here's how it ended up working, in case it's useful to anyone or someone spots a hole in it.

A stand-in SwiftUI module

There's a stand-in SwiftUI module with the same names and signatures as Apple's. So the learner's file is the file they'd write in Xcode, import SwiftUI and all, and their mistakes get the same compiler errors.

The module draws nothing. A run turns the views into a tree of plain nodes, with each modifier wrapping what it modifies, in order. That order matters for the same reason it matters in real SwiftUI: .padding().background(.blue) and .background(.blue).padding() are different trees.

#Preview is what gets drawn

A macro can't name something a host program can find. So before compiling, the #Preview line gets rewritten to a plain let (line numbers kept, so compiler errors still point at the right line), and a generated main.swift hands every preview to the host.

One run explores the whole screen

After rendering, the host presses every control once and keeps each screen that follows, up to 160 screens within two seconds. When you tap a button in the browser, it just follows a path that was already explored, so there's no second run. A tap that crashes gets pinned to its button instead of killing the whole preview.

The browser does the layout

The browser reimplements SwiftUI's proposal and response rules: stacks sharing space by flexibility, frames and padding proposing and reporting sizes, text wrapping to what it's offered. The constants came from frames the iOS simulator printed: line heights, spacing, button padding, symbol sizes.

Checking it against the real thing

Every example is also drawn with real SwiftUI on the iOS simulator, and the two pictures are compared. The weakest spot is SF Symbols, which are stand-in icons because their licence keeps them on Apple platforms. It's close to Xcode, not identical, and you still finish real apps in Xcode on a Mac.


This is the SwiftUI part of SwiftQuest, a course I'm building. Every exercise runs on a real Swift compiler, each run in its own throwaway gVisor container (I wrote about that sandbox here). The SwiftUI course has 8 destinations and 24 quests, from your first view to one app of your own built in three milestones, and it's open to beta testers now next to the Swift course. There's no deadline, you can be approved the same day, and testers get Pro for life: https://swiftquest.dev/beta?ref=devto

Happy to go deeper on any of the above in the comments.

Top comments (0)