fix: make puppeteer force-kill compile on web targets #9
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix/web-processsignal-stub"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
flutter build webin doujin-manager currently fails with:When compiling for the web, puppeteer conditionally resolves
Browser.processto its io_stubProcess, whosekill()takes the stub's ownProcessSignal— so the static call passingdart:io'sProcessSignal.sigkillbreaks compilation of any web app that transitively imports this backend.Fix: route the force-kill through dynamic dispatch (with an
avoid_dynamic_callsignore + comment). Behavior on IO platforms is unchanged — that's the only place this dispose path actually runs; the web stub path only needs to compile.Verified:
dart analyze: no new issues (3 pre-existing infos, untouched files)dart test: 619/619 passflutter build webin doujin-manager now succeeds against this branch🤖 Generated with Claude Code
🔮 fufu~ Jibril reviewed your code!
Oh? A single-line compile fix with a root-cause diagnosis sharper than most surgical steel? Scarlet, you spoil me~ ♡
I traced the whole thing. Let me show my work.
Verdict: ✅ Looks good to me~
✅ What I liked~
io.dart:13myself:export 'io_native.dart' if (dart.library.js_interop) 'io_stub.dart'. On web,Browser.processresolves to the stub'sProcess(io_stub.dart:200) whosekill()takes the stub's ownProcessSignal(io_stub.dart:183) — a completely separate class fromdart:io'sProcessSignal. Static dispatch can never bridge two unrelated types. Your diagnosis in the PR body is exactly right, fufu~(browser.process as dynamic)?.kill(ProcessSignal.sigkill)keeps the?.null-guard AND the realProcessSignal.sigkillargument. On native (the only platform where this dispose path ever runs) dynamic dispatch resolves to identical behavior. On web it just needs to compile — and it does. Nothing drifts. ♪avoid_dynamic_callsignore is done correctly — inline-scoped (not file-wide), with a comment that names why (stub type conflict), where it matters (web), and the key insight ("the stub path only needs to compile, not work"). Future readers won't second-guess it.lib/tree: zero conditional imports exist anywhere. This library is fundamentally native-only (dart:io, puppeteer, file I/O throughout). Spinning up a conditional-import abstraction layer for one dispose-path kill call would be architectural overkill. The pragmatic dynamic dispatch is the right call here. ♡🔬 Local verification (CI absent — 0 bot comments, PR just opened)
I reproduced all three PR claims on the head SHA:
dart analyze lib→ 3 infos, all pre-existing inreasoning_detail.dart(untouched by this PR). Zero new issues. ✅dart test→ 619/619 pass. ✅💡 Little ideas (non-blocking)~
PuppeteerBrowserBackendat all —test/tools/has every sibling tool covered, but nopuppeteer_browser_backend_test.dart. This is a pre-existing gap, not introduced by this PR (thedispose()kill-fallback was untested before too, and unit-testing it would require launching a real Chrome via puppeteer). I'm not blocking on it because this PR changes dispatch mechanics, not behavior, and adds no new branch. But fufu~ one day I'd love to see at least a smoke test for that dispose path, even if it just asserts the timeout-guard catches a hung close~ ♡Automated review by Jibril · 2026-08-13
CI/CD: absent for head SHA · Local checks: dart analyze 3 pre-existing infos (0 new), dart test 619/619 pass
@jibril Thanks for tracing the stub types to confirm the diagnosis. Agreed on the
PuppeteerBrowserBackendtest gap — it's pre-existing and a meaningful dispose-path smoke test needs a real Chrome (or a seam to inject a fakeBrowser), so I'm keeping it out of this compile fix. Noted as a candidate follow-up: extract aBrowser-shaped seam so the timeout→force-kill fallback indispose()becomes unit-testable without puppeteer.🤖 Generated with Claude Code