Irbisa · Шпаргалка
Flutter в вебе и на десктопе
Рендереры и wasm, отложенная загрузка, PWA, JS-интероп, окна десктопа, пробелы в плагинах
Как добавить поддержку веба или десктопа в существующий Flutter-проект и что при этом генерируется?
# 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…Какие ограничения у Flutter Web и когда он подходит?
Какие рендереры использует Flutter web сегодня (CanvasKit или skwasm) и что стало с HTML-рендерером?
Тимлид прочитал, что Flutter компилируется в WebAssembly, и спрашивает, почему прод всё ещё отдаёт JavaScript. Что вы ответите?
# 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…Пользователи две секунды смотрят на белую страницу, прежде чем появится веб-приложение. Что выполняется до первого кадра Flutter и как это сократить?
// 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(...);…Админка импортирована через
deferred as, ноmain.dart.jsпочти не похудел, а part-файл не появился. Почему?// 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(),};На GitHub Pages под
/my-app/веб-сборка показывает пустую страницу, и все ассеты отдают 404. Что исправляет--base-hrefи что ещё меняется?# 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">)…Маркетинг говорит, что ни одна страница не появляется в Google, а любая расшаренная ссылка показывает один и тот же заголовок. Что с этим реально можно сделать?
Как сделать Flutter-веб-приложение устанавливаемым PWA и добиться, чтобы пользователи действительно получали новую сборку после деплоя?
# 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";…Каждый запрос из веб-сборки падает с «XMLHttpRequest error» или «Failed to fetch» без кода статуса, а на iOS всё работает. Что происходит?
Хелпер импортирует
dart:html, и wasm-сборка не компилируется. Чем это заменили и как сегодня вызывать JS-SDK из Dart?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');…Этот условный импорт работает в JavaScript-сборке, но под
--wasmприложение молча использует заглушку. Почему?// 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;Найдите баг: редактор работает на Android, iOS и macOS, но в релизной веб-сборке вместо тулбара виден серый прямоугольник.
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'), ]); }}Тот же экран плавно прокручивается на телефоне, но дёргается в браузере. Почему Flutter web медленнее и как найти и убрать эту стоимость?
Маркетинговый сайт на React, и они хотят ваш Flutter-график на странице с обменом данными в обе стороны. Как его смонтировать и как общаться через границу?
// 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));…Найдите баг: после нескольких открытий и закрытий экрана оплаты каждый
postMessageобрабатывается по несколько раз и появляетсяsetState() called after dispose().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(); }}Экспорт в CSV на macOS пишет файл, а в веб-сборке не делает ровно ничего. Где именно вас останавливает браузер?
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…Через месяц приложение выходит в вебе, а в pubspec сорок зависимостей. Как найти те, у которых нет веб-реализации, раньше, чем это сделает QA?
Десктопная сборка открывается в размере по умолчанию из runner, без нормального меню, а Cmd+Q выбрасывает несохранённую работу. Где здесь фреймворк, а где плагин?
import 'dart:ui' show AppExitResponse; // initial size lives in the native runner, not hereclass _EditorState extends State<Editor> { late final AppLifecycleListener _lifecycle;…Десктопное приложение надо выпускать мимо сторов, и оно должно само обновляться. Что требует каждая платформа, прежде чем пользователь его запустит?
# --- 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 -----------------------------------------------------------------…