# Getting started

SwiftBrowser runs an iOS SwiftUI app in the browser from its unchanged
sources. The app compiles to WebAssembly against an API-compatible SwiftUI
shim and draws inside an iPhone frame on a desktop, or full screen on a
phone. You keep building the same project in Xcode for iOS; the browser
build is a second target that needs no Mac.

This page takes an existing app from zero to a deployed static site. The
[CLI reference](https://swiftbrowser-docs.pages.dev/cli) has every option, and
[Compatibility](https://swiftbrowser-docs.pages.dev/compatibility) lists what the shim supports.

## Requirements

- Node 22 or later.
- Swift 6.4, installed with [swiftly](https://www.swift.org/install/)
  (`swiftly install 6.4.0`), or any 6.4 toolchain whose `usr/bin` is in
  `SWIFT_TOOLCHAIN_BIN`.
- The Swift SDK for WebAssembly and Binaryen's `wasm-opt`. `doctor --install`
  fetches both.

Linux and macOS both work. Nothing is installed globally besides the Swift
SDK; Binaryen and cached data live in `~/.cache/swiftbrowser`.

```sh
npx @swiftbrowser/cli doctor --install
```

`doctor` without `--install` only reports what is missing.

## 1. Check the app

Point the CLI at an `.xcodeproj`, a folder that holds one (directly or one
level down), or a plain folder of Swift sources:

```sh
npx @swiftbrowser/cli check ~/Projects/MyApp
```

`check` lists every module the app imports as supported, rewritten or
unsupported (with the usual way around each), then compiles the app natively
against the shim. It takes seconds and builds no WebAssembly. Every error
names your file and line. Anything the shim lacks is a compile error, never a
wrong rendering at runtime.

When a project has several app targets, pick one with `--target <name>`.

## 2. Work around what is missing

Code that cannot run in the browser goes behind the `SWIFTBROWSER` compilation
condition, which the CLI defines, much like `#if os(iOS)`:

```swift
#if SWIFTBROWSER
// A stand-in for the browser.
Text("Maps are not available in the browser yet")
#else
Map(position: $position)
#endif
```

Xcode never defines `SWIFTBROWSER`, so the iOS build is unaffected.

## 3. Run it with live reload

```sh
npx @swiftbrowser/cli dev ~/Projects/MyApp
```

The dev server opens a landing page at <http://localhost:5173> with a QR code,
and serves the app at `/app/?app=<Name>`. Saving a Swift file rebuilds the
module and reloads the page with the app's `@State` carried over where the
view tree still matches.

To try it on a phone, add `--host` to expose the server on your network and
scan the QR code. On a phone the app drops the iPhone frame and uses the real
screen and safe areas; in Safari, Share → Add to Home Screen runs it full
screen.

Other useful flags: `--port`, `--open`, and `--verbose` for the full compiler
output.

## 4. Build a static site

```sh
npx @swiftbrowser/cli build ~/Projects/MyApp -o dist
```

`build` makes a release module, optimized and stripped with `wasm-opt`, and a
complete static site around it: a landing page, the app page at
`/app/?app=<Name>`, the asset catalogs and a web app manifest. A small app is
about 17 MB, 4.5 MB with brotli. Serve `dist/` from any static host that sends
`.wasm` files as `application/wasm` (Cloudflare Pages, Netlify, GitHub Pages
and S3 all do).

## What the CLI does to your project

Nothing outside `<project>/.swiftbrowser/`, which you should add to
`.gitignore`. The CLI reads the Xcode project, copies the app target's sources
into a generated SwiftPM package there, adjusts the copies for the shim
(keeping line numbers, so diagnostics point at your files) and builds that.
See [What happens to your project](https://swiftbrowser-docs.pages.dev/cli#what-happens-to-your-project).

## Configuration

Most projects need none. When the Xcode project is not enough, or the app is
a plain folder of sources, an optional `swiftbrowser.json` next to it names
the sources, resources, asset catalogs, icon, ICU locales and extra
compilation conditions. See
[swiftbrowser.json](https://swiftbrowser-docs.pages.dev/cli#swiftbrowserjson-optional).

## Data that persists

What an iOS app keeps on the device, the browser keeps per app:

| On iOS | In the browser | Reset with |
|---|---|---|
| `UserDefaults`, `@AppStorage` | localStorage | clearing site data |
| SwiftData | IndexedDB, `sb-swiftdata:<App>` | `?swiftdata=reset` |
| Files in the app's home (`URL.documentsDirectory`, …) | IndexedDB, `sb-files:<App>` | `?files=reset` |

## Next

- [CLI reference](https://swiftbrowser-docs.pages.dev/cli): commands, Foundation and ICU
  data, frameworks, Core ML, Swift packages.
- [Compatibility](https://swiftbrowser-docs.pages.dev/compatibility): the SwiftUI and framework APIs that work.
- [Architecture](https://swiftbrowser-docs.pages.dev/architecture): how the shim, the render ops and the
  renderer fit together.
