-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Description
Go + Wails + chromedp — Deep Dive Analysis
Overview
Go backend with native goroutine concurrency, Wails for desktop UI (uses system WebView), and chromedp for Chrome DevTools Protocol-based browser control. Second-ranked solution (7.85/10).
Architecture
┌──────────────────────────────────────┐
│ Wails Desktop App │
│ ┌────────────────────────────────┐ │
│ │ Go Backend │ │
│ │ - Goroutine pool (100) │ │
│ │ - Channel-based task queue │ │
│ │ - chromedp browser control │ │
│ │ - Proxy pool manager │ │
│ │ - SQLite (go-sqlite3) │ │
│ ├────────────────────────────────┤ │
│ │ System WebView (UI) │ │
│ │ - Svelte/React dashboard │ │
│ │ - Wails bindings (RPC) │ │
│ │ - Real-time updates │ │
│ └────────────────────────────────┘ │
└──────────────────────────────────────┘
│
▼
┌──────────────────────────────────────┐
│ Chrome/Chromium (headless) │
│ - 100 browser contexts via CDP │
│ - Each context: own proxy │
│ - Controlled via DevTools Protocol│
└──────────────────────────────────────┘
Key Dependencies
// go.mod
require (
github.com/chromedp/chromedp v0.10.x
github.com/wailsapp/wails/v2 v2.9.x
github.com/mattn/go-sqlite3 v1.14.x
golang.org/x/sync v0.9.x // errgroup, semaphore
)Proxy per Task Implementation
func (a *App) RunTask(config TaskConfig) (TaskResult, error) {
// Create allocator with proxy
allocCtx, cancel := chromedp.NewExecAllocator(context.Background(),
chromedp.Flag("headless", true),
chromedp.ProxyServer(config.Proxy.Server),
)
defer cancel()
ctx, cancel := chromedp.NewContext(allocCtx)
defer cancel()
// Set proxy auth if needed
if config.Proxy.Username != "" {
chromedp.ListenTarget(ctx, func(ev interface{}) {
if e, ok := ev.(*fetch.EventAuthRequired); ok {
go func() {
fetch.ContinueWithAuth(e.RequestID, &fetch.AuthChallengeResponse{
Response: fetch.AuthChallengeResponseResponseProvideCredentials,
Username: config.Proxy.Username,
Password: config.Proxy.Password,
}).Do(cdp.WithExecutor(ctx, chromedp.FromContext(ctx).Target))
}()
}
})
}
var result TaskResult
err := chromedp.Run(ctx, executeSteps(config.Steps, &result)...)
return result, err
}Concurrency Model
func (a *App) RunBatch(tasks []TaskConfig) []TaskResult {
results := make([]TaskResult, len(tasks))
sem := semaphore.NewWeighted(100) // max 100 concurrent
var wg sync.WaitGroup
for i, task := range tasks {
wg.Add(1)
go func(idx int, t TaskConfig) {
defer wg.Done()
sem.Acquire(context.Background(), 1)
defer sem.Release(1)
result, err := a.RunTask(t)
if err != nil {
result = TaskResult{Error: err.Error()}
}
results[idx] = result
// Notify UI of progress
runtime.EventsEmit(a.ctx, "task:complete", idx, result)
}(i, task)
}
wg.Wait()
return results
}Strengths
- Native concurrency: Goroutines handle 100+ tasks with ~1.5GB RAM
- Fast: Compiled binary, no runtime overhead
- Small bundle: ~15MB (no bundled browser for UI)
- Channel-based queue: Built-in Go channels, no external queue needed
- Type safety: Strong typing catches errors at compile time
- Single binary: Easy distribution
- Low memory per goroutine: ~8KB stack vs ~1MB per OS thread
Weaknesses
- chromedp limitations: No auto-wait (must implement manually), no smart selectors
- Chromium only: No Firefox/WebKit support
- No network interception: CDP fetch domain is lower-level than Playwright
- Manual auth handling: Must implement auth flows manually
- Steeper learning curve: Go + Wails + CDP knowledge needed
- WebView inconsistency: Different rendering per OS
- Less automation tooling: No codegen, no trace viewer
Resource Estimates (100 tasks)
| Resource | Estimate |
|---|---|
| RAM | ~1.5 GB |
| CPU | 2-4 cores sufficient |
| Disk | ~15MB app + system Chrome |
| Startup | <1s |
| Goroutine overhead | ~8KB each |
When to Choose This Stack
✅ Performance is top priority
✅ Team knows Go
✅ Need minimal resource usage
✅ Chromium-only testing is acceptable
✅ Don't need advanced automation (auto-wait, codegen)
✅ Want single binary distribution
❌ Avoid if: need multi-browser, need rich automation API, team doesn't know Go, or need network mocking
Verdict: 7.85/10
Best raw performance. Ideal if your team knows Go and you only need Chromium.
References issue #1 for full comparison
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels