前言
如何優(yōu)雅的將項目中的代碼,亦或是你的 demo 代碼展示到界面上?本文對使用簡單、便于維護(hù)且通用的解決方案,進(jìn)行相關(guān)的對比和探究
為了節(jié)省大家的時間,把最終解決方案的相關(guān)接入和用法寫在前面
預(yù)覽代碼
快速開始
接入:pub,github
dependencies: code_preview: ^0.1.5
用法:CodePreview,提供需要預(yù)覽的 className,可自動匹配該類對應(yīng)的代碼文件
本來想把寫法簡化成傳入對象,但是因?yàn)橐恍┰驘o奈放棄,改成了className
具體可以參考下面Flutter Web中的問題模塊的說明
import 'package:code_preview/code_preview.dart'; import 'package:flutter/material.dart'; class Test extends StatelessWidget { const Test({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return const CodePreview(className: 'Test'); } }
使用效果:flutter_smart_dialog
配置代碼文件
因?yàn)樵硎潜闅v資源文件,所以必須將需要展示的代碼文件或者其文件夾路徑,定義在 assets 下,這步操作,為大家提供了一個自動化的插件解決
強(qiáng)烈建議需要展示到界面的代碼,都放在統(tǒng)一的文件夾里管理
展示界面的代碼需要在 pugspec.yaml 中的 assets 定義
如果代碼預(yù)覽的文件夾,分級復(fù)雜,每次都需要定義路徑實(shí)在麻煩
提供一個插件:Flutter Code Helper
安裝:Plugins 中搜索Flutter Code Helper
pugspec.yaml 中定義下需要自動生成文件夾的路徑,文件夾隨便套娃,會自動幫你遞歸在 assets 下生成
不需要自動生成,可:不寫該配置,或者配置空數(shù)組(auto_folder: [])
code_helper: auto_folder: [ "assets/", "lib/widgets/" ]
說明下:上面的插件是基于 RayC 的 FlutterAssetsGenerator 插件項目改的
看了下 RayC 的插件代碼和相關(guān)功能,和我預(yù)想的上面功能實(shí)現(xiàn)有一定出入,改動起來變動較大
想試下插件項目的各種新配置,直接拉到最新
后期如果想到需要什么功能,方便隨時添加
所以沒向其插件里面提 pr,就單獨(dú)新開了個插件項目
高級使用
主題
提供倆種代碼樣式主題
日間模式
CodePreview.config = CodePreviewConfig(codeTheme: CodeTheme.light);
夜間模式
CodePreview.config = CodePreviewConfig(codeTheme: CodeTheme.dark);
注釋解析
你可以使用如下的格式,在類上添加注釋
key 的前面必須加@,舉例(@title,@xxx)
key 與 value 的之間,必須使用分號分割,舉例(@xxx: xxx)
value 如果需要換行,換行的文案前必須加中劃線
/// @title: /// - test title one /// - test title two /// @content: test content /// @description: test description class OneWidget extends StatelessWidget { const OneWidget({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return const Placeholder(); } }
然后可以從customBuilder的回調(diào)獲取 param 參數(shù),param 中擁有 parseParam 參數(shù)
獲取取得上面注釋的數(shù)據(jù):param.parseParam ['title'] 或者 param.parseParam ['***']
獲取的 value 的類型是 List
customBuilder的用法
codeWidget內(nèi)置的代碼預(yù)覽布局,如果你想定義自己預(yù)覽代碼的布局,那就可以不使用codeWidget
一般來說,可以根據(jù)注釋獲取的數(shù)據(jù),結(jié)合codeWidget嵌套來自定義符合要求的布局
param中含有多個有用內(nèi)容,可自行查看
import 'package:code_preview/code_preview.dart'; import 'package:flutter/material.dart'; class Test extends StatelessWidget { const Test({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return CodePreview( className: 'OneWidget', customBuilder: (Widget codeWidget, CustomParam? param) { debugPrint(param?.parseParam['title'].toString()); debugPrint(param?.parseParam['content'].toString()); debugPrint(param?.parseParam['description'].toString()); return codeWidget; }, ); } }
目前內(nèi)部預(yù)覽的布局,會自動去掉類上的注釋,如果想保留注釋,可自行匹配下
CodePreview.config = CodePreviewConfig(removeParseComment: false);
幾種代碼預(yù)覽方案
FlutterUnit 方案
FlutterUnit 項目也是自帶代碼預(yù)覽方案,這套方案是比較特殊方案
大概看了下,整個 FlutterUnit 的數(shù)據(jù)都是基于flutter.db,該文件里面就有相關(guān) demo 的文本信息
所有的 demo 也是單獨(dú)存在一個叫widgets的項目中
所以大概可以猜測出
應(yīng)該會有個 db 的輔助工具,會去掃描widgets的項目中的 demo 代碼
將他們的文本信息都掃描出來,然后解析上面的注釋等相關(guān)信息,分類存儲到數(shù)據(jù)庫中,最后生成 db 文件
映射表,宿主可以通過 db 中的組件類名,從這里拿到 demo 效果實(shí)例
總結(jié)
整套流程看下來,實(shí)現(xiàn)起來的工作量還是有點(diǎn)大的
db 輔助工具的編寫
文本注釋相關(guān)解析規(guī)則
如何便捷的維護(hù) db 文件(輔助工具是否支持,生成后自動覆蓋宿主 db 文件)
不同平臺 db 文件的讀取和相關(guān)適配
優(yōu)點(diǎn)
因?yàn)閽呙韫ぞ卟灰蕾?Flutter 相關(guān)庫,預(yù)覽方案可以快速的移植到其它編程語言(compose,SwiftUI 等)
具備高度自定義,因?yàn)槭峭耆?dú)立的第三方掃描工具,可以隨性所欲的定制化
缺點(diǎn)
最明顯的缺點(diǎn),應(yīng)該就是稍微改下 demo 代碼,就需要三方工具重新生成 db 文件(如果三方工具實(shí)現(xiàn)的是 cli 工具,可以將掃描生成命令和 push 等命令集成一起,應(yīng)該可以比較好的避免該問題)
build_runner 方案
build_runner 是個強(qiáng)大代碼自動生成工具,根據(jù) ast 語法樹 + 自定義注解信息,可以生成很多強(qiáng)大的附屬代碼信息,例如json_serializable等庫
所以,也能利用這點(diǎn)自定義類注解,獲取到對應(yīng)的整個類的代碼信息,在對應(yīng)附屬的xx.g.dart文件中,將獲取的代碼內(nèi)容轉(zhuǎn)換成字符串,然后直接將xx.g.dart文件的代碼字符串信息,展示到界面就行了
優(yōu)點(diǎn)
可以通過生成命令,全自動的生成代碼,甚至將整個預(yù)覽 demo 的映射表都可以自動配置完成
可以規(guī)范的通過注解配置多個參數(shù)
缺點(diǎn)
因?yàn)閎uild_runner需要解析整個 ast 語法樹,一旦項目很大之后,解析生成的時間會非常非常的長!
因?yàn)楝F(xiàn)在很多的這類庫都是依賴build_runner,所以跑自動生成命令,會導(dǎo)致巨多xx.g.dart文件被改動,極大的增加 cr 工作量
資源文件方案
這應(yīng)該最常用的一種方案
在pubspec.yaml中的assets中定義下我們代碼文件路徑
flutter: assets: - lib/widgets/show/
然后用 loadString 獲取文件內(nèi)容
final code = await rootBundle.loadString('lib/widgets/show/custome_dialog_animation.dart');
優(yōu)點(diǎn)
侵入性非常低,不會像build_runnner方案那樣影響到其它模塊
便于維護(hù),如果 demo 預(yù)覽代碼被改變了,打包的時候,資源文件也會生成對應(yīng)改變后的代碼文件
缺點(diǎn)
使用麻煩,使用的時候需要傳入具體的文件路徑,才能找到想要的代碼資源文件
需要反復(fù)的在pubspec.yaml中的assets里面定義文件路徑
資源文件方案優(yōu)化
上面的三種方案各有優(yōu)缺點(diǎn),明確當(dāng)前的訴求
目前是想寫個簡單的,通用的,僅在 Flutter 中實(shí)現(xiàn)代碼預(yù)覽方案
要求使用簡單,高效
維護(hù)簡單,多人開發(fā)的時候不會有很大成本
FlutterUnit 方案:實(shí)現(xiàn)起來成本較大,且多人開發(fā)對單個 db 文件的維護(hù)很可能會有點(diǎn)問題,例如:更新代碼的時候,db 文件忘記更新
build_runner 方案:生成時間是個問題,還有很對其他類型xx.g.dart文件產(chǎn)生影響也比較麻煩
資源文件方案:整體是符合預(yù)期的,但是使用時候,需要傳入路徑和pubspec.yaml中反復(fù)定義文件路徑,這是倆個很大痛點(diǎn)
結(jié)合實(shí)現(xiàn)成本和訴求,選擇資源文件方案,下面對其痛點(diǎn)進(jìn)行優(yōu)化
使用優(yōu)化
Flutter 的編譯產(chǎn)物中,有個相當(dāng)有用的文件:AssetManifest.json
AssetManifest.json 文件里面,有所有的資源文件的路徑,然后就簡單了,我們只需要讀取該文件內(nèi)容
final manifestContent = await rootBundle.loadString('AssetManifest.json');
獲取到所有的路徑之后,再結(jié)合傳入的類名,讀取所有路徑的文件內(nèi)容,然后和傳入的類名做正則匹配就行了
稍微優(yōu)化
將傳入的類名,轉(zhuǎn)換為下劃線名稱和所有路徑名稱做匹配,如果能匹配上,再進(jìn)行內(nèi)容匹配,匹配成功后就返回該文件的代碼內(nèi)容
如果上述匹配失敗,就進(jìn)行兜底的全量匹配
優(yōu)化前
import 'package:code_preview/code_preview.dart'; import 'package:flutter/material.dart'; class Test extends StatelessWidget { const Test({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return const CodePreview(path: 'lib/widgets/show/custome_dialog_animation.dart'); } }
優(yōu)化后
import 'package:code_preview/code_preview.dart'; import 'package:flutter/material.dart'; class Test extends StatelessWidget { const Test({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return const CodePreview(className: 'CustomDialogAnimation'); } }
一般來說,我是統(tǒng)一配置預(yù)覽 demo 和 className,這樣比較好對照
路徑定義優(yōu)化
本來是想在pubspec.yaml的assets里面直接寫通配符定義全路徑,然后悲劇了,它不支持這種寫法
flutter: assets: - lib/widgets/**/*.dart
GG,只能想其他辦法了,想了很多方法都不行,只能從外部入手,用 idea 插件的形式,實(shí)現(xiàn)自動化掃描生成路徑
安裝:Plugins 中搜索Flutter Code Helper
pugspec.yaml 中定義下需要自動生成文件夾的目錄,文件夾隨便套娃,會自動幫你遞歸在 assets 下生成
不需要自動生成,可:不寫該配置,或者配置空數(shù)組(auto_folder: [])
code_helper: auto_folder: [ "assets/", "lib/widgets/" ]
Flutter Web 中的問題
魔幻的 runtimeType
flutter web 的 release 模式中
dart2js 會壓縮 JS,這樣會使得類型名被改變
例如:dart 中的TestWidgetFunction類的 runtimeType,可能會變成minified:Ah,而不是TestWidgetFunction!
為啥需要壓縮呢?壓縮名稱可以使得編譯器將 JavaScript 體積縮小 3 倍 +;精確等效語義和性能 / 代碼大小之間的權(quán)衡,Dart 明顯是選擇了后者
這種情況只會在 Flutter Web 的 release 模式下發(fā)生,其他平臺和 Flutter web 的 Debug | Profile 模式都不會有這種問題;所以說Xxx.runtimeType.toString,并不一定會得到預(yù)期內(nèi)的數(shù)據(jù)。。。
解決思路
將壓縮類型minified:Ah恢復(fù)成Test
將獲取的Test字符串使用相同算法壓縮成minified:Ah
如有知道如何實(shí)現(xiàn)的,務(wù)必告訴鄙人
下面從壓縮級別調(diào)整的角度,探究是否可解決該問題
dart2js 壓縮說明
注:flutter build web 默認(rèn)的是 O4 優(yōu)化級別
O0: 禁用許多優(yōu)化。
O1: 啟用默認(rèn)優(yōu)化 (僅是 dart2js 該命令的默認(rèn)級別)
O2: 在 O1 優(yōu)化基礎(chǔ)上,尊重語言語義且對所有程序安全的其他優(yōu)化(例如縮小)
備注:使用 - O2, 使用開發(fā) JavaScript 編譯器編譯時,類型的字符串表示不再與 Dart VM 中的字符串表示相同
O3: 在 O2 優(yōu)化基礎(chǔ)上,并省略隱式類型檢查。
注意:省略類型檢查可能會導(dǎo)致應(yīng)用程序因類型錯誤而崩潰
O4: 在 O3 優(yōu)化基礎(chǔ)上,啟用更積極的優(yōu)化
注意:O4 優(yōu)化容易受到輸入數(shù)據(jù)變化的影響,在依賴 O4 之前,需測試用戶輸入中的邊緣情況
下面是 flutter 新建項目,未做任何改動,不同壓縮級別的 js 產(chǎn)物體積
# main.dart.js: 7.379MB flutter build web --dart2js-optimization O0 # main.dart.js: 5.073MB flutter build web --dart2js-optimization O1 # main.dart.js: 1.776MB flutter build web --dart2js-optimization O2 # main.dart.js: 1.716MB flutter build web --dart2js-optimization O3 # main.dart.js: 1.687MB flutter build web --dart2js-optimization O4
總結(jié)
預(yù)期用法
為什么想使用對象?因?yàn)楫?dāng)對象名稱改變時,對應(yīng)使用的地方,可以便捷觀察到需要改變
可以使用傳入的對象實(shí)例,在內(nèi)部使用 runtimeType 獲取類型名,再進(jìn)行相關(guān)匹配
CodePreview(code: Test());
但是
綜上可知,使用flutter build web --dart2js-optimization O1編譯的 flutter web release 產(chǎn)物,能夠使得 runtimeType 的語義和 Dart VM 中字符串保持一致
但是該壓縮級別下的,js 體積過于夸張,務(wù)必會對加載速度產(chǎn)生極大影響,可想而知,在復(fù)雜項目中的體積增漲肯定更加離譜
對于想要用法更加簡單,使用低級別壓縮命令打包的想法需要舍棄
用法不得已做妥協(xié)
CodePreview(className: "Test");
這是個讓我非常糾結(jié)的思路歷程
最后
到這里也結(jié)束了,自我感覺,對大家應(yīng)該能有一些幫助
一般來說,大部分團(tuán)隊,都會有個自己的內(nèi)部組件庫,因?yàn)?Flutter 強(qiáng)大的跨平臺特性,所以就能很輕松的發(fā)布到 web 平臺,可以方便的體驗(yàn)各種組件的效果,結(jié)合文章中的代碼預(yù)覽方案,就可以更加快速的上手各種組件用法了~
審核編輯:劉清
-
Rayc
+關(guān)注
關(guān)注
0文章
2瀏覽量
6082 -
flutter
+關(guān)注
關(guān)注
0文章
13瀏覽量
530
原文標(biāo)題:Flutter如何將代碼顯示到界面上
文章出處:【微信號:OSC開源社區(qū),微信公眾號:OSC開源社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
如何將RT-Thread移植到NXP MCUXPressoIDE上

評論