Flutter Web на WebAssembly: почему падает сборка --wasm и как это починить
Flutter Web собирается в WebAssembly командой «flutter build web --wasm» на Flutter 3.22 и новее. Сборка падает, если в проекте остались пакеты с «dart:html». Wasm-версия запускается в Chrome и Edge; где браузер не тянет Wasm, Flutter сам отдаёт обычную JS-сборку. Для кабинета с тяжёлыми таблицами и графиками переход даёт более плавную отрисовку.
Почему сборка Flutter Web под WebAssembly падает 🧱
Менеджеры московского дистрибьютора открывают веб-кабинет заказов на ноутбуках. Прайс на несколько тысяч позиций прокручивается рывками, фильтр отвечает с заметной задержкой. Разработчик читает, что Wasm ускоряет отрисовку, добавляет флаг в команду сборки, и CI краснеет: библиотека «dart:html» недоступна на этой платформе.
Причина не во Flutter. Один из пакетов в зависимостях, например старая библиотека выгрузки в Excel, написан под JS-компиляцию и обращается к браузеру через «dart:html». Wasm эту библиотеку не поддерживает, поэтому сборка останавливается на первом же импорте.
Пока сборка красная, кабинет остаётся прежним: менеджеры листают прайс рывками, а часть заказов уходит по телефону и в мессенджеры. В 1С такие заказы попадают вручную, с опечатками в артикулах. Если флаг включили в спешке и выложили без проверки на реальных устройствах, ошибка всплывёт у пользователей: например, у торгового агента с iPhone в день отгрузки.
Старые зависимости с dart:html
Wasm-компилятор не принимает «dart:html», «dart:js», «dart:js_util» и «package:js». Вместо них нужны «package:web» и «dart:js_interop». Свой код можно переписать сразу, с чужими пакетами сложнее: приходится ждать обновления автора или менять пакет.
Браузер без WasmGC
Flutter компилирует в Wasm с расчётом на сборку мусора внутри самого WebAssembly, она называется WasmGC. Chrome поддерживает её с версии 119, Edge работает на том же движке. По остальным браузерам смотрите документацию Flutter для вашей версии: список менялся от релиза к релизу. Где WasmGC нет, приложение запускается из JS-сборки.
Как исправить: переводим кабинет на Wasm по шагам 🛠️
Порядок рассчитан так, чтобы рабочая версия кабинета не пострадала: все шаги идут в отдельной ветке и на тестовом адресе.
- ✓Обновите Flutter до 3.22 или новее: сборка в Wasm доступна начиная с этой версии.
- ✓Запустите «flutter build web --wasm». Вывод покажет файлы и пакеты, где остались несовместимые импорты.
- ✓Переведите свой код с «dart:html» на «package:web», а вызовы JavaScript на «dart:js_interop». Чужие пакеты обновите до версий с поддержкой Wasm: на pub.dev у пакета видна отметка о совместимости. Если замены нет, ищите другой пакет или выносите нужную функцию в собственный модуль.
- ✓Настройте на веб-сервере заголовки «Cross-Origin-Opener-Policy: same-origin» и «Cross-Origin-Embedder-Policy: credentialless» (или «require-corp»). Они включают многопоточную отрисовку. Без них приложение запустится, но будет рисовать в одном потоке. Заодно проверьте, что файлы .wasm отдаются с типом «application/wasm».
- ✓Выложите сборку на тестовый адрес и откройте с устройств ваших пользователей: ноутбука менеджера, планшета склада, iPhone торгового агента.
В кабинетах для бизнеса «dart:html» обычно прячется там, где приложение говорит с браузером напрямую: выгрузка отчёта в файл, токен в localStorage, печать документа, открытие ссылки в новой вкладке. Начните поиск с этих мест.
Когда сборка прошла, сравните скорость до и после на тех экранах, ради которых затевали переход: прайс, остатки, графики продаж. Измеряйте на ноутбуке менеджера, а не на мощной машине разработчика: на слабом железе разница другая.
Какой режим сборки выбрать для кабинета 📊
Wasm нужен не каждому кабинету. Выигрыш заметен там, где экран считает и рисует много: большие таблицы, графики, карточки с фильтрами. В форме заявки из пяти полей разницы не будет, и переход ради перехода добавит только работы.
| Режим сборки | Где запускается | Что нужно от сервера | Когда выбирать |
|---|---|---|---|
| Только JS | Все современные браузеры, включая iPhone | Обычная раздача файлов | Простые экраны, старые устройства у пользователей |
| Wasm, один поток | Браузеры с WasmGC, например Chrome и Edge | Тип «application/wasm» для файлов .wasm | Внутренний кабинет на корпоративных ноутбуках |
| Wasm, несколько потоков | Те же браузеры | Заголовки COOP и COEP | Тяжёлые таблицы и графики, если нет чужих встроенных виджетов |
| «--wasm» с запасной JS-сборкой | Wasm там, где браузер умеет, JS там, где нет | Оба набора файлов, заголовки COOP и COEP | Кабинет для клиентов с неизвестными браузерами |
Складу с корпоративными ноутбуками на Chrome хватает Wasm с несколькими потоками. Публичному кабинету для клиентов с неизвестными браузерами нужна сборка с запасной JS-версией. В свежих версиях Flutter «flutter build web --wasm» кладёт в выдачу обе, а нужную выбирает загрузчик при открытии страницы.
Что делать, если ошибка повторяется 🔁
Сборка проходит, но кабинет открывается без картинок и карты
Заголовок «Cross-Origin-Embedder-Policy» блокирует всё, что приходит с чужих доменов без разрешения: изображения с внешнего хранилища, виджет карты, встроенный чат. В консоли браузера это видно по сообщениям о блокировке из-за политики embedder. Выход: отдавать такие ресурсы с вашего домена или с заголовком «Cross-Origin-Resource-Policy». Если не получается, уберите COEP и оставьте однопоточный Wasm.
Менеджеры видят старую версию после выкладки
Flutter кеширует файлы через service worker. Если выложить сборку по частям, браузер соберёт кабинет из старых и новых файлов. Выкладывайте каталог «build/web» целиком и выводите номер версии в подвал кабинета: по нему поддержка сразу поймёт, какую версию видит человек.
Падает на пакете, которого нет в вашем коде
Это транзитивная зависимость: её тянет другой пакет. Найдите, какой именно, командой «flutter pub deps». Обновите родительский пакет, а если его автор не выпускает обновлений, вынесите нужную функцию в свой небольшой модуль на «package:web».
Первый запуск стал дольше
Wasm-сборка грузит свои файлы, и на медленном офисном Wi-Fi это заметно. Проверьте, что сервер сжимает .wasm и .js (gzip или brotli) и что кеширование включено: повторный запуск берёт файлы из кеша и открывается быстрее.
Как предотвратить проблемы с Wasm заранее ✅
- ✓Собирайте проект в CI двумя командами: обычной и с «--wasm». Красная вторая сборка покажет новый несовместимый пакет в день появления, а не перед релизом.
- ✓Перед добавлением пакета смотрите отметку совместимости с Wasm на pub.dev.
- ✓Держите заголовки сервера в конфиге в репозитории рядом с проектом. Настройка, которая живёт в памяти одного администратора, пропадает вместе с ним.
- ✓Тестируйте на устройствах пользователей, а не только в Chrome на машине разработчика. На iPhone любой браузер работает на движке Safari, поэтому торговые агенты с iOS идут по пути Safari, как бы ни назывался браузер.
- ✓После каждого обновления Flutter читайте заметки о Web: поддержка Wasm и браузеров меняется от релиза к релизу.
Отдельно про хостинг. Если в кабинете хранятся данные физических лиц, база должна лежать на серверах в России: этого требует 152-ФЗ. Проверьте это до запуска, а не после первой жалобы клиента.
Сколько стоит кабинет на Flutter Web и что мы делаем
Мы пишем приложения и веб-кабинеты на Flutter: одна кодовая база даёт iOS, Android и веб. Подробности есть на странице разработки мобильных приложений. Мобильная разработка у нас стоит от 500 000 руб; точную сумму называем после разбора задачи.
Если Flutter-проект у вас уже есть, начинаем с проверки. Прогоняем обе сборки, собираем список пакетов, которые мешают Wasm, и по каждому говорим, что обновить, что заменить, а что переписать. Затем исправляем код, настраиваем заголовки и проверяем кабинет на устройствах вашей команды. Заголовки на сервере настраивает системный администратор, его час стоит 3800 руб; остальные расценки собраны на странице тарифов.
Наше отличие в том, что мы знаем, с чем кабинет разговаривает за экраном. Заказы, остатки и цены живут в 1С, поэтому интеграцию приложения с 1С мы закладываем с первого этапа, а не дописываем перед запуском. Готовый вариант для оптовиков и дистрибьюторов описан на странице B2B-приложения с 1С.
Wasm нужен не каждому кабинету. Если приложение только для сотрудников, работает с данными 1С и не требует публичного веба, подойдёт разработка на 1С:Мобильной платформе. Мы скажем об этом до сметы.
Пришлите ссылку на репозиторий или описание кабинета: посмотрим, где ломается сборка и нужен ли вам Wasm.
❓ Частые вопросы
Что даёт Flutter Web на WebAssembly для бизнес-кабинета?
Wasm заметнее всего помогает на тяжёлых экранах: больших таблицах, графиках, карточках с фильтрами. Для простых форм заявки разницы почти нет. Перед переходом сравните скорость на ноутбуке менеджера до и после: если экраны лёгкие, обычная JS-сборка проще в поддержке и открывается везде.
Какие браузеры поддерживают Flutter Web с Wasm?
Wasm-сборка опирается на WasmGC: Chrome поддерживает её с версии 119, Edge работает на том же движке. По Firefox и Safari сверяйтесь с документацией Flutter для вашей версии. Если браузер не подходит, Flutter сам запускает обычную JS-сборку, и кабинет остаётся доступным.
Почему «flutter build web --wasm» выдаёт ошибку про dart:html?
Ваш код или один из пакетов использует «dart:html», «dart:js» или «package:js», которые Wasm не поддерживает. Замените их на «package:web» и «dart:js_interop», а чужие пакеты обновите до версий с поддержкой Wasm. Найти виновника в зависимостях поможет команда «flutter pub deps».
Зачем серверу заголовки COOP и COEP для Flutter Web?
Они включают многопоточную отрисовку в Wasm-режиме. Без них приложение запустится, но будет рисовать в одном потоке. Есть и обратная сторона: заголовок COEP блокирует чужие ресурсы без разрешения, например карты и внешние картинки, поэтому после включения проверьте, что кабинет показывает всё нужное.
Сколько стоит разработка кабинета или приложения на Flutter?
Мобильная разработка в ukved.ru стоит от 500 000 руб. Итоговую сумму мы называем после разбора задачи: она зависит от числа экранов и глубины интеграции с 1С. Работа системного администратора, например настройка заголовков на сервере, оплачивается по ставке 3800 руб в час.
Или позвоните: +7 906 045-28-27 — в рабочее время с 9:00 до 19:00
Остались вопросы? Нужна помощь?
Менеджеры компании с радостью ответят на ваши вопросы, произведут расчет стоимости услуг и подготовят индивидуальное коммерческое предложение.
Бесплатная консультация

