Building Desktop Apps with Wails #7 Adding a Frontend Framework — Svelte, Vue, React
The six main posts (#1–#6) built the front half in vanilla JavaScript. That is the leanest way to learn the concepts, but a framework is easier in a real app where screens grow and state intertwines. This deep-dive post covers attaching a frontend framework like Svelte, Vue, or React to Wails. It covers the gap left by the practice track’s assumption of a lightweight component framework.
This series is six main posts plus two deep-dives, eight in all.
- Main: #1 · #2 · #3 · #4 · #5 · #6
- Deep-dive: #7 Adding a frontend framework — Svelte, Vue, React ← this post · #8 Debugging — dev tools, logs, common errors
What it means that Wails is frontend-agnostic #
As seen in #2, a Wails project splits into a Go root and a frontend directory. Wails does not care what you use inside that frontend directory. All Wails requires is exactly two things: a command to install the frontend and a command to build it. Both live in wails.json.
{
"frontend:install": "npm install",
"frontend:build": "npm run build"
}wails dev and wails build call these commands to prepare the frontend and bundle its output (static files) into the final binary. So any framework that builds with Vite fits naturally. Svelte, Vue, React, Solid — all the same within this structure.
Starting with a wails init template #
For a new project, starting from a framework template is easiest. Pass a template name to the -t option of wails init.
wails init -n myapp -t svelte # or svelte-ts
wails init -n myapp -t vue # or vue-ts
wails init -n myapp -t react # or react-ts
wails init -n myapp -t vanilla # the default used in the main seriesTemplates with -ts are the TypeScript variants. A template preconfigures frontend with that framework and Vite, so right after generating, just wails dev and the hot-reload loop runs as-is. Whichever framework you pick, the Go-side code (#3’s bindings, #4’s runtime) does not change at all.
Bindings are the same regardless of framework #
The way Wails exposes Go methods as frontend functions (#3) is identical regardless of framework. Import the bindings auto-generated in the wailsjs folder and call them. Below is the same Greet call in three frameworks — the only difference is how you connect state to the screen.
<script>
import { Greet } from "../wailsjs/go/main/App";
let name = "", result = "";
async function greet() { result = await Greet(name); }
</script>
<input bind:value={name} />
<button on:click={greet}>Greet</button>
<p>{result}</p><script setup>
import { ref } from "vue";
import { Greet } from "../wailsjs/go/main/App";
const name = ref(""), result = ref("");
const greet = async () => { result.value = await Greet(name.value); };
</script>The key is that the line import { Greet } from "../wailsjs/go/main/App" is the same across the three frameworks. The part that calls the Go method is common, and only the way you reflect the result on screen — bind:value (Svelte) or ref (Vue) — differs per framework. This makes clear why the practice track puts the truth of the data in Go and leaves the frontend to the screen: whatever the framework, there is one way to call Go.
What to choose #
- Vanilla: no dependencies and the smallest bundle. Fits simple-state tools like the main series.
- Svelte: light, with reactivity baked into the syntax, matching a desktop app’s small bundle well.
- Vue, React: large ecosystems and component assets, and zero learning cost if the team already knows them.
The right answer is what the team already uses. If you must learn something new, desktop apps value bundle size and simplicity, so starting with vanilla or Svelte and growing when needed is the safe path.
Adding to a vanilla app later #
To add a framework to an app that already started vanilla, replace the frontend directory with that framework’s Vite project and confirm wails.json’s build command matches. Vite’s build output path must match where Wails expects it (frontend/dist); if it does not, you get the “window opens but the screen is blank” symptom covered in #8.
Summary #
- Wails is frontend-agnostic. As long as
wails.json’s install and build commands match, any framework that builds with Vite fits. - A new project is easiest started with
wails init -t svelte|vue|react(or the-tsvariant). The Go-side code stays the same regardless of framework. - Binding calls (
import { Greet } from "../wailsjs/...") are identical across the three frameworks. Only the way you connect the result to the screen differs. - Prefer what the team uses; if learning new, small-bundle vanilla or Svelte suits the desktop.
- When adding to vanilla later, match Vite’s output path to where Wails expects it. A mismatch gives a blank screen.
- Next post covers debugging — catching common errors, including this one, with dev tools and logs.