Web 渲染器

Flutter Web 提供了两种 构建模式 和两种 渲染器。构建模式是在构建应用时选择的,它决定了应用中可用的两种渲染器之一,以及如何选择渲染器。在应用启动时,渲染器会在运行时 (runtime) 被选择,这决定了用于渲染 UI 的 Web 技术。

两种构建模式是:默认模式和 WebAssembly 模式。

两种渲染器是:canvaskitskwasm

渲染器

#

在 Flutter 中渲染 UI 从框架中的 Widget 和 RenderObject 开始。一旦处理完成,RenderObject 会生成一个由多个 Layer 组成的 Scene 对象。随后,该 Scene 被传递给 Flutter 引擎,将其转换为像素。整个框架,包括所有的 widget 和自定义的应用代码,以及大部分引擎,都是用 Dart 编写的。然而,引擎中有很大一部分是用 C++ 编写的,其中包括 Skia 以及定制的 Flutter 引擎代码。关于如何编译 Dart 和 C++、使用哪种图形系统将 UI 转换为像素、如何在多个线程间分配工作负载等问题, Web 上有多种可供选择的方案。

Flutter Web 并不提供所有可用的方案,而是仅提供了两种精心挑选的方案。

canvaskit

#

使用 canvaskit 渲染器时,Dart 代码会被编译为 JavaScript,并且 UI 会在主线程中渲染到 WebGL 上。它兼容所有现代浏览器。该渲染器包含一个编译成 WebAssembly 的 Skia 副本,这会增加大约 1.5MB 的下载大小。

skwasm

#

使用 skwasm 渲染器时,Dart 代码会被编译为 WebAssembly。此外,如果托管服务器满足 SharedArrayBuffer 安全要求, Flutter 会使用一个专用的 web worker 将部分渲染工作转移到单独的线程上,以利用多核 CPU 的优势。该渲染器包含一个编译为 WebAssembly 的更精简的 Skia,增加大约 1.1MB 的下载大小。

构建模式

#

默认构建模式

#

使用 flutter runflutter build web 命令时,如果不传递 --wasm 或传递 --no-wasm,则会使用默认模式。此构建模式仅使用 canvaskit 渲染器。

WebAssembly 构建模式

#

此模式通过在 flutter runflutter build web 命令中传递 --wasm 标志启用。

在此模式下,skwasmcanvaskit 都可以使用。 skwasm 依赖 wasm 垃圾回收机制,而这一功能尚未被所有现代浏览器支持。因此,在运行时 (runtime),如果浏览器支持垃圾回收,Flutter 将选用 skwasm,如果不支持,则会回退到 canvaskit。这确保了在 WebAssembly 模式下编译的应用程序仍然能够在所有现代浏览器中运行。

--wasm 标志不适用于非 Web 平台。

在运行时 (runtime) 选择渲染器

#

默认情况下,在 WebAssembly 模式下构建时,Flutter 会自动决定何时使用 skwasm,以及何时回退到 canvaskit。你可以通过传递配置对象给加载器来覆盖这一行为,具体步骤如下:

  1. 使用 --wasm 标志构建应用程序,以使应用能够使用 skwasmcanvaskit 渲染器。

  2. 按照 编写自定义 flutter_bootstrap.js 中的描述设置自定义 Web 应用初始化。

  3. 准备一个配置对象,将其 renderer 属性设置为 "canvaskit""skwasm"

  4. 将准备好的 config 对象作为新对象的 config 属性,传递给之前注入代码提供的 _flutter.loader.load 方法。

示例:

html
<body>
  <script>
    {{flutter_js}}
    {{flutter_build_config}}

    // TODO: Replace this with your own code to determine which renderer to use.
    const useCanvasKit = true;

    const config = {
      renderer: useCanvasKit ? "canvaskit" : "skwasm",
    };
    _flutter.loader.load({
      config: config,
    });
  </script>
</body>

在调用 load 方法后,Web 渲染器就无法再次更改。因此,必须在调用 _flutter.loader.load 之前决定使用哪种渲染器。

如何选择合适的构建模式

#

将 Dart 编译为 WebAssembly 伴随着一些新的要求,所有应用代码以及应用使用的插件和 package 都必须满足这些要求:

  • 代码必须只使用新的 JS 互操作库 dart:js_interop。旧的 dart:jsdart:js_utilpackage:js 已不再支持。

  • 使用 Web API 的代码必须使用新的 package:web 而不是 dart:html

  • WebAssembly 实现了 Dart 的数值类型 intdouble,其行为与 Dart VM 完全一致。在 JavaScript 中,这些类型是使用 JS 的 Number 类型进行模拟的。你的代码可能无意或故意依赖于 JS 中的数值行为。如果是这样,这部分代码需要更新,以确保与 Dart VM 的行为一致。

总体建议可以总结如下:

  • 如果你的应用依赖于尚未支持 WebAssembly 的插件和 package,那就选择默认模式。

  • 如果你的应用代码和 package 与 WebAssembly 兼容,并且应用性能非常重要,那就选择 WebAssembly 模式。 skwasm 相较于 canvaskit 在应用启动时间和帧性能方面有明显优势。 skwasm 性能优势在多线程模式下尤为显著,因此请考虑配置服务器以满足 SharedArrayBuffer 安全要求

示例

#

在 Chrome 浏览器中使用默认构建模式运行:

flutter run -d chrome

使用默认构建模式构建你的应用以进行发布:

flutter build web

使用 WebAssembly 模式构建你的应用以进行发布:

flutter build web --wasm

使用默认构建模式运行你的应用以进行性能分析:

flutter run -d chrome --profile