本文字数:4307字
预计阅读时间:30分钟
01
前言
在之前的文章中,我们详细的介绍过Flutter Web
从0到部署上线的流程,并且针对其中遇到的问题进行了分析与修复:https://www.jianshu.com/p/6213f8a88288
我们也对Flutter Web
的项目进行了打包部署上线。在产品体验中会发现,跟传统的web
端网页对比,还是明显感觉到性能上的差异,特别是启动的过程明显耗时较长。本文将针对Flutter Web
项目的做一些启动上的优化和探讨。SDK
版本:Flutter SDK 3.19.0
。
02
main.dart.js分包
main.dart.js
是Flutter Web
的编译产物,所有的业务逻辑都在这一个js
文件里,可想而知它会比较臃肿。在Flutter Web
发布后,就有了main.dart.js
分包的需求,看了很多网上的案例,使用deferred-components
即可达成分包的目的。但在写上一篇文章的时候,我们用的是Flutter SDK 3.10.5
,按照官网的步骤进行了分包处理发现编译是成功的,但是最终并没有实现分包。阅读官网文档,当时明确说明了deferred-components
只能用于Android
的编译产物。猜测那时候可能发现了Web
分包的一些问题,导致在某一些版本的SDK
并不支持Web
的deferred-components
。链接如下:https://flutter.cn/docs/perf/deferred-components
现在重新阅读官网,描述已经进行了修改:
Flutter
在Android
和Web
上支持延迟加载或「懒」加载。在不同平台实现方式有所不同。Android
平台的 动态功能模块 提供打包为Android module
的延迟组件。Web
平台将这些组件创建为单独的*.js
文件。延迟组件中的代码不会影响其他平台,其他平台在初始安装时会正常构建包含所有延迟组件和资源的应用。
看上去目前deferred-components
在Web
端已经做到了很好的支持,那么我们就实验一下,步骤如下:
1、添加依赖
通过将deferred-components
依赖添加到应用程序的pubspec.yaml
中的flutter
下即可:
flutter:
deferred-components:
2、实现
我们找到一个可以被延迟加载的Widget
,使用deferred
关键字进行导入:
import './widget/me_read_achievement_widget.dart' deferred as achievement;
然后调用loadLibrary()
:
late Future<void> _libraryFuture;
@override
void initState() {
super.initState();
_libraryFuture = achievement.loadLibrary();
}
最后使用FutureBuilder
等待loadLibrary
的Future
对象初始化完成,并实现延迟加载:
@override
Widget build(BuildContext context) {
return FutureBuilder<void>(
future: _libraryFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return achievement.MeReadAchievementWidget();
}
return const CircularProgressIndicator();
},
);
}
最后再进行打包。
3、编译产物
打包完成后我们看下编译产物,会发现除了main.dart.js
之外又多了一个main.dart.js_1.part.js
:
main.dart.js_1.part.js
即为分包。
4、分包加载
部署之后我们打开浏览器看一下效果:
在启动Web
页面后我们发现只加载了main.dart.js
:
只有操作到相应的页面,才会加载main.dart.js_1.part.js
:
这说明如果业务比较复杂页面很多的情况下,我们可以根据自己的需求和体验细化项目的结构,将Widget
进行拆分,在需要的时候再进行延迟加载,一定程度上减少main.dart.js
的包体积,以达到启动时加速的目的。
03
canvaskit.js和canvaskit.wasm
CanvasKit
是以WASM
为编译目标的Web
平台图形绘制接口,其目标是将Skia
的图形API
导出到Web
平台。其中canvaskit
中绘制的实现全部在canvaskit.js
中调用浏览器绘制API
来实现,而计算相关的内容全部放在了wasm
中实现。由此可知这两个文件是实现Flutter Web
渲染核心文件。它们也是在启动过程中进行的,且是从google
的服务器进行的下载:
canvaskit.js:
canvaskit.wasm:
由于众所周知的原因,访问这两个地址将会比较慢,在有些时候甚至会访问失败。这两个文件的加载失败也就直接导致了页面无法渲然的问题。由于我们的项目是CDN
部署,因此我们也需要把它部署到CDN
上面,并访问其CDN
地址。官方给了两种方式:
1、在初始化引擎时配置
从官网说明来看,我们可以在
initializeEngine
时通过配置canvasKitBaseUrl
参数的方式来实现加载canvaskit
相关的文件。如:
_flutter.loader.loadEntrypoint({
onEntrypointLoaded: async function(engineInitializer) {
let appRunner = await engineInitializer.initializeEngine({
canvasKitBaseUrl: YOUR_CANVASKIT_CDN_BASE_URL
});
await appRunner.runApp();
}
});
其中YOUR_CANVASKIT_CDN_BASE_URL
是你canvaskit.js
和canvaskit.wasm
文件所在的根目录,然后正常编译打包即可。另外我们也可以不改源文件配置,通过在打包时配置参数来实现。
2、打包配置参数
我们可以通过以下参数进行配置:
--dart-define=FLUTTER_WEB_CANVASKIT_URL
完整的打包命令如下:
flutter build web -t lib/main_test.dart --no-tree-shake-icons --dart-define=FLUTTER_WEB_CANVASKIT_URL=YOUR_CANVASKIT_CDN_BASE_URL --release
通过实践,这两种方式都可以实现从自己的CDN
上读取canvaskit.js
和canvaskit.wasm
文件的目的,我们来看一下执行结果:
对比一下,从Google
服务器下载下来的用时:
都用了2,3秒的时间,而从我们自己的CDN
上:只用了毫秒级,优化效果非常明显。
好的,接下来我们发现,还有一些字体文件会从Google
的服务器进行下载,接下来我们优化一下字体的问题。
注意:在开发调试的过程中,由于直接加载的是本地的canvaskit.js
和canvaskit.wasm
文件,所以不用做任何处理。
04
字体加载优化
优化了canvaskit
相关文件后,我们发现启动还是很慢,抓包看原来还有一些字体是从Google
下载的,比如:
这两个文件的下载路径修改,Flutter
官方并没有给任何参考。那么我们找找加载它们的实现。打开编译后的产物,main.dart.js
,我们搜一下这两个字体:
找到了这个代码后,处理就很简单了,将KFOmCnqEu92Fr1Me5WZLCzYlKw.ttf
这个文件下载下来,放到CDN
上,再修改一下这段代码的url
到我们的CDN
地址即可。另一个字体我们看到,它是在一个数组中:
这个数组长度非常长,有一百多个成员。Flutter
会根据不同的浏览器环境,和不同的语言环境加载不同的字体。其Host
定义如下:
其中j
就是每个字体的url
参数。一百多个字体一个一个手动下载是不太现实了,但我们可以批量下载,思路就是从这个数组中截取所有的ttf
路径,拼上Host
进行下载。注意:需要保留Google
的目录结构。大家可以用任意自己熟悉的方式实现批量下载,我用Python
写了个脚本进行批量实现:
# coding=utf-8
import os
import requests
original_text = 'r=this.b=A.cOH(new A.bs4(this),A.a([A.aY("Noto Sans","notosans/v32/o-0IIpQlx3QUlC5A4PNb4j5Ba_2c7A.ttf",!0),A.aY("Noto Color Emoji","notocoloremoji/v25/Yq6P-KqIXTD0t4D9z1ESnKM3-HpFab5s79iz64w.ttf",s),A.aY("Noto Emoji","notoemoji/v47/bMrnmSyK7YY-MEu6aWjPDs-ar6uWaGWuob-r0jwvS-FGJCMY.ttf",!s),A.aY("Noto Music","notomusic/v20/pe0rMIiSN5pO63htf1sxIteQB9Zra1U.ttf",!0),A.aY("Noto Sans Symbols","notosanssymbols/v41/rP2up3q65FkAtHfwd-eIS2brbDN6gxP34F9jRRCe4W3gfQ8gavVFRkzrbQ.ttf",!0),A.aY("Noto Sans Symbols 2","notosanssymbols2/v22/I_uyMoGduATTei9eI8daxVHDyfisHr71ypPqfX71-AI.ttf",!0),A.aY("Noto Sans Adlam","notosansadlam/v22/neIczCCpqp0s5pPusPamd81eMfjPonvqdbYxxpgufnv0TGnBZLwhuvk.ttf",!0),A.aY("Noto Sans Anatolian Hieroglyphs","notosansanatolianhieroglyphs/v16/ijw9s4roRME5LLRxjsRb8A0gKPSWq4BbDmHHu6j2pEtUJzZWXybIymc5QYo.ttf",!0),A.aY("Noto Sans Arabic","notosansarabic/v18/nwpxtLGrOAZMl5nJ_wfgRg3DrWFZWsnVBJ_sS6tlqHHFlhQ5l3sQWIHPqzCfyGyvu3CBFQLaig.ttf",!0),A.aY("Noto Sans Armenian","notosansarmenian/v42/ZgN0jOZKPa7CHqq0h37c7ReDUubm2SEdFXp7ig73qtTY5idb74R9UdM3y2nZLorxb60iYy6zF3Eg.ttf",!0),A.aY("Noto Sans Avestan","notosansavestan/v21/bWti7ejKfBziStx7lIzKOLQZKhIJkyu9SASLji8U.ttf",!0),A.aY("Noto Sans Balinese","notosansbalinese/v24/NaPwcYvSBuhTirw6IaFn6UrRDaqje-lpbbRtYf-Fwu2Ov7fdhE5Vd222PPY.ttf",!0),A.aY("Noto Sans Bamum","notosansbamum/v27/uk-0EGK3o6EruUbnwovcbBTkkklK_Ya_PBHfNGTPEddO-_gLykxEkxA.ttf",!0),A.aY("Noto Sans Bassa Vah","notosansbassavah/v17/PN_bRee-r3f7LnqsD5sax12gjZn7mBpL5YwUpA2MBdcFn4MaAc6p34gH-GD7.ttf",!0),A.aY("Noto Sans Batak","notosansbatak/v19/gok2H6TwAEdtF9N8-mdTCQvT-Zdgo4_PHuk74A.ttf",!0),A.aY("Noto Sans Bengali","notosansbengali/v20/Cn-SJsCGWQxOjaGwMQ6fIiMywrNJIky6nvd8BjzVMvJx2mcSPVFpVEqE-6KmsolLudCk8izI0lc.ttf",!0),A.aY("Noto Sans Bhaiksuki","notosansbhaiksuki/v17/UcC63EosKniBH4iELXATsSBWdvUHXxhj8rLUdU4wh9U.ttf",!0),A.aY("Noto Sans Brahmi","notosansbrahmi/v18/vEFK2-VODB8RrNDvZSUmQQIIByV18tK1W77HtMo.ttf",!0),A.aY("Noto Sans Buginese","notosansbuginese/v18/esDM30ldNv-KYGGJpKGk18phe_7Da6_gtfuEXLmNtw.ttf",!0),A.aY("Noto Sans Buhid","notosansbuhid/v22/Dxxy8jiXMW75w3OmoDXVWJD7YwzAe6tgnaFoGA.ttf",!0),A.aY("Noto Sans Canadian Aboriginal","notosanscanadianaboriginal/v22/4C_TLjTuEqPj-8J01CwaGkiZ9os0iGVkezM1mUT-j_Lmlzda6uH_nnX1bzigWLn_yAsg0q0uhQ.ttf",!0),A.aY("Noto Sans Carian","notosanscarian/v16/LDIpaoiONgYwA9Yc6f0gUILeMIOgs7ob9yGLmfI.ttf",!0),A.aY("Noto Sans Caucasian Albanian","notosanscaucasianalbanian/v16/nKKA-HM_FYFRJvXzVXaANsU0VzsAc46QGOkWytlTs-TXrYDmoVmRSZo.ttf",!0),A.aY("Noto Sans Chakma","notosanschakma/v17/Y4GQYbJ8VTEp4t3MKJSMjg5OIzhi4JjTQhYBeYo.ttf",!0),A.aY("Noto Sans Cham","notosanscham/v29/pe06MIySN5pO62Z5YkFyQb_bbuRhe6D4yip43qfcERwcv7GykboaLg.ttf",!0),A.aY("Noto Sans Cherokee","notosanscherokee/v20/KFOPCm6Yu8uF-29fiz9vQF9YWK6Z8O10cHNA0cSkZCHYWi5PDkm5rAffjl0.ttf",!0),A.aY("Noto Sans Coptic","notosanscoptic/v20/iJWfBWmUZi_OHPqn4wq6kgqumOEd78u_VG0xR4Y.ttf",!0),A.aY("Noto Sans Cuneiform","notosanscuneiform/v17/bMrrmTWK7YY-MF22aHGGd7H8PhJtvBDWgb9JlRQueeQ.ttf",!0),A.aY("Noto Sans Cypriot","notosanscypriot/v15/8AtzGta9PYqQDjyp79a6f8Cj-3a3cxIsK5MPpahF.ttf",!0),A.aY("Noto Sans Deseret","notosansdeseret/v17/MwQsbgPp1eKH6QsAVuFb9AZM6MMr2Vq9ZnJSZtQG.ttf",!0),A.aY("Noto Sans Devanagari","notosansdevanagari/v25/TuGoUUFzXI5FBtUq5a8bjKYTZjtRU6Sgv3NaV_SNmI0b8QQCQmHn6B2OHjbL_08AlXQly-AzoFoW4Ow.ttf",!0),A.aY("Noto Sans Duployan","notosansduployan/v17/gokzH7nwAEdtF9N8-mdTDx_X9JM5wsvrFsIn6WYDvA.ttf",!0),A.aY("Noto Sans Egyptian Hieroglyphs","notosansegyptianhieroglyphs/v28/vEF42-tODB8RrNDvZSUmRhcQHzx1s7y_F9-j3qSzEcbEYindSVK8xRg7iw.ttf",!0),A.aY("Noto Sans Elbasan","notosanselbasan/v16/-F6rfiZqLzI2JPCgQBnw400qp1trvHdlre4dFcFh.ttf",!0),A.aY("Noto Sans Elymaic","notosanselymaic/v15/UqyKK9YTJW5liNMhTMqe9vUFP65ZD4AjWOT0zi2V.ttf",!0),A.aY("Noto Sans Georgian","notosansgeorgian/v42/PlIaFke5O6RzLfvNNVSitxkr76PRHBC4Ytyq-Gof7PUs4S7zWn-8YDB09HFNdpvnzFj-f5WK0OQV.ttf",!0),A.aY("Noto Sans Glagolitic","notosansglagolitic/v17/1q2ZY4-BBFBst88SU_tOj4J-4yuNF_HI4ERK4Amu7nM1.ttf",!0),A.aY("Noto Sans Gothic","notosansgothic/v16/TuGKUUVzXI5FBtUq5a8bj6wRbzxTFMX40kFQRx0.ttf",!0),A.aY("Noto Sans Grantha","notosansgrantha/v17/3y976akwcCjmsU8NDyrKo3IQfQ4o-r8cFeulHc6N.ttf",!0),A.aY("Noto Sans Gujarati","notosansgujarati/v23/wlpWgx_HC1ti5ViekvcxnhMlCVo3f5pv17ivlzsUB14gg1TMR2Gw4VceEl7MA_ypFwPM_OdiEH0s.ttf",!0),A.aY("Noto Sans Gunjala Gondi","notosansgunjalagondi/v19/bWtX7e7KfBziStx7lIzKPrcSMwcEnCv6DW7n5g0ef3PLtymzNxYL4YDE4J4vCTxEJQ.ttf",!0),A.aY("Noto Sans Gurmukhi","notosansgurmukhi/v26/w8g9H3EvQP81sInb43inmyN9zZ7hb7ATbSWo4q8dJ74a3cVrYFQ_bogT0-gPeG1OenbxZ_trdp7h.ttf",!0),A.aY("Noto Sans HK","notosanshk/v31/nKKF-GM_FYFRJvXzVXaAPe97P1KHynJFP716qHB--oWTiYjNvVA.ttf",!0),A.aY("Noto Sans Hanunoo","notosanshanunoo/v20/f0Xs0fCv8dxkDWlZSoXOj6CphMloFsEsEpgL_ix2.ttf",!0),A.aY("Noto Sans Hatran","notosanshatran/v16/A2BBn4Ne0RgnVF3Lnko-0sOBIfL_mM83r1nwzDs.ttf",!0),A.aY("Noto Sans Hebrew","notosanshebrew/v43/or3HQ7v33eiDljA1IufXTtVf7V6RvEEdhQlk0LlGxCyaeNKYZC0sqk3xXGiXd4qtoiJltutR2g.ttf",!0),A.aY("Noto Sans Imperial Aramaic","notosansimperialaramaic/v16/a8IMNpjwKmHXpgXbMIsbTc_kvks91LlLetBr5itQrtdml3YfPNno.ttf",!0),A.aY("Noto Sans Indic Siyaq Numbers","notosansindicsiyaqnumbers/v16/6xK5dTJFKcWIu4bpRBjRZRpsIYHabOeZ8UZLubTzpXNHKx2WPOpVd5Iu.ttf",!0),A.aY("Noto Sans Inscriptional Pahlavi","notosansinscriptionalpahlavi/v16/ll8UK3GaVDuxR-TEqFPIbsR79Xxz9WEKbwsjpz7VklYlC7FCVtqVOAYK0QA.ttf",!0),A.aY("Noto Sans Inscriptional Parthian","notosansinscriptionalparthian/v16/k3k7o-IMPvpLmixcA63oYi-yStDkgXuXncL7dzfW3P4TAJ2yklBJ2jNkLlLr.ttf",!0),A.aY("Noto Sans JP","notosansjp/v52/-F6jfjtqLzI2JPCgQBnw7HFyzSD-AsregP8VFBEj75vY0rw-oME.ttf",!0),A.aY("Noto Sans Javanese","notosansjavanese/v23/2V01KJkDAIA6Hp4zoSScDjV0Y-eoHAHT-Z3MngEefiidxJnkFFliZYWj4O8.ttf",!0),A.aY("Noto Sans KR","notosanskr/v36/PbyxFmXiEBPT4ITbgNA5Cgms3VYcOA-vvnIzzuoyeLTq8H4hfeE.ttf",!0),A.aY("Noto Sans Kaithi","notosanskaithi/v20/buEtppS9f8_vkXadMBJJu0tWjLwjQi0KdoZIKlo.ttf",!0),A.aY("Noto Sans Kannada","notosanskannada/v26/8vIs7xs32H97qzQKnzfeXycxXZyUmySvZWItmf1fe6TVmgop9ndpS-BqHEyGrDvNzSIMLsPKrkY.ttf",!0),A.aY("Noto Sans Kayah Li","notosanskayahli/v21/B50nF61OpWTRcGrhOVJJwOMXdca6Yecki3E06x2jVTX3WCc3CZH4EXLuKVM.ttf",!0),A.aY("Noto Sans Kharoshthi","notosanskharoshthi/v16/Fh4qPiLjKS30-P4-pGMMXCCfvkc5Vd7KE5z4rFyx5mR1.ttf",!0),A.aY("Noto Sans Khmer","notosanskhmer/v23/ijw3s5roRME5LLRxjsRb-gssOenAyendxrgV2c-Zw-9vbVUti_Z_dWgtWYuNAJz4kAbrddiA.ttf",!0),A.aY("Noto Sans Khojki","notosanskhojki/v18/-nFnOHM29Oofr2wohFbTuPPKVWpmK_d709jy92k.ttf",!0),A.aY("Noto Sans Khudawadi","notosanskhudawadi/v21/fdNi9t6ZsWBZ2k5ltHN73zZ5hc8HANlHIjRnVVXz9MY.ttf",!0),A.aY("Noto Sans Lao","notosanslao/v30/bx6lNx2Ol_ixgdYWLm9BwxM3NW6BOkuf763Clj73CiQ_J1Djx9pidOt4ccbdf5MK3riB2w.ttf",!0),A.aY("Noto Sans Lepcha","notosanslepcha/v19/0QI7MWlB_JWgA166SKhu05TekNS32AJstqBXgd4.ttf",!0),A.aY("Noto Sans Limbu","notosanslimbu/v22/3JnlSDv90Gmq2mrzckOBBRRoNJVj0MF3OHRDnA.ttf",!0),A.aY("Noto Sans Linear A","notosanslineara/v18/oPWS_l16kP4jCuhpgEGmwJOiA18FZj22zmHQAGQicw.ttf",!0),A.aY("Noto Sans Linear B","notosanslinearb/v17/HhyJU4wt9vSgfHoORYOiXOckKNB737IV3BkFTq4EPw.ttf",!0),A.aY("Noto Sans Lisu","notosanslisu/v25/uk-3EGO3o6EruUbnwovcYhz6kh57_nqbcTdjJnHP2Vwt29IlxkVdig.ttf",!0),A.aY("Noto Sans Lycian","notosanslycian/v15/QldVNSNMqAsHtsJ7UmqxBQA9r8wA5_naCJwn00E.ttf",!0),A.aY("Noto Sans Lydian","notosanslydian/v17/c4m71mVzGN7s8FmIukZJ1v4ZlcPReUPXMoIjEQI.ttf",!0),A.aY("Noto Sans Mahajani","notosansmahajani/v19/-F6sfiVqLzI2JPCgQBnw60Agp0JrvD5Fh8ARHNh4zg.ttf",!0),A.aY("Noto Sans Malayalam","notosansmalayalam/v26/sJoi3K5XjsSdcnzn071rL37lpAOsUThnDZIfPdbeSNzVakglNM-Qw8EaeB8Nss-_RuD9BFzEr6HxEA.ttf",!0),A.aY("Noto Sans Mandaic","notosansmandaic/v16/cIfnMbdWt1w_HgCcilqhKQBo_OsMI5_A_gMk0izH.ttf",!0),A.aY("Noto Sans Manichaean","notosansmanichaean/v17/taiVGntiC4--qtsfi4Jp9-_GkPZZCcrfekqCNTtFCtdX.ttf",!0),A.aY("Noto Sans Marchen","notosansmarchen/v19/aFTO7OZ_Y282EP-WyG6QTOX_C8WZMHhPk652ZaHk.ttf",!0),A.aY("Noto Sans Masaram Gondi","notosansmasaramgondi/v17/6xK_dThFKcWIu4bpRBjRYRV7KZCbUq6n_1kPnuGe7RI9WSWX.ttf",!0),A.aY("Noto Sans Math","notosansmath/v15/7Aump_cpkSecTWaHRlH2hyV5UHkG-V048PW0.ttf",!0),A.aY("Noto Sans Mayan Numerals","notosansmayannumerals/v16/PlIuFk25O6RzLfvNNVSivR09_KqYMwvvDKYjfIiE68oo6eepYQ.ttf",!0),A.aY("Noto Sans Medefaidrin","notosansmedefaidrin/v23/WwkzxOq6Dk-wranENynkfeVsNbRZtbOIdLb1exeM4ZeuabBfmErWlT318e5A3rw.ttf",!0),A.aY("Noto Sans Meetei Mayek","notosansmeeteimayek/v15/HTxAL3QyKieByqY9eZPFweO0be7M21uSphSdhqILnmrRfJ8t_1TJ_vTW5PgeFYVa.ttf",!0),A.aY("Noto Sans Meroitic","notosansmeroitic/v17/IFS5HfRJndhE3P4b5jnZ3ITPvC6i00UDgDhTiKY9KQ.ttf",!0),A.aY("Noto Sans Miao","notosansmiao/v17/Dxxz8jmXMW75w3OmoDXVV4zyZUjgUYVslLhx.ttf",!0),A.aY("Noto Sans Modi","notosansmodi/v23/pe03MIySN5pO62Z5YkFyT7jeav5qWVAgVol-.ttf",!0),A.aY("Noto Sans Mongolian","notosansmongolian/v17/VdGCAYADGIwE0EopZx8xQfHlgEAMsrToxLsg6-av1x0.ttf",!0),A.aY("Noto Sans Mro","notosansmro/v18/qWcsB6--pZv9TqnUQMhe9b39WDzRtjkho4M.ttf",!0),A.aY("Noto Sans Multani","notosansmultani/v20/9Bty3ClF38_RfOpe1gCaZ8p30BOFO1A0pfCs5Kos.ttf",!0),A.aY("Noto Sans Myanmar","notosansmyanmar/v20/AlZq_y1ZtY3ymOryg38hOCSdOnFq0En23OU4o1AC.ttf",!0),A.aY("Noto Sans NKo","notosansnko/v6/esDX31ZdNv-KYGGJpKGk2_RpMpCMHMLBrdA.ttf",!0),A.aY("Noto Sans Nabataean","notosansnabataean/v16/IFS4HfVJndhE3P4b5jnZ34DfsjO330dNoBJ9hK8kMK4.ttf",!0),A.aY("Noto Sans New Tai Lue","notosansnewtailue/v22/H4cKBW-Pl9DZ0Xe_nHUapt7PovLXAhAnY7wqaLy-OJgU3p_pdeXAYUbghFPKzeY.ttf",!0),A.aY("Noto Sans Newa","notosansnewa/v16/7r3fqXp6utEsO9pI4f8ok8sWg8n_qN4R5lNU.ttf",!0),A.aY("Noto Sans Nushu","notosansnushu/v19/rnCw-xRQ3B7652emAbAe_Ai1IYaFWFAMArZKqQ.ttf",!0),A.aY("Noto Sans Ogham","notosansogham/v17/kmKlZqk1GBDGN0mY6k5lmEmww4hrt5laQxcoCA.ttf",!0),A.aY("Noto Sans Ol Chiki","notosansolchiki/v29/N0b92TJNOPt-eHmFZCdQbrL32r-4CvhzDzRwlxOQYuVALWk267I6gVrz5gQ.ttf",!0),A.aY("Noto Sans Old Hungarian","notosansoldhungarian/v18/E213_cD6hP3GwCJPEUssHEM0KqLaHJXg2PiIgRfjbg5nCYXt.ttf",!0),A.aY("Noto Sans Old Italic","notosansolditalic/v16/TuGOUUFzXI5FBtUq5a8bh68BJxxEVam7tWlRdRhtCC4d.ttf",!0),A.aY("Noto Sans Old North Arabian","notosansoldnortharabian/v16/esDF30BdNv-KYGGJpKGk2tNiMt7Jar6olZDyNdr81zBQmUo_xw4ABw.ttf",!0),A.aY("Noto Sans Old Permic","notosansoldpermic/v17/snf1s1q1-dF8pli1TesqcbUY4Mr-ElrwKLdXgv_dKYB5.ttf",!0),A.aY("Noto Sans Old Persian","notosansoldpersian/v16/wEOjEAbNnc5caQTFG18FHrZr9Bp6-8CmIJ_tqOlQfx9CjA.ttf",!0),A.aY("Noto Sans Old Sogdian","notosansoldsogdian/v16/3JnjSCH90Gmq2mrzckOBBhFhdrMst48aURt7neIqM-9uyg.ttf",!0),A.aY("Noto Sans Old South Arabian","notosansoldsoutharabian/v16/3qT5oiOhnSyU8TNFIdhZTice3hB_HWKsEnF--0XCHiKx1OtDT9HwTA.ttf",!0),A.aY("Noto Sans Old Turkic","notosansoldturkic/v17/yMJNMJVya43H0SUF_WmcGEQVqoEMKDKbsE2RjEw-Vyws.ttf",!0),A.aY("Noto Sans Oriya","notosansoriya/v27/AYCppXfzfccDCstK_hrjDyADv5e9748vhj3CJBLHIARtgD6TJQS0dJT5Ivj0f6_c6LhHBRe-.ttf",!0),A.aY("Noto Sans Osage","notosansosage/v18/oPWX_kB6kP4jCuhpgEGmw4mtAVtXRlaSxkrMCQ.ttf",!0),A.aY("Noto Sans Osmanya","notosansosmanya/v18/8vIS7xs32H97qzQKnzfeWzUyUpOJmz6kR47NCV5Z.ttf",!0),A.aY("Noto Sans Pahawh Hmong","notosanspahawhhmong/v18/bWtp7e_KfBziStx7lIzKKaMUOBEA3UPQDW7krzc_c48aMpM.ttf",!0),A.aY("Noto Sans Palmyrene","notosanspalmyrene/v16/ZgNPjOdKPa7CHqq0h37c_ASCWvH93SFCPnK5ZpdNtcA.ttf",!0),A.aY("Noto Sans Pau Cin Hau","notosanspaucinhau/v20/x3d-cl3IZKmUqiMg_9wBLLtzl22EayN7ehIdjEWqKMxsKw.ttf",!0),A.aY("Noto Sans Phags Pa","notosansphagspa/v15/pxiZyoo6v8ZYyWh5WuPeJzMkd4SrGChkqkSsrvNXiA.ttf",!0),A.aY("Noto Sans Phoenician","notosansphoenician/v17/jizFRF9Ksm4Bt9PvcTaEkIHiTVtxmFtS5X7Jot-p5561.ttf",!0),A.aY("Noto Sans Psalter Pahlavi","notosanspsalterpahlavi/v16/rP2Vp3K65FkAtHfwd-eISGznYihzggmsicPfud3w1G3KsUQBct4.ttf",!0),A.aY("Noto Sans Rejang","notosansrejang/v21/Ktk2AKuMeZjqPnXgyqrib7DIogqwN4O3WYZB_sU.ttf",!0),A.aY("Noto Sans Runic","notosansrunic/v17/H4c_BXWPl9DZ0Xe_nHUaus7W68WWaxpvHtgIYg.ttf",!0),A.aY("Noto Sans SC","notosanssc/v36/k3kCo84MPvpLmixcA63oeAL7Iqp5IZJF9bmaG9_FnYxNbPzS5HE.ttf",!0),A.aY("Noto Sans Saurashtra","notosanssaurashtra/v23/ea8GacQ0Wfz_XKWXe6OtoA8w8zvmYwTef9ndjhPTSIx9.ttf",!0),A.aY("Noto Sans Sharada","notosanssharada/v16/gok0H7rwAEdtF9N8-mdTGALG6p0kwoXLPOwr4H8a.ttf",!0),A.aY("Noto Sans Shavian","notosansshavian/v17/CHy5V_HZE0jxJBQlqAeCKjJvQBNF4EFQSplv2Cwg.ttf",!0),A.aY("Noto Sans Siddham","notosanssiddham/v20/OZpZg-FwqiNLe9PELUikxTWDoCCeGqndk3Ic92ZH.ttf",!0),A.aY("Noto Sans Sinhala","notosanssinhala/v26/yMJ2MJBya43H0SUF_WmcBEEf4rQVO2P524V5N_MxQzQtb-tf5dJbC30Fu9zUwg2a5lgLpJwbQRM.ttf",!0),A.aY("Noto Sans Sogdian","notosanssogdian/v16/taiQGn5iC4--qtsfi4Jp6eHPnfxQBo--Pm6KHidM.ttf",!0),A.aY("Noto Sans Sora Sompeng","notosanssorasompeng/v24/PlIRFkO5O6RzLfvNNVSioxM2_OTrEhPyDLolKvCsHzCxWuGkYHR818DpZXJQd4Mu.ttf",!0),A.aY("Noto Sans Soyombo","notosanssoyombo/v17/RWmSoL-Y6-8q5LTtXs6MF6q7xsxgY0FrIFOcK25W.ttf",!0),A.aY("Noto Sans Sundanese","notosanssundanese/v24/FwZw7_84xUkosG2xJo2gm7nFwSLQkdymq2mkz3Gz1_b6ctxpNNHCizv7fQES.ttf",!0),A.aY("Noto Sans Syloti Nagri","notosanssylotinagri/v20/uU9eCAQZ75uhfF9UoWDRiY3q7Sf_VFV3m4dGFVfxN87gsj0.ttf",!0),A.aY("Noto Sans Syriac","notosanssyriac/v16/Ktk7AKuMeZjqPnXgyqribqzQqgW0LYiVqV7dXcP0C-VD9MaJyZfUL_FC.ttf",!0),A.aY("Noto Sans TC","notosanstc/v35/-nFuOG829Oofr2wohFbTp9ifNAn722rq0MXz76Cy_CpOtma3uNQ.ttf",!0),A.aY("Noto Sans Tagalog","notosanstagalog/v22/J7aFnoNzCnFcV9ZI-sUYuvote1R0wwEAA8jHexnL.ttf",!0),A.aY("Noto Sans Tagbanwa","notosanstagbanwa/v18/Y4GWYbB8VTEp4t3MKJSMmQdIKjRtt_nZRjQEaYpGoQ.ttf",!0),A.aY("Noto Sans Tai Le","notosanstaile/v17/vEFK2-VODB8RrNDvZSUmVxEATwR58tK1W77HtMo.ttf",!0),A.aY("Noto Sans Tai Tham","notosanstaitham/v20/kJEbBv0U4hgtwxDUw2x9q7tbjLIfbPGHBoaVSAZ3MdLJBCUbPgquyaRGKMw.ttf",!0),A.aY("Noto Sans Tai Viet","notosanstaiviet/v19/8QIUdj3HhN_lv4jf9vsE-9GMOLsaSPZr644fWsRO9w.ttf",!0),A.aY("Noto Sans Takri","notosanstakri/v23/TuGJUVpzXI5FBtUq5a8bnKIOdTwQNO_W3khJXg.ttf",!0),A.aY("Noto Sans Tamil","notosanstamil/v27/ieVc2YdFI3GCY6SyQy1KfStzYKZgzN1z4LKDbeZce-0429tBManUktuex7vGo70RqKDt_EvT.ttf",!0),A.aY("Noto Sans Tamil Supplement","notosanstamilsupplement/v21/DdTz78kEtnooLS5rXF1DaruiCd_bFp_Ph4sGcn7ax_vsAeMkeq1x.ttf",!0),A.aY("Noto Sans Telugu","notosanstelugu/v25/0FlxVOGZlE2Rrtr-HmgkMWJNjJ5_RyT8o8c7fHkeg-esVC5dzHkHIJQqrEntezbqQUbf-3v37w.ttf",!0),A.aY("Noto Sans Thaana","notosansthaana/v23/C8c14dM-vnz-s-3jaEsxlxHkBH-WZOETXfoQrfQ9Y4XrbhLhnu4-tbNu.ttf",!0),A.aY("Noto Sans Thai","notosansthai/v20/iJWnBXeUZi_OHPqn4wq6hQ2_hbJ1xyN9wd43SofNWcd1MKVQt_So_9CdU5RtpzF-QRvzzXg.ttf",!0),A.aY("Noto Sans Tifinagh","notosanstifinagh/v20/I_uzMoCduATTei9eI8dawkHIwvmhCvbn6rnEcXfs4Q.ttf",!0),A.aY("Noto Sans Tirhuta","notosanstirhuta/v16/t5t6IQYRNJ6TWjahPR6X-M-apUyby7uGUBsTrn5P.ttf",!0),A.aY("Noto Sans Ugaritic","notosansugaritic/v16/3qTwoiqhnSyU8TNFIdhZVCwbjCpkAXXkMhoIkiazfg.ttf",!0),A.aY("Noto Sans Vai","notosansvai/v17/NaPecZTSBuhTirw6IaFn_UrURMTsDIRSfr0.ttf",!0),A.aY("Noto Sans Wancho","notosanswancho/v17/zrf-0GXXyfn6Fs0lH9P4cUubP0GBqAPopiRfKp8.ttf",!0),A.aY("Noto Sans Warang Citi","notosanswarangciti/v17/EYqtmb9SzL1YtsZSScyKDXIeOv3w-zgsNvKRpeVCCXzdgA.ttf",!0),A.aY("Noto Sans Yi","notosansyi/v19/sJoD3LFXjsSdcnzn071rO3apxVDJNVgSNg.ttf",!0),A.aY("Noto Sans Zanabazar Square","notosanszanabazarsquare/v19/Cn-jJsuGWQxOjaGwMQ6fOicyxLBEMRfDtkzl4uagQtJxOCEgN0Gc.ttf",!0)],t.Qg))}return r},'
font_list_content = original_text.split('"')
font_list = []
for font in font_list_content:
if font.endswith(".ttf"):
font_list.append(font)
host = 'https://fonts.gstatic.com/s/'
fonts = "fonts/"
path = ""
for font in font_list:
folder_list = font.split("/")
for folder in folder_list:
if (folder.endswith(".ttf")):
url = host + path + folder
proxies = {
'http': 'http://127.0.0.1:9098', # 替换为你的VPN IP和端口
'https': 'http://127.0.0.1:9098', # 同上
}
r = requests.get(url,proxies=proxies)
print("finish")
with open(fonts + path + folder, 'wb') as file:
file.write(r.content)
path = ""
else:
path += folder + "/"
os.makedirs(fonts + path, exist_ok=True)
其中由于这两天Google
的字体服务器连接不上,所以我使用了vpn
,在代码中需要通过proxies
进行代理的相关配置。下载完成后的结果如下:
我们再将所有的字体资源上传到CDN
上,然后修改main.dart.js
文件,将Host
改为我们CDN
的相应地址,然后我们来看一下优化效果:
优化之前也是2,3秒的样子,再看一下优化后的:也是毫秒级别,可见优化效果之明显。
字体的打包部署时如何优化我们已经了解了。那么我们开发调试的时候应该怎么处理呢?我们复习一下Flutter Web
的渲染模式:
Flutter
为了实现多浏览器的效果一致性,在canvaskit
渲染模式下,会下载相应的字体进行绘制。因此在开发调试的阶段,我们可以关闭canvaskit
渲染模式使用html
方式进行渲染,就不会加载这些字体了。命令如下:
flutter run -d Chrome -t lib/main_test.dart --web-renderer html
这样就解决了开发调试时的字体问题。
05
总结
到此为止,我们通过main.dart.js分包
,配置canvaskit.js
和canvaskit.wasm
的加载url
,字体加载优化这三个方式可以为Flutter Web
项目减少5-6秒的启动耗时。希望可以给大家一些帮助。