Irbisa · Cheatsheet
Flutter on Web & Desktop
Web renderers and wasm, deferred loading, PWA, JS interop, desktop windowing, plugin gaps
How do you add web or desktop support to an existing Flutter project, and what does that generate?
# from the project root; lib/ is not touchedflutter create --platforms=web,macos,windows,linux . flutter doctor # Xcode / Visual Studio / GTK toolchainsflutter devices # chrome, macos, ...flutter run -d chrome…What are the limitations of Flutter Web, and when is it a good fit?
Which renderers does Flutter web use today (CanvasKit or skwasm), and what happened to the HTML renderer?
Your lead read that Flutter compiles to WebAssembly and asks why the production build still ships JavaScript. What do you tell them?
# Emits main.dart.wasm AND main.dart.js; flutter.js picks per browserflutter build web --release --wasm # Multi-threaded skwasm needs cross-origin isolation on the HTML documentcurl -sI https://app.example.com/ | grep -i '^cross-origin'# Cross-Origin-Embedder-Policy: credentialless…Users stare at a white page for two seconds before the web app appears. What runs before the first Flutter frame, and how do you shorten it?
// index.html: <div id="boot">skeleton markup</div> and// window.addEventListener('flutter-first-frame', () =>// document.getElementById('boot')?.remove()); // before: every await here is white screen// await Firebase.initializeApp(); await config.fetch(); runApp(...);…The admin console is imported with
deferred as, yetmain.dart.jsbarely shrank and no part file appeared. Why?// main.dartimport 'admin/admin_page.dart' deferred as admin;import 'routes.dart'; Future<Widget> openAdmin() async { await admin.loadLibrary(); return admin.AdminPage();} // routes.dart: imported eagerly by main.dartimport 'package:flutter/material.dart';import 'admin/admin_page.dart'; final routes = <String, WidgetBuilder>{ '/': (_) => const HomePage(), '/admin': (_) => const AdminPage(),};Deployed to GitHub Pages under
/my-app/, the web build shows a blank page and every asset 404s. What does--base-hreffix, and what else changes?# GitHub Pages project site: https://user.github.io/my-app/flutter build web --release --base-href /my-app/ grep '<base' build/web/index.html# <base href="/my-app/"> (web/index.html must keep <base href="$FLUTTER_BASE_HREF">)…Marketing says none of your pages show up in Google and every shared link previews the same title. What can you actually do about that?
How do you make a Flutter web app an installable PWA, and make sure users actually get the new build after a deploy?
# What browsers were told on the last deploycurl -sI https://app.example.com/main.dart.js | grep -i cache-control # nginx: revalidate the entrypoints, long caching only for files you version yourself# location ~ ^/(index\.html|flutter_bootstrap\.js|main\.dart\.(js|mjs|wasm)|version\.json)$ {# add_header Cache-Control "no-cache";…Every request from the web build fails with "XMLHttpRequest error" or "Failed to fetch" and no status code, while iOS works. What is going on?
A helper imports
dart:htmland the wasm build refuses to compile. What replaced it, and how do you call a JS SDK from Dart today?import 'dart:js_interop';import 'dart:js_interop_unsafe';import 'package:web/web.dart' as web; // before (not available to dart2wasm):// html.document.getElementById('root')!.classes.add('ready');…This conditional import works in the JavaScript build, but under
--wasmthe app silently runs the stub. Why?// storage.dartimport 'storage_stub.dart' if (dart.library.io) 'storage_io.dart' if (dart.library.html) 'storage_web.dart'; // storage_web.dartimport 'package:web/web.dart' as web; String? readToken() => web.window.localStorage.getItem('token'); // storage_stub.dartString? readToken() => null;Find the bug: the editor works on Android, iOS and macOS, but in the web release build the toolbar is just a grey box.
import 'dart:io' show Platform;import 'package:flutter/material.dart'; class EditorToolbar extends StatelessWidget { const EditorToolbar({super.key, required this.onSave}); final VoidCallback onSave; @override Widget build(BuildContext context) { final desktop = Platform.isMacOS || Platform.isWindows || Platform.isLinux; return Row(children: [ IconButton(icon: const Icon(Icons.save), onPressed: onSave), if (desktop) Text(Platform.isMacOS ? 'Cmd+S' : 'Ctrl+S'), ]); }}The same screen scrolls smoothly on a phone but janks in the browser. Why is Flutter web slower, and how do you find and fix the cost?
The marketing site is React and they want your Flutter chart on the page with data flowing both ways. How do you mount it and talk across the boundary?
// web/flutter_bootstrap.js (your copy of the template):// {{flutter_js}}// {{flutter_build_config}}// _flutter.loader.load({ config: { hostElement: document.querySelector('#chart') } });// React side: <div id="chart" style={{height: 360}} />// el.addEventListener('chart-selection', (e) => setSelected(e.detail.id));…Find the bug: after opening and closing the payment screen a few times, each
postMessageis handled several times andsetState() called after dispose()appears.class _PaymentFrameState extends State<PaymentFrame> { String _status = 'waiting'; void _onMessage(web.MessageEvent e) { if (e.origin == payOrigin) setState(() => _status = '${e.data.dartify()}'); } @override void initState() { super.initState(); web.window.addEventListener('message', _onMessage.toJS); } @override void dispose() { web.window.removeEventListener('message', _onMessage.toJS); super.dispose(); }}Export to CSV writes the file on macOS and does nothing at all in the web build. Where exactly does the browser stop you?
import 'dart:convert';import 'dart:js_interop';import 'package:file_selector/file_selector.dart';import 'package:web/web.dart' as web; // wrong on web: compiles, then fails; there is no documents directory…The app ships on web next month and pubspec has forty dependencies. How do you find the ones with no web implementation before QA does?
The desktop build opens at the runner's default size, has no real menu bar, and Cmd+Q throws away unsaved work. What is framework and what is a plugin?
import 'dart:ui' show AppExitResponse; // initial size lives in the native runner, not hereclass _EditorState extends State<Editor> { late final AppLifecycleListener _lifecycle;…You have to ship the desktop app outside any store and it must update itself. What does each platform demand before a user can double-click it?
# --- Windows ---------------------------------------------------------------flutter build windows --release# ship all of build/windows/x64/runner/Release/ : exe + DLLs + data/dart run msix:create --release # reads msix_config: from pubspec.yaml # --- macOS -----------------------------------------------------------------…