一,Flutter Web架构
目前,除了可以支持Android、iOS移动跨平台开发之外,Flutter还支持macOS、Windows、Linux和Web等多个跨平台的开发。可以说,作为一款先进的跨平台开发框架,Flutter已经真正意义上实现了“一次编写,处处运行”的美好愿景。
众所周知,Dart 语言存在之初就已经支持直接编译成JavaScript,并且针对开发和生产环境的工具链进行了优化。许多重要的应用已经使用 Dart 编译成的 JavaScript 在生产环境上运行,包括 Google Ads 的广告商工具 。由于Flutter 框架是 Dart 编写的,所以将其编译成 JavaScript 相对而言更为简单。
然而,使用C++编写的Flutter引擎是为了与底层操作系统进行交互的,而不是 Web 浏览器。因此我们需要另辟蹊径。Flutter 在 Web 平台上以浏览器的标准 API 重新实现了引擎。 目前我们有两种在 Web 上呈现内容的选项:HTML 和 WebGL。在 HTML 模式下,Flutter 使用 HTML、CSS、Canvas 和 SVG 进行渲染。而在 WebGL 模式下,Flutter 使用了一个编译为 WebAssembly 的 Skia 版本,名为 CanvasKit 。HTML 模式提供了最佳的代码大小,CanvasKit 则提供了浏览器图形堆栈渲染的最快途径,并为原生平台的内容 5 提供了更高的图形保真度。Flutter Web 版本的分层架构图如下所示。
与其他运行 Flutter 的平台相比,Flutter Web最明显的区别也许是 Flutter 不再需要提供 Dart 的运行时。取而代之的是 Flutter 框架本身(和你写的代码)一并编译成 JavaScript。另外值得注意的是,Dart 在不同模式下(JIT 和 AOT、平台原生和 Web 编译)的语义几乎没有差异,大部分开发者绝对可以无差异地编写这两种模式下的代码。
二、浏览器基础知识
2.1 WebGL
WebGL(Web图形库)是一个JavaScript API,可在任何兼容的Web浏览器中渲染高性能的交互式3D和2D图形,而无需使用插件。WebGL通过引入一个与OpenGL ES 2.0非常一致的API来做到这一点,该API可以在HTML5 <canvas> 元素中使用。 这种一致性使API可以利用用户设备提供的硬件图形加速。
目前支持 WebGL 的浏览器有:Firefox 4+, Google Chrome 9+, Opera 12+, Safari 5.1+, Internet Explorer 11+和Microsoft Edge build 10240+等;然而, WebGL 一些特性也需要用户的硬件设备支持。可以通过caniuse来查看主流的浏览器对WebGL的支持情况。
WebGL2 是WebGL的一个主要更新,它基于OpenGL ES 3.0,引入了对大部分的OpenGL ES 3.0功能集的支持,它是通过WebGL2RenderingContext界面提供的。
2.2 canvas标签
<canvas>元素可被用来通过 JavaScript(Canvas API 或 WebGL API)绘制图形及图形动画,事实上,<canvas> 元素本身只是一个位图,不提供任何绘制对象的信息。。比如:
<canvas id="canvas" width="300" height="300">
抱歉,您的浏览器不支持 canvas 元素
</canvas>
2.3 Canvas API
Canvas API 提供了一个通过JavaScript 和 HTML的元素来绘制图形的方式。它可以用于动画、游戏画面、数据可视化、图片编辑以及实时视频处理等方面。Canvas API主要聚焦于2D图形。而同样使用<canvas>元素的 WebGL API 则用于绘制硬件加速的2D和3D图形。
2.4 CSS Painting API
CSS Painting API — CSS Houdini API 的一部分— 允许开发人员编写 JavaScript 函数,这些函数可以直接绘制到元素的背景、边框或内容中。CSS Paint API 旨在使开发人员能够以编程方式定义图像,然后可以在任何可以调用 CSS 图像的地方使用这些图像,例如 CSS background-image、border-image、mask-image等。
2.5 CSS Houdini
Houdini是一组底层API,它们公开了CSS引擎的各个部分,从而使开发人员能够通过加入浏览器渲染引擎的样式和布局过程来扩展CSS。 Houdini是一组API,它们使开发人员可以直接访问CSS 对象模型 (CSSOM),使开发人员可以编写浏览器可以解析为CSS的代码,从而创建新的CSS功能,而无需等待它们在浏览器中本地实现。
三,编译器
Flutter 官方给我们提供了 dart2js 和 dartdevc 两个编译器是将Dart编译JavaScript。
- 针对开发环境,Web 版本的 Flutter 使用支持增量编译的编译器 dartdevc 进行编译,以支持应用热重载。
- 针对生产环境,Dart 深度优化的编译器 dart2js 将会用于编译,将 Flutter 核心框架和你的应用打包至缩小的源文件中,可部署在任何服务器上。代码可以在单个文件中提供,也可拆分成多个文件以【 延迟加载库 】提供。
3.1 dartdevc
Dart 开发编译器(dartdevc,也称为DDC)允许开发者在 Chrome 浏览器中运行和调试您的 Dart Web 应用程序。与 dart2js 不同,dartdevc 支持增量编译并发出模块化 JavaScript。像webdev serve这样使用 dartdevc 的工具,你可以编辑 Dart 代码,然后在 Chrome 中刷新,并且几乎可以立即看到效果。
不过需要注意的是,第一次使用 dartdevc 编译耗时最长,因为必须编译整个应用程序。之后,只要serve命令再次运行,dartdevc 的刷新时间就会比 dart2js 快得多。
3.2 dart2js
使用dart2js工具能够将Dart 代码编译为可部署的 JavaScript。而另一个 Dart-to-JavaScript 编译器仅供开发环境使用。下面是一个将 Dart 文件编译为JavaScript 的命令:
dart2js -O2 -o test.js test.dart
四,Web 渲染器
同时,为了实现将Dart代码编译为JavaScript代码,Flutter Web在FrameWork层提供了Html渲染器和CanvasKit渲染器。使用的命令如下:
flutter run -d chrome --web-renderer html
flutter build web --web-renderer canvaskit
4.1 HTML 渲染
Html渲染能够使用 HTML,CSS,Canvas 和 SVG 元素来渲染,应用的大小相对较小。
4.2 CanvasKit 渲染
使用CavasKit渲染能够将 Skia 编译成 WebAssembly 格式,并使用 WebGL 渲染(见下面的WebGL说明)。应用在移动和桌面端保持一致,有更好的性能,以及降低不同浏览器渲染效果不一致的风险,但是应用的大小会增加大约 2MB。
至于选择哪种渲染器,可以参考以下几点:
- 如果是运行在移动端浏览器平台上可能需要更关心应用大小,而如果是运行在桌面端浏览器则需要更关心性能,此时最好选择 auto 选项;
- 不管是运行在移动端还是桌面端,都更关心应用大小,那么请选择 html 选项。
- 不管是运行在移动端还是桌面端都更关心性能,和跨浏览器的像素级一致性,那么请选择canvaskit选项。
五、Flutter Web优化
当我们将Flutter Web项目部署后,由于没有进行优化,首次加载通常耗时是比较长的。之所以会这样,是因为我们使用“flutter build web --release”命令构建应用包的时候,默认使用饿是Canvaskit渲染来构建的Web产物。并且,默认使用外网地址加载JS库、字体库、CSS等资源文件。
https://unpkg.com/canvaskit-wasm@0.24.0/bin/
https://fonts.gstatic.com/s/roboto/v20/KFOmCnqEu92Fr1Me5WZLCzYlKw.ttf
https://fonts.googleapis.com/css2?family=Noto+Sans+JP
5.1 Canvaskit渲染优化点
1,使用CDN地址执行构建命令:
flutter build web --release --base-href '/web/' --dart-define=FLUTTER_WEB_CANVASKIT_URL=https://cdn.cnht.com.cn/cdn_resources/common/canvaskit-wasm/0.31.0/bin/
2,使用本地文件加载 canvaskit 库:
//web是Tomcat里项目的名称
flutter build web --release --base-href '/web/' --dart-define=FLUTTER_WEB_CANVASKIT_URL=/web/canvaskit/
3,将字体和css样式文件放到工程目录下,然后加载本的资源:
5.2 Html渲染优化点
使用HTML渲染也有一些优化点,总结起来有以下几点:
1, tree-shake优化
flutter 构建 web 不支持 --tree-shake-icons 命令,不能直接使用,报错如下:
不过,我们可以借助构建其他平台的资源文件优化,然后再拷贝到Web产物内即可。步骤如下:
- flutter build apk –tree-shake-icons 构建Android产物;
- 找到优化后的资源文件使用rar工具解压缩得到优化后的MaterialIcons-Regular.otf;
- 把优化后的MaterialIcons-Regular.otf替换Web产物的文件,优化后 MaterialIcons-Regular.otf 大小从1.6MB优化到1KB;
5.3 禁用PWA
修改index.html内的js即可,去掉flutter.js,去掉flutter_service_worker.js。flutter_service_worker.js 这个文件的作用是提供 PWA 功能支持,国内很少用这个特性。加载flutter_service_worker.js,内部会下载如下4个文件,去掉后减少5个请求,可以明显加快响应的速度。
const CORE = [
"/",
"main.dart.js",
"index.html",
"assets/NOTICES",
"assets/AssetManifest.json",
"assets/FontManifest.json"];
self.addEventListener("install", (event) => {
self.skipWaiting();
return event.waitUntil(
caches.open(TEMP).then((cache) => {
return cache.addAll(
CORE.map((value) => new Request(value, {'cache': 'reload'})));
})
);
});
5.4 去掉无用的字体
如果我们打开Web构建的包,会在build/web/assets/FontManifest.json 文件中看到生成的原文件内容的字体,而这些字体是没啥用的,我们可以将这些没有作用的字体删除。