Skip to content

fix(dev): fix frontend dev server startup race#5776

Draft
savely-krasovsky wants to merge 3 commits into
wailsapp:masterfrom
savely-krasovsky:fix-windows-bug
Draft

fix(dev): fix frontend dev server startup race#5776
savely-krasovsky wants to merge 3 commits into
wailsapp:masterfrom
savely-krasovsky:fix-windows-bug

Conversation

@savely-krasovsky

@savely-krasovsky savely-krasovsky commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Description

Fixes a race in wails3 dev where the native application may exit before the frontend dev server becomes ready.

The watcher starts the frontend task in the background and immediately launches the application. Previously, the application stopped waiting after 10 attempts at 500 ms intervals. Frontends that took slightly longer than five seconds to start caused a fatal error.

Fixes # (issue)

Type of change

Please select the option that is relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration using wails doctor.

  • Windows
  • macOS
  • Linux

If you checked Linux, please specify the distro and version.

Test Configuration

Please paste the output of wails doctor. If you are unable to run this command, please describe your environment in as much detail as possible.

Checklist:

  • (v2 only) I have updated website/src/pages/changelog.mdx with details of this PR (v3 changelog entries are added automatically)
  • My code follows the general coding style of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

Summary by CodeRabbit

  • New Features
    • Added wails3 tool waitport to wait for a host/port to become reachable.
    • Development startup now performs a frontend readiness wait before launching the app when a frontend dev server is configured.
  • Bug Fixes
    • Improved non-production shutdown messaging by basing readiness/behavior on whether a frontend dev server URL is set.
    • Improved MCP server initialization error reporting during startup.
  • Tests
    • Added unit tests for port-wait behavior and frontend readiness injection (including idempotency).

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7582c1e0-0ae4-46ad-81c8-00f4116ba2c7

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Development startup now includes a waitport command that polls frontend server readiness. Watcher configuration injects the command when a frontend dev server is configured, while application startup and quit-hook flows are updated.

Changes

Frontend readiness

Layer / File(s) Summary
Port readiness command
v3/internal/commands/tool_waitport.go, v3/internal/commands/tool_waitport_test.go, v3/cmd/wails3/main.go
Adds the waitport CLI command, environment-based port resolution, bounded polling, timeout errors, and helper tests.
Watcher readiness wiring
v3/internal/commands/watcher.go, v3/internal/commands/watcher_test.go, v3/internal/commands/build_assets/config.yml, v3/internal/commands/dev_config_test.go
Adds a one-time frontend readiness task when configured, avoids duplicates, and validates generated command ordering.
Application startup lifecycle
v3/pkg/application/application.go, v3/pkg/application/application_dev.go, v3/pkg/application/application_production.go
Removes the preRun invocation, moves MCP initialization within startup, and updates quit-hook behavior and signatures.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Watcher
  participant CLI
  participant ToolWaitPort
  participant FrontendDevServer
  Watcher->>CLI: run wails3 tool waitport
  CLI->>ToolWaitPort: pass host, port, and timeout
  ToolWaitPort->>FrontendDevServer: poll configured port
  FrontendDevServer-->>ToolWaitPort: connection result
  ToolWaitPort-->>Watcher: continue or return timeout
Loading

Suggested labels: reviewed ✅

Suggested reviewers: leaanthony

Poem

I’m a bunny who waits by the port,
Till the frontend hops into court.
One check, then retry—
No server? Goodbye!
Then startup proceeds with a snort.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly matches the main change: fixing the frontend dev server startup race in wails3 dev.
Description check ✅ Passed The description includes summary, motivation, testing platforms, and change type, but the issue number and test configuration are still placeholders.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@savely-krasovsky

Copy link
Copy Markdown
Contributor Author

This was my constant struggle while I develop Windows App. I don't know, maybe because of Windows Defender or something else, but on Windows frontend part start kind of long and I was contantly getting this race:

$ wails3 dev
Wails v3.0.0-alpha2.117 › Build
task: [windows:common:go:mod:tidy] go mod tidy
task: Task "windows:common:generate:icons" is up to date
task: [windows:common:go:mod:tidy] go mod tidy
task: [windows:common:install:frontend:deps] pnpm install
Already up to date
Done in 39ms using pnpm v11.8.0
task: [generate:bindings (BUILD_FLAGS=-buildvcs=false -gcflags=all="-l")] wails3 generate bindings -f '-buildvcs=false -gcflags=all="-l"' -clean=true -ts
Wails v3.0.0-alpha2.117 › Generate Bindings
 INFO  Processed: 332 Packages, 1 Service, 33 Methods, 40 Enums, 152 Models, 3 Events in 1.0032622s.                                                                                                      
 INFO  Output directory: D:\projects\fidoapp\frontend\bindings
task: [build:frontend (DEV=true)] pnpm run build:dev
$ vite build --minify false --mode development
vite v8.0.16 building client environment for development...
✔ [paraglide-js] Compilation complete (message-modules)                                                                                                                                                
✓ 5746 modules transformed.
computing gzip size...
dist/index.html                                                       0.39 kB │ gzip:   0.28 kB
dist/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2      7.50 kB
dist/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2           9.00 kB
dist/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2       12.10 kB
dist/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2      15.19 kB
dist/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2          40.40 kB
dist/assets/index-Bf6eh-vi.css                                      170.34 kB │ gzip:  26.53 kB
dist/assets/index-B8pXrTFH.js                                     2,640.94 kB │ gzip: 411.61 kB

[PLUGIN_TIMINGS] Your build spent significant time in plugins. Here is a breakdown:
  - wails-typed-events (85%)
  - vite-plugin-svelte:compile (7%)
  - vite-plugin-svelte:preprocess (7%)
See https://rolldown.rs/options/checks#plugintimings for more details.

✓ built in 4.75s
task: [windows:generate:syso] wails3 generate syso -arch amd64 -icon windows/icon.ico -manifest windows/wails.exe.manifest -info windows/info.json -out ../wails_windows_amd64.syso
task: [windows:build:native] go build -buildvcs=false -gcflags=all="-l" -o "bin/fidoapp.exe"
task: [windows:build:native] powershell Remove-item *.syso

Need documentation? Run: wails3 docs
 ♥   If Wails is useful to you or your company, please consider sponsoring the project: wails3 sponsor
task: [windows:run] bin/fidoapp.exe
Jul 13 02:36:23.779 INF Build Info: Wails=v3.0.0-alpha2.117 Compiler=go1.26.4 -compiler=gc -gcflags=all=-l CGO_ENABLED=0 GOARCH=amd64 GOOS=windows GOAMD64=v1 -buildmode=exe
Jul 13 02:36:23.780 INF AssetServer Info: middleware=true handler=true devServerURL=http://localhost:9245
Jul 13 02:36:23.780 INF Platform Info: Go-WebView2Loader=true WebView2=150.0.4078.65 ID=25H2 Name=Windows 10 Pro Version=2009 (Build: 26200) Branding=Windows 11 Pro
Jul 13 02:36:23.780 INF Waiting for frontend dev server to start... url=http://localhost:9245
task: [common:install:frontend:deps] pnpm install
Jul 13 02:36:24.287 INF Retrying...
Already up to date
Done in 28ms using pnpm v11.8.0
task: [common:dev:frontend] pnpm run dev -- --port 9245 --strictPort
Already up to date
Done in 27ms using pnpm v11.8.0
$ vite "--" "--port" "9245" "--strictPort"
Jul 13 02:36:25.289 INF Retrying...
Jul 13 02:36:26.291 INF Retrying...
Jul 13 02:36:27.293 INF Retrying...
Jul 13 02:36:28.295 INF Retrying...
✔ [paraglide-js] Compilation complete (locale-modules)                                                                                                                                                 

  VITE v8.0.16  ready in 3257 ms

  ➜  Local:   http://127.0.0.1:9245/
Jul 13 02:36:28.797 ERR 

******************************** FATAL *********************************
*      There has been a catastrophic failure in your application.      *
**************************** Error Details *****************************
unable to connect to frontend server. Please check it is running - FRONTEND_DEVSERVER_URL='http://localhost:9245'************************************************************************

  ERROR   task: Failed to run task "run": exit status 1

This PR fixes my issues completely.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@v3/pkg/application/application_dev.go`:
- Around line 25-26: Update the frontend readiness loop around client.Get in
application startup to enforce a request timeout, using an http.Client with a
finite Timeout or a context deadline for each request. Preserve the existing
retry behavior while ensuring an unresponsive frontend cannot block startup
indefinitely.
- Line 25: Update the retry documentation associated with the loop in
application startup to state that the server is retried a maximum of 30 times,
matching the loop’s 30 iterations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 54c051b6-72c9-4c79-b358-c53a6af957ca

📥 Commits

Reviewing files that changed from the base of the PR and between 3440ae5 and fc9f35a.

📒 Files selected for processing (2)
  • v3/internal/commands/dev.go
  • v3/pkg/application/application_dev.go

Comment thread v3/pkg/application/application_dev.go Outdated
Comment thread v3/pkg/application/application_dev.go Outdated
@savely-krasovsky
savely-krasovsky force-pushed the fix-windows-bug branch 2 times, most recently from dc1e1d3 to f84439e Compare July 18, 2026 13:47
@savely-krasovsky savely-krasovsky changed the title fix(dev): use loopback IP and increase frontend server wait timeout fix(dev): fix frontend dev server startup race Jul 18, 2026
@savely-krasovsky

Copy link
Copy Markdown
Contributor Author

@leaanthony could you review please? This is SO persistent on Windows, I am tired to restart wails3 dev for ten times to just finally launch it :( This commit fixes issue completely

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
v3/internal/commands/watcher.go (1)

32-36: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use a robust match for idempotency.

If a user customizes the waitport command in their configuration (e.g., adding a port flag or modifying the timeout to wails3 tool waitport --timeout 30), the exact string match will fail. This would cause a duplicate readiness task to be injected.

Consider matching on the command prefix or using strings.Contains to ensure idempotency even with customized arguments.

♻️ Proposed refactor
 	for _, execute := range config.ExecStruct {
-		if execute.Cmd == frontendDevServerReadyCommand {
+		if strings.HasPrefix(execute.Cmd, "wails3 tool waitport") {
 			return
 		}
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@v3/internal/commands/watcher.go` around lines 32 - 36, Update the command
comparison in the ExecStruct loop to recognize customized waitport commands,
including added flags or timeout arguments, instead of requiring an exact match
with frontendDevServerReadyCommand. Use a robust prefix or containment match
while preserving the early return that prevents duplicate readiness-task
injection.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@v3/internal/commands/build_assets/config.yml`:
- Around line 59-60: The static template should no longer define the hardcoded
waitport task; remove it from v3/internal/commands/build_assets/config.yml lines
59-60 and rely on watcher.go’s dynamic injection when FRONTEND_DEVSERVER_URL is
active. Update the related assertions in v3/internal/commands/dev_config_test.go
lines 22-26 to expect three tasks and remove the explicit waitport-task match.

---

Nitpick comments:
In `@v3/internal/commands/watcher.go`:
- Around line 32-36: Update the command comparison in the ExecStruct loop to
recognize customized waitport commands, including added flags or timeout
arguments, instead of requiring an exact match with
frontendDevServerReadyCommand. Use a robust prefix or containment match while
preserving the early return that prevents duplicate readiness-task injection.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ac16d6dc-5c26-4f29-a8ee-c50795729fe7

📥 Commits

Reviewing files that changed from the base of the PR and between f84439e and aaae62b.

📒 Files selected for processing (10)
  • v3/cmd/wails3/main.go
  • v3/internal/commands/build_assets/config.yml
  • v3/internal/commands/dev_config_test.go
  • v3/internal/commands/tool_waitport.go
  • v3/internal/commands/tool_waitport_test.go
  • v3/internal/commands/watcher.go
  • v3/internal/commands/watcher_test.go
  • v3/pkg/application/application.go
  • v3/pkg/application/application_dev.go
  • v3/pkg/application/application_production.go

Comment on lines +59 to +60
- cmd: wails3 tool waitport --timeout 60
type: once

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Remove the hardcoded waitport command from the static template.

Hardcoding the waitport command in the default configuration breaks wails3 dev for projects that do not use a frontend development server. In these projects, WAILS_VITE_PORT will be unset, causing the hardcoded command to fail and halt the watcher's startup entirely.

Since watcher.go correctly and dynamically injects this task only when a frontend dev server is active (by checking FRONTEND_DEVSERVER_URL), relying exclusively on the dynamic injection prevents startup failures in non-dev-server setups.

  • v3/internal/commands/build_assets/config.yml#L59-L60: Remove the hardcoded waitport task so that projects safely default to dynamic injection.
  • v3/internal/commands/dev_config_test.go#L22-L26: Update the assertions to expect an array length of 3 instead of 4, and remove the explicit match for the waitport task to align with the template changes.
📍 Affects 2 files
  • v3/internal/commands/build_assets/config.yml#L59-L60 (this comment)
  • v3/internal/commands/dev_config_test.go#L22-L26
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@v3/internal/commands/build_assets/config.yml` around lines 59 - 60, The
static template should no longer define the hardcoded waitport task; remove it
from v3/internal/commands/build_assets/config.yml lines 59-60 and rely on
watcher.go’s dynamic injection when FRONTEND_DEVSERVER_URL is active. Update the
related assertions in v3/internal/commands/dev_config_test.go lines 22-26 to
expect three tasks and remove the explicit waitport-task match.

@savely-krasovsky savely-krasovsky changed the title fix(dev): fix frontend dev server startup race DRAFT: fix(dev): fix frontend dev server startup race Jul 22, 2026
@savely-krasovsky savely-krasovsky changed the title DRAFT: fix(dev): fix frontend dev server startup race fix(dev): fix frontend dev server startup race Jul 22, 2026
@savely-krasovsky
savely-krasovsky marked this pull request as draft July 22, 2026 13:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant