背景
在使用Flutter Web開發的網站過程中,常常會遇到不同瀏覽器之間的兼容性問題。例如,在Google瀏覽器中動畫和交互都非常流暢,但在360瀏覽器中卻會出現卡頓現象;在Google瀏覽器中動態設置圖標顏色正常顯示,而在Safari瀏覽器中顏色會缺失變成黑色;甚至在某些電腦的Google瀏覽器中也會出現動畫卡頓和頁面報錯的問題。
優化方案
這些問題的根源在于渲染模式的選擇。將渲染模式從HTML改為CanvasKit后,大部分問題得以解決,動畫變得流暢,畫面也變得順滑,圖標顯示正常,兼容性也得到了提升。
渲染模式
- HTML渲染模式:Flutter使用HTML的
custom element
、CSS
、Canvas
和SVG
來渲染UI元素。 - CanvasKit渲染模式:Flutter將Skia編譯成
WebAssembly
格式,并使用WebGL
進行渲染。
HTML | CanvasKit | |
---|---|---|
命令行 | –web-renderer html | –web-renderer canvaskit |
優點 | 體積更小 | 渲染性能強,多端一致 |
缺點 | 渲染性能差,跨端兼容差 | 體積相較HTML多2.5M |
盡管CanvasKit模式提供了更流暢的體驗,但它也帶來了一些新的問題。
由CanvasKit引起的問題
圖片跨域
報錯描述:
Access to XMLHttpRequest at ‘https://…/icon/setting_228.webp’ from origin ‘https://…’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
在CanvasKit模式下,圖片請求類型變為xhr
,不支持跨域,導致跨域問題。解決方法是將圖片放到與服務同域的目錄下。
首次打開加載慢
首次加載CanvasKit模式的網站時,會下載大量文件,包括CanvasKit繪制引擎和字體。解決方法是將引擎和字體文件存放到自己的服務器,以加快下載速度。
-
引擎本地化:下載引擎文件并放到項目中,然后在運行或打包時指定本地路徑。
--dart-define=FLUTTER_WEB_CANVASKIT_URL=assets/canvaskit/
-
字體本地化:下載字體文件并放到本地,替換構建后的main.dart.js中的字體路徑。
字體需下載
Skia自繪引擎需要字體庫支持,導致首次加載時出現字體亂碼。解決方法是在pubspec.yaml中設置本地字體包。
main.dart.js 切片化
以上兩步只是加快了下載速度,但所需要下載的內容大小沒變,好在Flutter 官方提供 deferred as
關鍵字來實現 Widget 的懶加載,而 dart2js 在編譯過程中可以將懶加載的 Widget 進行按需打包,這樣的拆包機制叫做 Lazy Loading。借助 Lazy Loading,我們可以在路由表中使用 deferred 引入各個路由(頁面),以此來達到業務代碼拆離的目的。具體的代碼請看這篇文章《JS 分片優化》,很詳細。
試驗拆分后,main.dart.js由8.5M縮減至5.5M。
加載時提示
為了解決首次加載時白屏的問題,可以在白屏時加個提示。
html復制
<style>body {width: 100vw;height: 100vh;display: flex;justify-content: center;align-items: center;}
</style>
<div id="text">靜態資源加載中...</div>
瀏覽器刷新后頁面加載兩次
刷新頁面時會加載兩次,是由于serviceWorker注冊失敗導致。解決方法是注釋掉注冊邏輯,直接調用loadMainDartJs()
。
路由包裝url地址方式失效
在CanvasKit模式下,刷新后不會停留在當前頁面。解決方法是在刷新時記錄當前頁面,并在初始化時還原。
最后
盡管CanvasKit模式在動畫和交互體驗上優于HTML模式,但其加載速度較慢。在內部使用的網站中,可以優先考慮交互體驗。
參考
- Flutter web內網網站如何發布?解決外網下canvaskit.js和字體無法加載問題
- serviceWorker 服務器與瀏覽器之間的代理
- Flutter 開啟web構建以及web的兩種渲染模式