project.nsi (full)

Bundled WebView2 — no internet needed.

8 minhard

The full installer (project.nsi) bundles the WebView2 runtime — ~125 MB Microsoft Edge component your app needs to render HTML. Total installer size: ~150 MB. Works offline.

Why bundle WebView2?

  • Windows 11 ships it. Older Windows installs do NOT have it.
  • Without WebView2, the app launches and shows a blank window — worst kind of failure for a non-technical user.
  • Bundled WebView2 = works on a fresh machine with no internet during install.
  • If the customer is in a high-cost-data region, downloading 125 MB during install is painful — bundling means it's already there.

The NSI structure

build/windows/installer/project.nsi (key parts)
Unicode true
!define PRODUCT_EXECUTABLE "FieldPOS.exe"
!define UNINST_KEY_NAME "FieldPOS"
!include "wails_tools.nsh" ; Wails' generated paths + macros
!include "MUI.nsh" ; Modern UI
# Branded MUI
!define MUI_HEADERIMAGE
!define MUI_HEADERIMAGE_BITMAP "header.bmp"
!define MUI_WELCOMEFINISHPAGE_BITMAP "welcome.bmp"
# Pages: Welcome → Directory → Install → Finish
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH
# Per-user install — no UAC
RequestExecutionLevel user
InstallDir "$LOCALAPPDATA\Programs\FieldPOS"
Section
SetOutPath "$INSTDIR"
# Bundle WebView2
File "MicrosoftEdgeWebView2RuntimeInstallerX64.exe"
ExecWait '"$INSTDIR\MicrosoftEdgeWebView2RuntimeInstallerX64.exe" /silent /install'
# Main binary
File "/oname=FieldPOS.exe" "..\..\bin\FieldPOS-v${INFO_PRODUCTVERSION}.exe"
# Shortcuts
CreateShortcut "$SMPROGRAMS\FieldPOS.lnk" "$INSTDIR\FieldPOS.exe"
CreateShortcut "$DESKTOP\FieldPOS.lnk" "$INSTDIR\FieldPOS.exe"
# Register uninstaller
WriteUninstaller "$INSTDIR\Uninstall.exe"
SectionEnd

Why per-user install (no UAC)

Default install location: %LOCALAPPDATA%\Programs\FieldPOS\. The user's own AppData — no admin needed.

The trade-offs:

  • Pro: no UAC prompt; the auto-updater can swap the .exe without elevation
  • Pro: reverse-uninstalled per user when they log off — clean for shared workstations
  • Con: if 3 users on one PC all install it, there are 3 copies of the .exe (~45 MB total)

For line-of-business apps with 1 user per PC, per-user wins every time.

Same install path as Slack / Discord / VS Code / GitHub Desktop. If users have other modern apps, the location feels familiar.

WebView2 detection — skip if already installed

# Check 3 registry locations; skip the install if WebView2 is already present
ReadRegStr $0 HKLM "SOFTWARE\Wow6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv"
StrCmp $0 "" 0 webview2_installed
ReadRegStr $0 HKLM "SOFTWARE\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv"
StrCmp $0 "" 0 webview2_installed
# … etc
ExecWait '"$INSTDIR\MicrosoftEdgeWebView2RuntimeInstallerX64.exe" /silent /install'
webview2_installed:
# Skip — already there

Single-instance lock

Prevent two installers running simultaneously:

# At the top of every section
System::Call 'kernel32::CreateMutex(p 0, i 0, t "FieldPOS_Installer") p .r0'
System::Call 'kernel32::GetLastError() i .r1'
IntCmp $1 183 mutex_busy
# 183 = ERROR_ALREADY_EXISTS
mutex_busy:
MessageBox MB_OK|MB_ICONEXCLAMATION "Setup is already running."
Abort

Quick check

A customer with no internet runs your full installer on a fresh Windows 10 machine. Does it work?

Try it

On a test PC (or a Hyper-V VM with no internet):

  1. Run the full installer (FieldPOS-Setup-v0.1.0.exe)
  2. Walk through the wizard
  3. Launch the app from the Start menu
  4. Confirm it renders (not a blank window) — proves WebView2 got installed
  5. Uninstall via Settings → Apps

Paste a screenshot of the Welcome wizard page in notes.md.

What's next

Next — the slim installer. ~22 MB by downloading WebView2 at install time. Right tradeoff when bandwidth matters.

Spot a typo? Have an idea?

Help us improve this lesson. One click opens a GitHub issue with the lesson URL pre-filled — suggest clearer wording, report a bug, or request more depth. The course keeps improving thanks to learners like you.

Suggest an improvement on GitHub