--- title: Build & Packaging Pipeline description: What happens under the hood when you run `wails3 build`, how cross-platform binaries are produced, and how installers are generated for each OS. sidebar: order: 6 --- `wails3 build` is a **single command** that drives a _multi-stage_ pipeline: 1. **Frontend production build** (Vite / React / …) 2. **Asset embedding** into Go sources 3. **Native compilation** for the target OS/arch 4. **Post-processing** (icon injection, version info, codesign) 5. **Packaging** into a distributable artefact (AppImage, DMG, MSI, …) This document follows every stage, shows where the code lives, and explains how to customise or debug it. --- ## 1. Entry Point: `internal/commands/build-assets.go` ``` wails3 build # cmd/wails3/main.go └─ internal/commands.Build() # build-assets.go ``` High-level tasks are delegated to **Taskfile** targets so the same logic runs in CI or locally. | Stage | Taskfile target | Go implementation | |-------|-----------------|-------------------| | Frontend build | `frontend:build` | `internal/commands/task.go` | | Embed assets | `embed:assets` | generated `bundled_assetserver.go` | | Go compile | `build:go` | `tool_buildinfo.go`, `tool_package.go` | | Package | `package:*` | `internal/packager`, `internal/commands/*` | --- ## 2. Frontend Production Build 1. The CLI changes into `frontend/` and executes the `build` task found in the project `Taskfile.yml` (`npm run build` by default). 2. Output is written to `frontend/dist/`. 3. A **content hash** manifest is produced (`manifest.json`) so cache-busting works out of the box. If the task fails the pipeline aborts early, returning the exit code of your build tool. --- ## 3. Embedding Assets Implemented in `internal/assetserver/build_production.go`: * Walks `frontend/dist` and generates a `go:embed` file `bundled_assetserver.go` (ignored by git). * Adds the `production` build tag. Result: the final binary contains every HTML/JS/CSS byte, so the executable is self-contained. --- ## 4. Native Compilation ### Build Flags | Flag | Purpose | |------|---------| | `-tags production` | Select prod asset server & runtime stubs | | `-ldflags "-s -w"` | Strip symbol table & DWARF (smaller binaries) | | `-X internal/buildinfo.BuildTime=$(date)` | Embed reproducible metadata | `internal/commands/tool_buildinfo.go` collects version, git commit, and build time then injects them using `go build -ldflags`. ### Cross Compilation Matrix | OS | Arch | Build Tag | CGO | Notes | |----|------|-----------|-----|-------| | Windows | amd64 / arm64 | `windows` | cgo enabled for WebView2 | Generates `.syso` via `internal/commands/syso.go` | | macOS | amd64 / arm64 | `darwin` | cgo enabled (Objective-C) | Codesign & notarisation tasks available | | Linux | amd64 / arm64 | `linux` | pure Go (webkit option) | GTK/WebKitGTK headers required for CGO build | `wails3 build -platform darwin/arm64` overrides GOOS/GOARCH. If CGO is needed on the host that can't compile the target (e.g. building Windows from Linux), the CLI falls back to **Docker** images (`ghcr.io/wailsapp/cross-compiler`). --- ## 5. Post-Processing ### Icons & Resources * **Windows** – `syso.go` merges your PNG/ICO into a `.syso` that `go build` links automatically. Also writes `manifest.xml` enabling High-DPI support. * **macOS** – `icons.go` turns `icon.png` → `.icns`, injects into `MyApp.app/Contents/Resources`. * **Linux** – `.desktop` files are generated in `/usr/share/applications` by each packager backend. ### Code Signing (Optional) * macOS: `codesign` + `xcrun altool --notarize-app` * Windows: `signtool.exe` * Linux: Not common (repository GPG handled externally) Task targets: `sign:mac`, `sign:windows`. --- ## 6. Packaging Back-Ends ### Linux | Artefact | Code Path | Tooling | |----------|-----------|---------| | **AppImage** (default) | `internal/commands/appimage.go` | `linuxdeploy` + `linuxdeploy-plugin-gtk` | | **deb / rpm / pacman** | `internal/packager` | `fpm` (invoked via Go) | Flags: ``` wails3 build -package deb # produces myapp_1.0.0_amd64.deb wails3 build -package rpm ``` ### macOS * **DMG** – `internal/commands/packager.go` calls `appdmg` to generate a drag-&-drop installer. * **ZIP** – fallback if `appdmg` is missing. * Sets CFBundle identifiers and version plist automatically. ### Windows * **MSI** – `internal/commands/packager.go` wraps **WiX** candle & light tools. Heat autogenerates the component tree from the built `.exe`. Extra resources: * `internal/commands/windows_resources/` contains templated **.wxs** fragments. * Version info injected via `rsrc` utility. --- ## 7. Build Artefact Layout After a successful build the CLI prints: ``` build/bin/ ├── myapp-linux-amd64 └── myapp-linux-amd64.AppImage build/package/ └── myapp_1.0.0_amd64.deb ``` The exact files depend on `-platform` and `-package` flags. --- ## 8. Customising the Pipeline | Need | Approach | |------|----------| | Run a linter before build | Add a `lint` task in **Taskfile.yml** and make `build` depend on it. | | Extra linker flags | `wails3 build -ldflags "-H windowsgui"` | | Skip packaging | `wails3 build -skip-package` (keeps raw binary). | | Bring your own packager | Implement `internal/packager/.go`, register in `packager.go`. | All Taskfile targets use environment variables exported by the CLI, so you can reference values like `$WAILS_VERSION` or `$WAILS_PLATFORM` inside custom tasks. --- ## 9. Troubleshooting | Symptom | Likely Cause | Fix | |---------|--------------|-----| | **`ld: framework not found WebKit` (mac)** | Xcode CLI tools missing | `xcode-select --install` | | **Blank window in prod build** | Frontend build failed or SPA routing | Check `frontend/dist/index.html` exists and `History API Fallback` is set. | | **`wixl` not found** (Linux MSI cross-build) | WiX toolset not installed in Docker image | Use `--docker` build or install WiX manually. | | **Duplicated symbol `_WinMain`** | Mixed `windowsgui` flag and syso | Remove custom `-ldflags` or let Wails manage resources. | Verbose mode: `wails3 build -verbose` dumps every command executed. --- ## 10. Key Source Map | Concern | File | |---------|------| | Task runner glue | `internal/commands/task_wrapper.go` | | Build dispatcher | `internal/commands/build-assets.go` | | AppImage builder | `internal/commands/appimage.go` | | Generic packager interface | `internal/packager/packager.go` | | Windows resource generator | `internal/commands/syso.go` | | Build info injector | `internal/commands/tool_buildinfo.go` | | Version constants | `internal/version/version.go` | Keep this table handy when you trace a build failure. --- You now have the full picture from **source code** to **installer**. Armed with this knowledge you can tweak the pipeline, add new packaging targets, or debug cross-compilation issues without fear. Happy shipping!