gui/docs/ref/wails-v3/contributing/asset-server.mdx

203 lines
6.9 KiB
Text
Raw Permalink Normal View History

---
title: Asset Server
description: How Wails v3 serves and embeds your web assets in development and production
sidebar:
order: 4
---
## Overview
Every Wails application ships a **single native executable** that combines:
1. Your *Go* backend
2. A *Web* frontend (HTML + JS + CSS)
The **Asset Server** is the glue that makes this possible.
It has **two operating modes** that are selected at compile-time via Go build
tags:
| Mode | Tag | Purpose |
|------|-----|---------|
| **Development** | `//go:build dev` | Fast iteration with hot-reload |
| **Production** | `//go:build !dev` | Zero-dependency, embedded assets |
The implementation lives in
`v3/internal/assetserver/` with clear file splits:
```
assetserver_dev.go # ⬅️ runtime dev server
assetserver_production.go # ⬅️ embedded server
assetserver_darwin.go # OS-specific helpers (same for linux/windows)
asset_fileserver.go # Shared static file logic
content_type_sniffer.go # MIME type detection
ringqueue.go # Tiny LRU for mime cache
```
---
## Development Mode
### Lifecycle
1. `wails3 dev` boots and **spawns your frontend dev server**
(Vite, SvelteKit, React-SWC …) by running the task defined in
`build/Taskfile.yml` (usually `npm run dev`).
2. Wails starts the **Dev Asset Server** listening on `localhost:<random>` and
tells the Go runtime to load `http://<host>:<VITE_PORT>` as the window URL.
3. Incoming requests are handled by `assetserver_dev.go`:
```
┌─────────┐ /runtime/... ┌─────────────┐
│ Browser │ ── native bridge ───▶ │ Runtime │
├─────────┤ └─────────────┘
│ JS │ / (index.html) proxy / -> Vite
└─────────┘ ◀─────────────┐
AssetServer │
┌────────────┐
│ Vite Dev │
│ Server │
└────────────┘
```
4. Static files (`/assets/logo.svg`) are **served directly from disk** via
`asset_fileserver.go` (for speed) while anything unknown is **proxied** to
the framework dev server, giving you *instant* hot-module replacement.
### Features
* **Live Reload** Vite/Snowpack/… injects HMR WebSocket; Wails only has to
proxy it.
* **Source Map Support** because assets are not bundled, your browser devtools
map errors back to original source.
* **No Go Re-compile** Only the frontend rebuilds; Go code stays running until
you change `.go` files.
### Switching Frameworks
The dev proxy is **framework-agnostic**:
* The root `Taskfile.yml` task file injects two env vars:
`APP_NAME` & `WAILS_VITE_PORT`.
* Taskfiles for each template emit those vars before running their dev servers.
* `assetserver_dev.go` simply proxies to that target.
Add a new template → define its dev task → Asset Server just works.
---
## Production Mode
When you run `wails3 build` the pipeline:
1. Runs the frontend **production build** (`npm run build`) producing
`/frontend/dist/**`.
2. **Embeds** that folder into `go:embed` FS at compile time (see
`bundled_assetserver.go` generated file).
3. Compiles the Go binary with `-tags production` (implicit).
### Request Handling
```go
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// 1. Try embedded static assets (exact path)
// 2. Fallback to index.html for SPA routing
// 3. Sniff content-type if extension unknown
// 4. Set strong cache headers
}
```
* **MIME Detection** If the build tool produced extension-less files (e.g.
`/assets/manifest`) `content_type_sniffer.go` inspects the first 512 bytes and
caches the result in a tiny lock-free LRU.
* **Ring Queue Caching** Frequently accessed assets (logo, CSS) are kept
in-memory for the lifetime of the app, removing the need for disk or embed FS
lookups.
* **Security Headers** Disallows `file://` navigation, enables `nosniff`.
Because everything is embedded, the shipped binary has **no external
dependencies** (even on Windows).
---
## Bridging Dev ↔ Prod
Both modes expose the **same public interface**:
```go
type AssetServer interface {
URL() string // dev: http://localhost:34115, prod: wails://app
Open() error // start listening
Close() // graceful shutdown
}
```
`pkg/application` happily uses whichever implementation was compiled in, meaning
**your application code does not change** between `dev` and `build`.
---
## How Frontend Frameworks Integrate
### Templates
Each official template (React, Vue, Svelte, Solid…) contains:
* `build/Taskfile.yml`
* `frontend/vite.config.ts` (or equivalent)
They export several tasks including:
| Task | Purpose |
|------|---------|
| `dev:frontend` | Starts the framework dev server on a **random free port** and prints it to stdout (`PORT=5173`). |
| `build:frontend` | Produces static assets into `dist/` + manifest for cache-busting. |
`internal/commands/dev.go` sets the `FRONTEND_DEVSERVER_URL` env var using the hard-coded `localhost` as the `host` and the emitted `VITE_PORT` env var as the `port` and launches the **Dev Asset Server**.
Frameworks remain fully decoupled from Go:
* No need to import Wails JS SDK at build time the runtime injects it at
window creation.
* Any framework with an HTTP dev server can plug in.
---
## Extending / Customising
Need custom headers, auth, or gzip?
1. Implement `type Middleware func(http.Handler) http.Handler`
2. Register via `internal/assetserver/options.go`
3. For prod, remember to add the same middleware in `assetserver_production.go`.
---
## Key Source Files
| File | Role |
|------|------|
| `assetserver_dev.go` | Reverse proxy + disk file server |
| `assetserver_production.go` | Embedded FS handler |
| `options.go` | Config struct parsed from `pkg/options/assetserver` |
| `build_dev.go` / `build_production.go` | Build-tag wrappers selecting correct implementation |
| `bundled_assetserver.go` | Generated embed data (only present in production builds) |
---
## Gotchas & Debugging
* **White Screen in Prod** usually SPA routing: ensure `History API Fallback`
is enabled in dev and `index.html` fallback works in prod.
* **404 in Dev** mis-matched `FRONTEND_DEV_PORT`; run with
`WAILSDEV_VERBOSE=1` to print every proxied request.
* **Large Assets** they are embedded; consider
[`assetserver.WithExternalDir("/path")`](https://pkg.go.dev) to load from disk.
---
You now know how the Wails **Asset Server** feeds your web code to the native
window in both **development** and **production**.
Master this layer and you can debug loading issues, add middlewares, or even
swap in a completely different frontend tool-chain with confidence.