Chuyển đến nội dung chính

Shipping Flutter Web on WebAssembly: the migration, the browsers, the headers

WebAssembly is the largest single bet in Flutter’s 2026 roadmap, and 3.47 moves it forward again with experimental deferred loading. The Q2 2026 survey rates Web at 72% satisfaction — the second-lowest platform score — and load performance is a big part of why. Wasm is the intended fix.

But shipping Wasm today is not a flag. It is a migration, a browser support matrix with a large hole in it, and two HTTP headers that most people forget.

The build commands

# Development
flutter run -d chrome --wasm

# Production
flutter build web --wasm

# Production, with symbolication for error monitoring
flutter build web --wasm --source-maps

# Staging/QA — readable stack traces, ~47% larger binary
flutter build web --wasm --no-strip-wasm

Use --source-maps for anything you point Sentry or a similar service at; it produces main.dart.wasm.map. Use --no-strip-wasm only in staging — the size cost is real.

Flutter 3.47 also adds experimental deferred loading:

flutter build web --release --wasm --enable-wasm-deferred-loading

At the Dart layer this is the same capability that landed as a preview in Dart 3.13 (dart compile wasm -O2 --enable-deferred-loading), reported to give meaningful initial-page-load improvements over dart2js for large applications. For a big app this is the difference between Wasm being theoretically faster and actually faster in the metric users feel.

The browser matrix, and the iOS problem

Flutter’s Wasm output needs WasmGC. Support today:

BrowserStatus
Chromium / V8Supported, version 119+
FirefoxAnnounced, currently blocked by a known bug
SafariSupports WasmGC, but has a compatibility bug
iOS browsersCannot run it — every iOS browser uses WebKit

Read the last row again. It is not “Safari on iOS”; it is all browsers on iOS, because Apple requires WebKit. If your web traffic skews mobile, a meaningful share of your users will not execute your Wasm build at all.

Which is why the fallback matters: even with --wasm, Flutter still compiles to JavaScript. If WasmGC is not detected at runtime, the JS build runs. You are shipping both, and the browser picks. That is good for correctness and bad for anyone hoping Wasm reduces their deployment size.

To confirm which path a session took:

const isRunningWithWasm = bool.fromEnvironment('dart.tool.dart2wasm');

Log it. Otherwise you will be optimising a code path most of your users never hit.

The actual migration: get off dart:html

This is the work. Wasm will not compile if your app imports unsupported web libraries.

LegacyReplacement
dart:htmlpackage:web
dart:js, package:jsdart:js_interop

Flutter gives you an early warning without needing a Wasm build at all — running plain flutter build web performs a Wasm dry run:

Wasm dry run failed:
Found incompatibilities with WebAssembly.

package:my_app/main.dart 1:1 - dart:html unsupported (0)

Run that today, even if you have no Wasm plans. It is a free audit of your dependency tree.

When a full compilation fails, ignore the stack trace and find the Context tree — it names the package chain that pulled in the incompatible library:

Context: The unavailable library 'dart:html' is imported through these packages:
    main.dart => package:my_app => dart:html

That is usually a transitive dependency, not your code. For a gradual migration, conditional imports let both worlds coexist:

import 'fallback.dart'
  if (dart.library.js) 'legacy_web_interop.dart'
  if (dart.library.js_interop) 'wasm_web_interop.dart';

The two headers everyone forgets

Flutter Wasm apps can render across multiple threads — but only if your server sends the right cross-origin headers:

HeaderValue
Cross-Origin-Embedder-Policycredentialless or require-corp
Cross-Origin-Opener-Policysame-origin

Without both, multi-threading silently does not happen. Your app works; it is just slower than the benchmark you read. Check them in your CDN or reverse proxy config, not just in local dev — this is a classic “fast on localhost, slow in production” trap.

Note that require-corp will break embedded third-party resources that do not opt in via CORP headers. If you embed a lot of external content, credentialless is usually the pragmatic choice.

Runtime differences worth knowing

package:web and dart:js_interop under Wasm are not bit-identical to the JS backend:

  • is / as checks behave differently on JS interop types
  • Zone propagation in callbacks differs

Neither breaks a typical app, but both will bite code that does clever things with type checks across the interop boundary. Test your interop layer specifically rather than assuming parity.

Your rollout plan

  1. Run flutter build web today and read the Wasm dry run output. That is your migration backlog.
  2. Update web/index.html to the current Flutter initialization, or regenerate with flutter create . --platforms web.
  3. Migrate your own code from dart:html to package:web and from dart:js to dart:js_interop.
  4. Chase the transitive offenders named in the Context tree. File issues on dependencies that still import dart:html.
  5. Configure COOP and COEP headers in your production serving layer, then verify them with the network tab.
  6. Build with --wasm --source-maps and wire the map file into your error monitoring.
  7. Log dart.tool.dart2wasm and measure what fraction of real sessions actually get the Wasm path.
  8. Try --enable-wasm-deferred-loading if your bundle is large, and measure initial page load rather than total size.

The bottom line

Wasm is genuinely faster, and the roadmap points at it becoming the default. But today it is an additive build, not a replacement: you ship JS as well, iOS users get the JS path regardless, and the performance win depends on two headers most teams have not set. The single highest-value thing you can do this week costs nothing — run flutter build web and read the dry-run output. Whether or not you ship Wasm this quarter, that list of dart:html dependencies is a debt you will pay eventually.


Originally published on FlutterCook. Read the latest version there — that copy is the one kept up to date.

Nhận xét

Bài đăng phổ biến từ blog này

5 concepts every Flutter dev should know

  Phụ lục: State management architecture Testing IDE Shortcuts Platform channel Maintaining a project Tôi đã làm việc với Flagship trong một thời gian dài, và đây là những điều mà tôi phát hiện ra là điều cần phải có đối với bất kỳ nhà phát triển Flagship nào, về tổng thể nó sẽ khiến bạn trở thành một nhà phát triển Flagship giỏi trong thời gian dài. 1. State management architecture Đây là một trong những chủ đề quan trọng nhất trong cộng đồng thiết bị rung, nó khá quan trọng nếu bạn muốn duy trì một dự án rung kích thước trung bình hoặc lớn. Nó sẽ giúp tạo một dự án suôn sẻ và thêm các tính năng mới một cách hoàn hảo.  2. Testing Đây là một chủ đề duy nhất mà tôi không hiểu tại sao nó lại quan trọng trước đó trong sự nghiệp của tôi, nhưng khi tôi tiến lên trong sự nghiệp của mình và có kinh nghiệm với nhiều dự án và vấn đề xảy ra trong môi trường sản xuất. Tôi đã nhận ra một cách khó khăn, tại sao điều này lại quan trọng như vậy. Nếu bạn vẫn muốn có thêm lý do để cân nhắc thử...

Thiết kế giao diện với DotNetBar (Phần 1)

Đây là phiên bản DotNetBar hỗ trợ C# và Visual Basic https://www.dropbox.com/s/wx80jpvgnlrmtux/DotNetBar.rar  , phiên bản này hỗ trợ giao diện Metro cực kỳ “dễ thương” Các bạn load về và cài đặt, khi cài đặt xong sẽ có source code mẫu của tất cả các control. Để sử dụng được các control của DotNetBar các bạn nhớ add item vào controls box. Thiết kế giao diện với DotNetBar, giao diện sẽ rất đẹp. Link các video hướng dẫn chi tiết cách sử dụng và coding: http://www.devcomponents.com/dotnetbar/movies.aspx Hiện tại DotNetBar có rất nhiều công cụ cực mạnh, trong đó có 3 công cụ dưới đây: DotNetBar for Windows Forms Requires with Visual Studio 2003, 2005, 2008, 2010 or 2012.   DotNetBar for WPF Requires with Visual Studio 2010 or 2012 and Windows Presentation Foundation.   DotNetBar for Silverlight Requires with Visual Studio 2010 or 2012 and Silverlight. Dưới đây là một số hình ảnh về các control trong DotnetBar.   Metro User Interface  controls with Metro Tiles, toolba...

2026 👏 Google miễn phí một năm gói AI Plus cho sinh viên Việt Nam 🇻🇳🇻🇳🇻🇳

Chúc mừng anh em 👏 Google miễn phí một năm gói AI Plus cho sinh viên Việt Nam 🇻🇳🇻🇳🇻🇳 Đối tượng là sinh viên đại học từ 18–24 tuổi (bao gồm sinh viên mới và sinh viên từng dùng gói AI Pro 2025). Lưu ý là cần xác minh tư cách sinh viên hàng năm. Khi nhận gói, anh em có được các ưu đãi sau: 🔖 Nâng cấp bộ nhớ đám mây lên 400GB. 🔖 Nhân đôi hạn mức truy cập mô hình AI. 🔖 Mở quyền trải nghiệm tính năng tạo video bằng Gemini Omni. Lưu ý chương trình chỉ dành cho sinh viên đủ điều kiện. Hạn nhận ưu đãi: 31 tháng 12, 2026. Các bạn cần có phương thức thanh toán hợp lệ khi đăng ký. Google AI Plus sẽ tự động tính phí 132.000 ₫/tháng sau khi thời gian dùng thử kết thúc, trừ phi bạn đã huỷ trước đó. Huỷ bất cứ lúc nào. CÁC BƯỚC THỰC HIỆN CHI TIẾT 🔹Bước 1: Truy cập cổng đăng ký chương trình 🔖 Mở trình duyệt và truy cập vào trang chính thức: gemini.google/students/ 🔖 Đăng nhập vào Tài khoản Google cá nhân của bạn. 🔖 Nhấn vào nút "Claim your student plan at no cost" (hoặc Nhận gó...