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

Ship Flutter Web trên WebAssembly: cuộc migrate, trình duyệt, và hai cái header

WebAssembly là canh bạc lớn nhất trong lộ trình Flutter 2026, và 3.47 đẩy nó tiến thêm một bước với deferred loading thử nghiệm. Khảo sát Q2 2026 chấm Web ở mức 72% hài lòng — điểm nền tảng thấp thứ nhì — và hiệu năng tải là một phần lớn của lý do. Wasm là phương án sửa được nhắm tới.

Nhưng ship Wasm hôm nay không phải là bật một cái cờ. Đó là một cuộc migrate, một ma trận hỗ trợ trình duyệt với một lỗ hổng lớn, và hai HTTP header mà phần lớn mọi người quên.

Các lệnh build

# Phát triển
flutter run -d chrome --wasm

# Production
flutter build web --wasm

# Production, kèm symbolication cho giám sát lỗi
flutter build web --wasm --source-maps

# Staging/QA — stack trace đọc được, binary lớn hơn ~47%
flutter build web --wasm --no-strip-wasm

Dùng --source-maps cho bất cứ thứ gì bạn trỏ Sentry hay dịch vụ tương tự vào; nó sinh main.dart.wasm.map. Chỉ dùng --no-strip-wasm ở staging — chi phí dung lượng là thật.

Flutter 3.47 cũng thêm deferred loading thử nghiệm:

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

Ở tầng Dart, đây cùng là năng lực đã ra mắt dạng preview trong Dart 3.13 (dart compile wasm -O2 --enable-deferred-loading), được ghi nhận cho cải thiện đáng kể thời gian tải trang lần đầu so với dart2js với ứng dụng lớn. Với app lớn, đây là ranh giới giữa việc Wasm nhanh hơn trên lý thuyết và nhanh hơn thật ở chỉ số người dùng cảm nhận.

Ma trận trình duyệt, và vấn đề iOS

Đầu ra Wasm của Flutter cần WasmGC. Hỗ trợ hiện tại:

Trình duyệtTrạng thái
Chromium / V8Hỗ trợ, từ bản 119+
FirefoxĐã công bố, hiện bị chặn bởi một lỗi đã biết
SafariHỗ trợ WasmGC, nhưng có lỗi tương thích
Trình duyệt trên iOSKhông chạy được — mọi trình duyệt iOS đều dùng WebKit

Hãy đọc lại dòng cuối. Không phải “Safari trên iOS”; là mọi trình duyệt trên iOS, vì Apple bắt buộc dùng WebKit. Nếu lưu lượng web của bạn nghiêng về di động, một phần đáng kể người dùng sẽ không chạy bản Wasm của bạn chút nào.

Chính vì thế fallback rất quan trọng: ngay cả với --wasm, Flutter vẫn biên dịch ra JavaScript. Nếu không phát hiện WasmGC lúc chạy, bản JS sẽ chạy. Bạn đang ship cả hai, và trình duyệt chọn. Điều đó tốt cho tính đúng đắn và tệ cho ai hy vọng Wasm giảm dung lượng triển khai.

Để xác nhận một phiên chạy theo đường nào:

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

Hãy log nó. Nếu không, bạn sẽ tối ưu một nhánh code mà phần lớn người dùng chẳng bao giờ chạm tới.

Cuộc migrate thật sự: thoát khỏi dart:html

Đây mới là phần việc. Wasm sẽ không biên dịch nếu app của bạn import thư viện web không được hỗ trợ.

Thay bằng
dart:htmlpackage:web
dart:js, package:jsdart:js_interop

Flutter cho bạn cảnh báo sớm mà không cần build Wasm — chạy flutter build web thường sẽ thực hiện một lượt Wasm dry run:

Wasm dry run failed:
Found incompatibilities with WebAssembly.

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

Hãy chạy nó ngay hôm nay, kể cả khi bạn chưa có kế hoạch Wasm. Đó là một lượt kiểm toán miễn phí cho cây dependency của bạn.

Khi biên dịch đầy đủ thất bại, hãy bỏ qua stack trace và tìm Context tree — nó nêu tên chuỗi package đã kéo thư viện không tương thích vào:

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

Thường đó là một dependency gián tiếp, không phải code của bạn. Để migrate dần, conditional import cho phép hai thế giới cùng tồn tại:

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

Hai cái header ai cũng quên

App Flutter Wasm có thể render trên nhiều luồng — nhưng chỉ khi server của bạn gửi đúng header cross-origin:

HeaderGiá trị
Cross-Origin-Embedder-Policycredentialless hoặc require-corp
Cross-Origin-Opener-Policysame-origin

Thiếu một trong hai, đa luồng lặng lẽ không xảy ra. App vẫn chạy; chỉ là chậm hơn con số benchmark bạn đọc được. Hãy kiểm tra chúng trong cấu hình CDN hoặc reverse proxy, không chỉ ở môi trường dev — đây là cái bẫy kinh điển “nhanh trên localhost, chậm trên production”.

Lưu ý require-corp sẽ làm hỏng các tài nguyên bên thứ ba nhúng vào mà không khai báo header CORP. Nếu bạn nhúng nhiều nội dung ngoài, credentialless thường là lựa chọn thực dụng.

Khác biệt lúc chạy đáng biết

package:webdart:js_interop dưới Wasm không giống hệt backend JS:

  • Kiểm tra is / as hành xử khác trên các kiểu JS interop
  • Zone lan truyền trong callback khác đi

Không cái nào làm hỏng một app thông thường, nhưng cả hai sẽ cắn đoạn code làm những trò thông minh với kiểm tra kiểu qua ranh giới interop. Hãy test riêng lớp interop thay vì cho rằng chúng ngang bằng.

Kế hoạch triển khai của bạn

  1. Chạy flutter build web ngay hôm nay và đọc kết quả Wasm dry run. Đó là backlog migrate của bạn.
  2. Cập nhật web/index.html theo phần khởi tạo Flutter hiện hành, hoặc sinh lại bằng flutter create . --platforms web.
  3. Migrate code của chính bạn từ dart:html sang package:web và từ dart:js sang dart:js_interop.
  4. Truy các thủ phạm gián tiếp được nêu trong Context tree. Mở issue cho những dependency còn import dart:html.
  5. Cấu hình header COOP và COEP ở tầng phục vụ production, rồi kiểm chứng bằng tab network.
  6. Build với --wasm --source-maps và nối file map vào hệ thống giám sát lỗi.
  7. Log dart.tool.dart2wasm và đo xem bao nhiêu phần trăm phiên thật sự đi đường Wasm.
  8. Thử --enable-wasm-deferred-loading nếu bundle của bạn lớn, và đo thời gian tải trang lần đầu thay vì tổng dung lượng.

Kết luận

Wasm nhanh hơn thật, và lộ trình chỉ tới việc nó thành mặc định. Nhưng hôm nay nó là một bản build cộng thêm, không phải thay thế: bạn vẫn ship JS, người dùng iOS vẫn nhận đường JS bất kể thế nào, và phần thắng hiệu năng phụ thuộc hai cái header mà phần lớn nhóm chưa đặt. Việc giá trị nhất bạn có thể làm tuần này chẳng tốn gì — chạy flutter build web và đọc kết quả dry run. Dù bạn có ship Wasm quý này hay không, danh sách dependency dính dart:html đó là món nợ sớm muộn cũng phải trả.


Bài viết gốc đăng tại FlutterCook. Bản trên đó là bản được cập nhật mới nhất.

Nhận xét

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

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...

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ử...

Announcing Flutter 2

  Phụ lục: Flutter on the web Flutter 2 on desktops, foldables, and embedded devices The growing Flutter ecosystem Dart: The secret sauce behind Flutter Flutter 2: Available now Hôm nay, chúng tôi sẽ công bố Flutter 2: một bản nâng cấp lớn cho Flutter cho phép các nhà phát triển tạo các ứng dụng đẹp, nhanh chóng và di động cho bất kỳ nền tảng nào. Với Flutter 2, bạn có thể sử dụng cùng một cơ sở mã để gửi các ứng dụng gốc cho năm hệ điều hành: IOS, Android, Windows, macOS và Linux; cũng như trải nghiệm web nhắm mục tiêu các trình duyệt như Chrome, Firefox, Safari hoặc Edge. Flutter thậm chí có thể được nhúng vào ô tô, TV và thiết bị gia dụng thông minh, mang đến trải nghiệm di động và lan tỏa nhất cho thế giới điện toán xung quanh. Mục tiêu của chúng tôi là thay đổi cơ bản cách các nhà phát triển nghĩ về việc xây dựng ứng dụng, bắt đầu không phải với nền tảng bạn đang nhắm mục tiêu mà là với trải nghiệm bạn muốn tạo. Flutter cho phép bạn tạo ra những trải nghiệm tuyệt đẹp trong đó ...