Przejdź do treści
Biblioteka skilli
Programowanie · Budowanie i kod

flutter-web

/flutter-web

Pomaga przy buildach Flutter web: kod z dart:js_interop, package:web i dart:ui_web, testy niekompilujące się na VM, biała strona po buildzie oraz QA działającej aplikacji w przeglądarce.

Repozytorium
flutter-skills ↗
Licencja
MIT
Ostatnia zmiana repozytorium
21.09.2026

Ocena i bezpieczeństwo

100/ 100Klasa: dobry
Format25 / 25
Frontmatter z nazwą i opisem, poprawna nazwa, opis do 1024 znaków, nazwa zgodna z folderem.
Odkrywalność25 / 25
Opis mówi, kiedy użyć skilla, ma sensowną długość i jest w 3. osobie.
Treść35 / 35
Co najmniej 150 słów i do 500 linii, nagłówki, listy kroków, przykłady albo kod.
Higiena15 / 15
Bez zaślepek typu TODO, bez ścieżek Windows, z licencją.
Ryzykobrak sygnałów w skanie
Pliki w paczce
1
Skrypty
0
Komentarze HTML
0
Adresy URL w SKILL.md
0
Przestarzałość

Brak sygnałów. Repozytorium zmienione 21.09.2026, bez odwołań do wycofanych modeli i API.

Licencja

MIT, otwarta: można używać i zmieniać, z zachowaniem informacji o autorze.

Co robi i kiedy

Pomaga przy buildach Flutter web: kod z dart:js_interop, package:web i dart:ui_web, testy niekompilujące się na VM, biała strona po buildzie oraz QA działającej aplikacji w przeglądarce.

Wyzwalacze z opisu

works on mobile but not on web
Oryginalny opis (EN)

Use when working on a Flutter web build - code touching dart:js_interop, package:web or dart:ui_web; tests that will not compile on the VM runner; a blank white page after a build; or QA of a running web app in a browser. Triggers on "works on mobile but not on web", a suite that breaks after a web import is added, or a screen that looks frozen in the browser.

Jak działa

  1. Browser QA only counts in a visible tab
  2. Browser-layer code needs the Chrome test runner
  3. Blank white page after changing a path dependency
  4. Watch the import chain, not just the import
  5. Checklist before shipping a web change
  6. Common mistakes
Sekcje z nagłówków SKILL.md, w oryginale · 166 linii, 1 126 słów
Podgląd SKILL.md
---
name: flutter-web
description: Use when working on a Flutter web build - code touching dart:js_interop, package:web or dart:ui_web; tests that will not compile on the VM runner; a blank white page after a build; or QA of a running web app in a browser. Triggers on "works on mobile but not on web", a suite that breaks after a web import is added, or a screen that looks frozen in the browser.
---

You are working on a Flutter **web** build. Everything here is a lesson that
cost real hours — each one looks like an application bug and is not.

## Browser QA only counts in a visible tab

Flutter web drives its **entire** frame pipeline from `requestAnimationFrame`,
and Chrome throttles rAF to near zero in a tab that is not the active one. In a
background tab the app still runs — events are processed, network calls fire —
but it barely paints. So route transitions appear frozen for tens of seconds,
and click coordinates read off a screenshot land nowhere, because the painted
frame no longer matches the real hit-test layout.

That looks exactly like two bugs that do not exist: a slow splash screen and
broken Tab traversal.

Before blaming the app:

```js
document.visibilityState   // must be "visible"
```

If it reports `hidden`, bring the browser window forward and make the tab
active. Two things stay reliable either way, and are the better evidence:

- `performance.getEntriesByType('resource')` for real timings — in one case it
  showed auth resolving at 1.4s while the screen looked stuck for 20s.
- `document.activeElement`, and the hidden `<input>` Flutter creates for the
  focused text field, which proves where focus actually is.

Each CDP screenshot forces one frame, so consecutive screenshots step a stalled
transition forward — useful, and itself a hint that you are in a throttled tab.

## Browser-layer code needs the Chrome test runner

Anything touching `dart:js_interop` or `package:web` — `getUserMedia`,
`MediaRecorder`, an `<audio>` element — **cannot even compile** under the
default VM test runner.

`@TestOn('browser')` is what makes that survivable: `flutter test` *skips* an
annotated file instead of compiling it. The browser layer is untested by
default, not untestable:

```bash
flutter test                      # VM: controllers, repositories, pure widgets
flutter test --platform chrome    # the browser layer
```

**Both commands run over `test/`.** Do not move browser tests to a directory of
their own — the web runner builds its entrypoint with `test/` as the root, so a
path outside it becomes a `../` that does not resolve and nothing compiles at
all. The annotation is the separator, not the directory.

The trap that makes this dangerous: `flutter test` alone reports **green** over
a browser test that never compiled. Run both before pushing, and run both in
CI as two separate steps.

`--platform chrome` is also flaky or unavailable on some machines (a file with
`@TestOn('browser')` hanging at *loading* until the test timeout is the usual
symptom). Where that happens, CI is the only place the browser layer runs — so
prefer **pulling the logic out of the browser-bound file into a plain Dart
one** and testing that on the VM runner.

### Make it testable: contract first, js_interop behind it

Declare the **minimum contract as an abstract class**, keep the `js_interop`
implementation behind it, and inject it so a widget test can pass a fake:

```dart
abstract class AudioRecorder {
  Future<void> start();
  Future<Uint8List?> stop();
  void dispose();
}

// browser_audio_recorder.dart — the only file importing package:web
class BrowserAudioRecorder implements AudioRecorder { ... }
```

### Every exit path must release a browser resource

When a widget holds a browser resource, release it on **every** way out —
not only the happy one:

- `dispose()` unconditionally, rather than only when a `_recording` flag flipped.
- A release when the screen turns out to be unmounted after an `await`.
- A guard so a second tap during the first `await` is a no-op.

A real leak was exactly the gap between those: permission was still pending, so
the flag had not flipped, so `dispose()` released nothing — and an orphaned
ticker wrote to a closed `StreamController` every 200 ms for the life of the tab.

## Blank white page after changing a path dependency

Path dependencies (a `design_system/` or `calendar/` package in the same repo)
are not always picked up by the incremental web build. It emits a bundle that
compiles, loads every asset, throws no JS error — and renders a blank white page
with an empty `<flutter-view>`. Hours disappear looking for a bug in code that
is fine.

```bash
rm -rf build/web && flutter build web --release --dart-define=BASE_URL=...
```

Do that **before** concluding anything from a blank screen.

## Watch the import chain, not just the import

A web-only import poisons every file that reaches it transitively, and the
compiler names the file that failed — not the file at fault.

The classic shape: a `app_routes.dart` holding both the route-name constants
*and* the route table. The table imports every screen, one of which imports
`dart:ui_web`. A sign-out use case importing that file for **one string
constant** then makes every VM test that touches it fail to compile, taking the
whole suite with it.

The fix is to split the constants into a file that imports nothing:

```dart
// app_route_names.dart — imports nothing
class AppRouteNames {
  static const login = '/login';
  static const home  = '/home';
}

// app_routes.dart — re-exports the names, and owns the table
export 'app_route_names.dart';

class AppRoutes { /* onGenerateRoute + the table */ }
```

Re-export at the **library** level, with `export`. Do not try to inherit the
names (`class AppRoutes extends AppRouteNames`): Dart does not inherit static
members, so `AppRoutes.login` would not resolve even when it compiles — and if
the names class is `final`, extending it is a compile error outright. Callers
say `AppRouteNames.login`; the `export` is what saves them a second import.

Screens and the root widget may import the table. A use case, a repository or
an interceptor may not — they take the names file.

So when the VM suite fails to **load** a file rather than fail an assertion,
read which file it named, then walk the import chain back to the web-only leaf.

## Checklist before shipping a web change

```bash
flutter analyze
flutter test                              # VM
flutter test --platform chrome            # browser layer
rm -rf build/web
flutter build web --release --dart-define=BASE_URL=<api-url>
```

## Common mistakes

- Debugging a "frozen" screen in a background tab. Check `document.visibilityState` first.
- Trusting a green `flutter test` over code that only compiles on the browser runner.
- Moving browser tests out of `test/` — `--platform chrome` cannot resolve a path outside it.
- Calling `js_interop` straight from a widget instead of behind an injectable interface.
- Releasing a browser resource only on the happy path. Unmount during an `await` is a real exit.
- Concluding "blank page = my bug" without a clean `build/web` rebuild first.
- Importing the route *table* from a use case or interceptor just to read one route name.
- Forgetting `--dart-define=BASE_URL`, so the compile-time constant is `""` and every call fails. See **flutter-run**.
- Leaving semantics off — Flutter web disables them by default. See **flutter-accessibility**.

Wersje

W bazie nie ma innych skilli o nazwie flutter-web.

Migawka bazy z 28.10.2026 · wersja paczki a1cff4ecc931 (skrót SHA-256 całej paczki)

Pobrania w ostatnich 30 dniach: 0 · ranking

Zgłoś problem z tym skillem: szkodliwa treść, błędny opis albo prośba autora o usunięcie.

Podobne skille

  • 100dart-n-flutter
    Prowadzi pisanie kodu Dart i Flutter zgodnie z oficjalnymi zaleceniami dla plików .dart.
  • 100dart-expert
    Pomaga w Dart i Flutter przy aplikacjach mobilnych i wieloplatformowych, w tym widgetach i frameworku Flutter.
  • 95flutter-development
    Wspiera tworzenie aplikacji wieloplatformowych we Flutterze i Dart na iOS, Androida, web, desktop i systemy wbudowane, z projektami Material i Cupertino oraz optymalizacją Dart.
  • 100flutter-app
    Pracuje w repozytorium Flutter i Dart w sandboxie: rozwiązuje prywatne zależności pub, uruchamia analyze i testy oraz sprawdza UI na emulatorze Androida lub po kompilacji do web ze zrzutami ekranu.
  • 100flutter-mcp-toolkit-debug
    Diagnozuje problemy w działającej aplikacji Flutter: czyta logi, ewaluuje wyrażenia Dart i interpretuje koperty błędów.
  • 90mobile-flutter
    Pomaga pisać aplikacje Flutter i Dart: układy, formularze, routing go_router, HTTP, bazy lokalne i wtyczki.

Uwagi i zgłoszenia

Wiadomość trafi do Bartosza Sokolińskiego. Adres e-mail jest potrzebny tylko do odpowiedzi. Szczegóły w polityce prywatności.