如何優雅的將專案中的程式碼,亦或是你的demo程式碼展示到介面上?本文對使用簡單、便於維護且通用的解決方案,進行相關的對比和探究
為了節省大家的時間,把最終解決方案的相關接入和用法寫在前面
dependencies:
code_preview: ^0.1.5
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');
}
}
因為原理是遍歷資原始檔,所以必須將需要展示的程式碼檔案或者其資料夾路徑,定義在assets下,這步操作,為大家提供了一個自動化的外掛解決
強烈建議需要展示到介面的程式碼,都放在統一的資料夾裡管理
如果程式碼預覽的資料夾,分級複雜,每次都需要定義路徑實在麻煩
提供一個外掛:Flutter Code Helper
Flutter Code Helper
code_helper:
auto_folder: [ "assets/", "lib/widgets/" ]
說明下:上面的外掛是基於RayC的FlutterAssetsGenerator外掛專案改的
所以沒向其外掛裡面提pr,就單獨新開了個外掛專案
主題
提供倆種程式碼樣式主題
CodePreview.config = CodePreviewConfig(codeTheme: CodeTheme.light);
CodePreview.config = CodePreviewConfig(codeTheme: CodeTheme.dark);
註釋解析
@
,舉例(@title,@xxx)分號
分割,舉例(@xxx: xxx)中劃線
/// @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
的回撥獲取param引數,param中擁有parseParam引數
customBuilder
的用法
codeWidget
內建的程式碼預覽佈局,如果你想定義自己預覽程式碼的佈局,那就可以不使用codeWidget
codeWidget
巢狀來自定義符合要求的佈局param
中含有多個有用內容,可自行檢視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;
},
);
}
}
CodePreview.config = CodePreviewConfig(removeParseComment: false);
FlutterUnit專案也是自帶程式碼預覽方案,這套方案是比較特殊方案
flutter.db
,該檔案裡面就有相關demo的文字資訊widgets
的專案中widgets
的專案中的demo程式碼總結
整套流程看下來,實現起來的工作量還是有點大的
優點
缺點
build_runner是個強大程式碼自動生成工具,根據ast語法樹+自定義註解資訊,可以生成很多強大的附屬程式碼資訊,例如 json_serializable
等庫
所以,也能利用這點自定義類註解,獲取到對應的整個類的程式碼資訊,在對應附屬的xx.g.dart
檔案中,將獲取的程式碼內容轉換成字串,然後直接將xx.g.dart
檔案的程式碼字串資訊,展示到介面就行了
優點
缺點
build_runner
需要解析整個ast語法樹,一旦專案很大之後,解析生成的時間會非常非常的長!build_runner
,所以跑自動生成命令,會導致巨多xx.g.dart
檔案被改動,極大的增加cr工作量這應該最常用的一種方案
pubspec.yaml
中的assets
中定義下我們程式碼檔案路徑flutter:
assets:
- lib/widgets/show/
final code = await rootBundle.loadString('lib/widgets/show/custome_dialog_animation.dart');
優點
build_runnner
方案那樣影響到其它模組缺點
pubspec.yaml
中的assets
裡面定義檔案路徑上面的三種方案各有優缺點,明確當前的訴求
目前是想寫個簡單的,通用的,僅在Flutter中實現程式碼預覽方案
要求使用簡單,高效
維護簡單,多人開發的時候不會有很大成本
FlutterUnit方案:實現起來成本較大,且多人開發對單個db檔案的維護很可能會有點問題,例如:更新程式碼的時候,db檔案忘記更新
build_runner方案:生成時間是個問題,還有很對其他型別xx.g.dart
檔案產生影響也比較麻煩
資原始檔方案:整體是符合預期的,但是使用時候,需要傳入路徑和pubspec.yaml
中反覆定義檔案路徑,這是倆個很大痛點
結合實現成本和訴求,選擇資原始檔方案
,下面對其痛點進行優化
Flutter的編譯產物中,有個相當有用的檔案:AssetManifest.json
AssetManifest.json檔案裡面,有所有的資原始檔的路徑,然後就簡單了,我們只需要讀取該檔案內容
final manifestContent = await rootBundle.loadString('AssetManifest.json');
獲取到所有的路徑之後,再結合傳入的類名,讀取所有路徑的檔案內容,然後和傳入的類名做正則匹配就行了
稍微優化
優化前
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');
}
}
優化後
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');
}
}
本來是想在pubspec.yaml
的assets
裡面直接寫萬用字元定義全路徑,然後悲劇了,它不支援這種寫法
flutter:
assets:
- lib/widgets/**/*.dart
GG,只能想其他辦法了,想了很多方法都不行,只能從外部入手,用idea外掛的形式,實現自動化掃描生成路徑
Flutter Code Helper
code_helper:
auto_folder: [ "assets/", "lib/widgets/" ]
flutter web的release模式中
TestWidgetFunction
類的runtimeType,可能會變成minified:Ah
,而不是TestWidgetFunction
!為啥需要壓縮呢?壓縮名稱可以使得編譯器將 JavaScript體積縮小 3 倍+;精確等效語意和效能/程式碼大小之間的權衡,Dart明顯是選擇了後者
這種情況只會在Flutter Web的release模式下發生,其他平臺和Flutter web的Debug | Profile模式都不會有這種問題;所以說Xxx.runtimeType.toString
,並不一定會得到預期內的資料。。。
具體討論可參考
解決思路
minified:Ah
恢復成 Test
Test
字串使用相同演演算法壓縮成minified:Ah
如有知道如何實現的,務必告訴鄙人
下面從壓縮級別調整的角度,探究是否可解決該問題
注:flutter build web預設的是O4優化級別
下面是flutter新建專案,未做任何改動,不同壓縮級別的js產物體積
# 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
CodePreview(code: Test());
但是
綜上可知,使用flutter build web --dart2js-optimization O1
編譯的flutter web release產物,能夠使得runtimeType的語意和Dart VM中字串保持一致
但是該壓縮級別下的,js體積過於誇張,務必會對載入速度產生極大影響,可想而知,在複雜專案中的體積增漲肯定更加離譜
對於想要用法更加簡單,使用低階別壓縮命令打包的想法需要捨棄
CodePreview(className: "Test");
這是個讓我非常糾結的思路歷程
到這裡也結束了,自我感覺,對大家應該能有一些幫助
一般來說,大部分團隊,都會有個自己的內部元件庫,因為Flutter強大的跨平臺特性,所以就能很輕鬆的釋出到web平臺,可以方便的體驗各種元件的效果,結合文章中的程式碼預覽方案,就可以更加快速的上手各種元件用法了~
好了,下次再見了,靚仔們!