Flutter Widget IDE 预览新进展,开始推进落地发布

去年 11 月我们就聊过《Flutter 终于正式规划 IDE Widget 预览支持》,而现在 Widget 预览功能终于开始推进正式落地,并发布了第二版的规划文档

如果你没看到前文,建议看看 :juejin.cn/post/744100...

其实一直以来由于 Flutter 具备 hotload 的能力,所以在 Widget Preview 能力这部分都被认为不是必须的场景,但是基于开发者可以更直观验证一些场景,如屏幕大小、方向、字体大小和区域设置等变量对App 的影响,Widget 预览最终还是被提上了议程。

而这次, Widget Preview 之所以正式开始推进,核心主要依赖两点:

因为 Widget Preview 实际会在 .dart_tool 目录下创建一个名为 widget_preview_scaffold 的 Flutter 项目,这个预览支持项目是一个 Flutter Web App

所以可以理解为,现在大家都是基于 Canvas 的同源 UI ,所以可以用 Web 来实时渲染,从而在 IDE 内实现实时预览。

在预览里,开发者可以和预览进行交互,支持缩放和平移,甚至可以预览动画,不过预览时的实际帧率最高只会是 60 FPS。

而本次 V2 版本规划的预览支持里,主要是新增了 flutter widget-preview 一些列命令,命令负责为项目生成预览脚手架并与预览环境交互支持。

例如,执行 flutter widget-preview start 命令后,就会在 .dart_tool 目录下生成一个预览工程,工程结构大致为:

  • lib/src/widget_preview_rendering.dart:preview scaffold 项目的真正入口点,负责初始化 Dart Tooling Daemon(DTD) 服务和用于渲染 lib/src/generated_preview.dart 中定义的预览的控件
  • lib/src/generated_preview.dart :包含 List<WidgetPreview> previews() 函数,函数最终会将已处理的 WidgetPreview 列表返回到 preview scaffold 用于渲染
  • lib/src/widget_preview.dart:包含 WidgetPreview 类的定义,是一个与 Preview 接近 1:1 映射的数据类,类包括一个 builder 属性,这个属性采用一个闭包返回要预览的 widget
  • lib/src/dtd_services.dart:包含一个 Dart Tooling Daemon (DTD) 服务器连接,为工具提供 Widget 预览服务,并访问其他工具提供的服务(比如和 IDE、分析服务器等交互)。

之后命令会初始化 widget_preview_scaffoldpubspec.yaml,在开发者的项目中添加路径依赖,并列出开发者项目中的资源。

然后在 widget_preview_scaffold 的根目录下生成一个 preview_manifest.json ,包含有关当前 Dart 和 Flutter SDK 版本的信息,以及用户的 pubspec.yaml 的哈希值,这个哈希值用于后续自动对比用户工程的 pubspec 是否发生变化。

接着会使用 package:analyzer 搜索 @Preview() 注解,就如下面代码一样 ,记录需要预览函数名称、库和提供给注解的所有参数等。

最终会根据 analyzer 搜索的结果生成 lib/src/generated_preview.dart

dart 复制代码
@Preview(name: 'Top-level preview')
Widget preview() => const Text('Foo');
​
​
@Preview(name: 'Builder preview')
WidgetBuilder builderPreview() {
  return (BuildContext context) {
    return const Text('Builder');
  };
}
​
​
class MyWidget extends StatelessWidget {
  @Preview(name: 'Constructor preview')
  const MyWidget.preview({super.key});
​
​
  @Preview(name: 'Factory constructor preview')
  factory MyWidget.factoryPreview() => const MyWidget.preview();
​
​
  @Preview(name: 'Static preview')
  static Widget previewStatic() => const Text('Static');
​
​
  @override
  Widget build(BuildContext context) {
    return const Text('MyWidget');
  }
}
​

而一旦用户运行了命令并生成预览脚手架工程之后,它就会被编译并使用提供的 --machine 运行,之后 Flutter 工具将在开发人员的项目目录上初始化一个文件观察器,用于检测源代码的更改,比如:

analyzer 会检测文件中添加或删除的 @Preview() ,必要时重新生成 lib/src/generated_preview.dart 。

另外,flutter widget-preview clean 可以触发删除 .dart_tool/widget_preview_scaffold/ 项目,强制它在下次运行 flutter widget-preview start 时重新生成 。

而针对 Preview 注解也有可定制参数,比如在预览时调节主题,亮度,文本大小等:

js 复制代码
base class Preview {
  /// Annotation used to mark functions that return widget previews.
  const Preview({
    this.name,
    this.width,
    this.height,
    this.textScaleFactor,
    this.wrapper,
    this.theme,
    this.brightness,
  });
​

同时,为了防止用户在整个 widget 预览环境中执行热重启,每个渲染的预览都能够在预览的 widget 上执行 "Soft restart" :

"Soft restart" 只是从一帧的 widget 树中删除预览的 widget,然后再将其重新插入到下一帧:github.com/flutter/flu...

最后,因为最终需要在 IDE 中托管的 webview 中打开预览,需要类似于 Dart/Flutter DevTools 嵌入到 IDE 中的方式,但是由于 DWDS(Web VM 服务实现)需要一个开放的 Chrome 调试端口才能运行,这在 VSCode 等 IDE 中不可用,但是 DWDS 又是热重载的必备支持,所以目前最大的阻碍是:

在没有 Chrome 调试端口的情况下运行 DWDS,同时保持热重载,做到当 DWDS 无法访问 Chrome 调试器时,改为提供一组有限的功能:github.com/dart-lang/w...

其他问题还有比如 dart:io、原生插件等场景需要如何在预览工程处理,但是这些问题都是后话,在 DWDS 适配 IDE场景支持后,IDE 预览就可以基本考虑实验性落地了。

看得出来其实 IDE 预览的话核心其实来自 Flutter Web ,由于 Flutter Web 支持 hotload 之后,用一个阴影工程来做实时预览确实是一个相对低成本的选择,不过真的要完整落地,需要考虑的细节还是很多,其中最重要的莫过于使用过程中的性能影响,如果体验太差,还不如直接 hotload 运行实际。

那么,你会期待或者需要 Flutter 的 IDE Widget 预览吗?

参考链接

相关推荐
前端大白话14 分钟前
救命!这10个Vue3技巧藏太深了!性能翻倍+摸鱼神器全揭秘
前端·javascript·vue.js
嘻嘻嘻嘻嘻嘻ys16 分钟前
《Vue 3全栈架构实战:Vite工程化、Pinia状态管理与Nuxt 3深度解析》
前端·后端
前端大白话17 分钟前
前端人必看!10个JavaScript“救命”技巧,让你告别加班改Bug
前端·javascript·程序员
cg501727 分钟前
Vue回调函数中的this
前端·javascript·vue.js
前端太佬29 分钟前
从零到一实现扫码登录:一个前端菜鸟的踩坑实录
前端·javascript·架构
yuanmenglxb200440 分钟前
微信小程序核心技术栈
前端·javascript·vue.js·笔记·微信小程序·小程序
爱编程的鱼40 分钟前
如何让 HTML 文件嵌入另一个 HTML 文件:详解与实践
前端·html
_09271 小时前
Vue 2 与 Vue 3 的核心区别及 Vue 3 新特性详解
前端
David凉宸1 小时前
一文带你使用Vue完成移动端(apk)项目
前端
会飞的鱼先生1 小时前
Vue3的内置组件 -实现过渡动画 TransitionGroup
前端·javascript·vue.js·vue