- 前端
【免费下载链接】bloc
A predictable state management library that helps implement the BLoC design pattern
Zed 是当前广受关注的现代代码编辑器,而 Bloc 是 Dart / Flutter 生态中极具代表性的可预测状态管理库。本指南围绕官方仓库中的 extensions/zed 扩展,系统讲解如何在 Zed 中安装 Bloc 扩展、使用其 30+ 个代码片段加速 Bloc、Cubit、bloc_test 与测试替身的编写,并深入剖析内建的 Bloc 语言服务器(基于bloc_tools)的自动下载、诊断上报与 lint 规则联动机制。读完本文,你将能在 Zed 中完整复现与 VSCode/IntelliJ 插件同级的 Bloc 开发体验。
扩展能力总览
extensions/zed 是 Bloc 官方为 Zed 编辑器提供的扩展,它提供两方面的能力:
- 代码片段(Snippets):覆盖 Bloc、Cubit、Flutter 组件(Provider/Builder/Listener 等)、测试(blocTest、Mock 系列)以及 Freezed 状态/事件定义的快捷展开。
- Bloc 语言服务器(Language Server):基于
bloc_tools二进制实现,为 Dart/Flutter 项目提供针对 bloc 相关 lint 规则的诊断信息,将bloc_lint的检查结果实时呈现在编辑器中。
从扩展清单文件 extension.toml 可以看到,扩展的元数据如下:
id = "bloc" name = "Bloc" description = "Support for the Bloc state management library for Dart and Flutter. Provides snippets and the Bloc language server." version = "0.1.0" schema_version = 1 authors = ["Felix Angelov <felangelov@gmail.com>", "Johannes Naylor <me@jonaylor.com>"] snippets = ["snippets/dart.json"] [language_servers.bloc] name = "Bloc Language Server" languages = ["Dart"]它声明了两个关键事实:片段文件位于 snippets/dart.json,且语言服务器仅针对 Dart 语言启用。当前仓库中该扩展为0.1.0初始版本(见 CHANGELOG.md,"initial extension release, includes snippets and language server")。
安装方式
官方 README 提供了两种安装途径:
方式一:从 Zed 扩展面板安装(推荐)
打开 Zed,在 Extensions 面板中搜索Bloc,点击 Install 即可。这是大多数用户日常使用的方式。
方式二:作为本地开发扩展(dev extension)安装
适合需要调试扩展本身或使用仓库内未发布版本的开发者:
- 打开 Zed;
- 打开命令面板(Command Palette),运行
zed: install dev extension; - 在弹出的目录选择器中,选中本仓库的
extensions/zed目录。
安装完成后,编辑.dart文件时即可自动获得片段补全与语言服务器诊断能力。
语言服务器:自动下载与配置
Zed 扩展本身并不打包语言服务器二进制,而是在首次使用时从 GitHub Releases 自动下载bloc_tools可执行文件。这一逻辑完整实现于 lib.rs,其下载流程如下:
- 优先读取用户为
bloc语言服务器配置的自定义二进制路径(通过 Zed 的lsp配置中bloc.binary.path指定),若有则直接使用; - 否则检查本地缓存路径中是否已存在可用的
bloc_tools二进制; - 向用户展示 "CheckingForUpdate" 安装状态,调用 GitHub Release API 拉取固定 tag 为
bloc_tools-v0.1.0-dev.22的发布资源(对应源码中的BLOC_TOOLS_RELEASE_TAG常量); - 根据当前平台与架构拼接资源名
bloc_{os}_{arch},映射关系为:macOS→macos、Linux→linux、Windows→windows,架构上 AArch64→arm64、x86_64 与 x86→x64; - 若本地不存在对应版本目录(形如
bloc_tools-<version>),则显示 "Downloading" 状态、下载二进制、赋予可执行权限,并清理旧的bloc_tools-*版本目录; - 缓存二进制路径,供后续会话复用。
语言服务器启动命令也由 lib.rs 决定:默认以language-server作为参数调用bloc_tools二进制,同时支持通过 Zed 的lsp配置覆盖二进制路径与参数。
从 command_runner.dart 可以看出,bloc_tools是一个多命令 CLI(bloc),除language-server(隐藏命令)外还包含new与lint命令。其中language-server命令(见 language_server_command.dart)会启动真正的 LSP 服务;lint命令(见 lint_command.dart)则用于在终端中直接对指定文件执行 lint 并打印格式化的诊断结果(错误/警告/提示各有不同的着色与-->行号指引)。
语言服务器如何产生诊断
语言服务器的核心实现在 language_server.dart,它通过语言服务器协议(LSP)与 Zed 通信:
- 在
initialize阶段,向编辑器声明支持增量文本同步(TextDocumentSyncKind.Incremental); - 在
initialized阶段,对工作区根目录(rootUri)执行一次全量诊断; - 在
didChangeContent阶段,对发生变化的文档执行增量诊断——这正是输入时实时出现 lint 提示的来源; - 在
didSave阶段,若保存的是analysis_options.yaml,会对其所在目录重新触发诊断,从而让 lint 规则配置的改动即时生效。
每个诊断条目都会被转换为标准 LSPDiagnostic(包含消息、规则 code、source、severity、行区间以及指向规则文档的codeDescription),Zed 会将其渲染为编辑器内的问题提示,并支持通过 code 跳转到规则说明。
支持的 lint 规则
语言服务器复用的是bloc_lint包的规则集。从 rules 目录 可以看到当前内置的规则实现,包括:
avoid_build_context_extensions/prefer_build_context_extensions:控制是否应避免或优先使用BuildContext扩展;avoid_flutter_imports:避免在 Dart 侧直接导入 Flutter;avoid_public_bloc_methods/avoid_public_fields:约束 Bloc 类的公开方法与字段;prefer_bloc/prefer_cubit:在可选用 Cubit/Bloc 的场景给出偏好建议;prefer_file_naming_conventions:校验文件命名约定;prefer_void_public_cubit_methods:建议公开的 Cubit 方法返回void。
规则的启用/禁用遵循与bloc_lint一致的配置方式(在analysis_options.yaml中配置),完整规则与配置细节可参考官方 lint 文档。你可以通过bloc lint [files]...在终端手动验证诊断结果,例如:
bloc lint lib/main.dart该命令会逐个文件分析并输出诊断汇总,无问题时返回退出码 0,发现问题返回 1(详见 lint_command.dart)。
代码片段(Snippets)
片段定义文件为 snippets/dart.json,所有片段支持 Tab 键跳转占位符(${1:Subject}、${0}等)。下面按 README 中的分类逐一说明。
Bloc 核心片段
| 快捷前缀 | 作用 | 展开内容要点 |
|---|---|---|
importbloc | 导入package:bloc | import 'package:bloc/bloc.dart'; |
importflutterbloc | 导入package:flutter_bloc | import 'package:flutter_bloc/flutter_bloc.dart'; |
importbloctest | 导入package:bloc_test | import 'package:bloc_test/bloc_test.dart'; |
bloc | 创建 Bloc 类 | 生成class XBloc extends Bloc<XEvent, XState>骨架,含构造函数super(XInitial())与on<XEvent>((event, emit) {...}) |
cubit | 创建 Cubit 类 | 生成class XCubit extends Cubit<XState>,构造函数super(XInitial()) |
onevent | 注册新的EventHandler | 生成on<XEvent>((event, emit) {...}); |
_onevent | 定义独立的EventHandler方法 | 生成void _onX(XEvent event, Emitter<XState> emit) {...}方法骨架 |
blocobserver | 创建BlocObserver类 | 完整覆盖onEvent、onError、onChange、onTransition四个钩子 |
blocstate | 创建状态类 | 生成class SubjectVerbState extends SubjectState,含const构造与props重写 |
blocevent | 创建事件类 | 生成class SubjectNounVerb extends SubjectEvent,含const构造与props重写 |
以bloc片段为例,实际展开的模板为:
class ${1:Subject}Bloc extends Bloc<$1Event, $1State> { ${1:Subject}Bloc() : super(${1:Subject}Initial()) { on<$1Event>((event, emit) { $0 }); } }其中$1会在 Tab 跳转时同步替换所有引用位置;blocstate与blocevent生成的props重写默认与equatable包协同使用,方便进行状态相等性比较。
Flutter 组件片段
| 快捷前缀 | 作用 | 展开内容要点 |
|---|---|---|
blocprovider | 创建BlocProvider | BlocProvider(create: (context) => XBloc(), child: ...) |
multiblocprovider | 创建MultiBlocProvider | 预置两个BlocProvider槽位的providers:列表 |
repoprovider | 创建RepositoryProvider | RepositoryProvider(create: (context) => XRepository(), ...) |
multirepoprovider | 创建MultiRepositoryProvider | 预置两个RepositoryProvider槽位 |
blocbuilder | 创建BlocBuilder | BlocBuilder<XBloc, XState>(builder: (context, state) {...}) |
blocselector | 创建BlocSelector | 含selector:与builder:两个回调槽位 |
bloclistener | 创建BlocListener | 含listener:回调与child:槽位 |
multibloclistener | 创建MultiBlocListener | 预置listeners:列表 |
blocconsumer | 创建BlocConsumer | 同时含listener:与builder: |
blocof | BlocProvider.of()快捷写法 | BlocProvider.of<XBloc>(context) |
repoof | RepositoryProvider.of()快捷写法 | RepositoryProvider.of<XRepository>(context) |
read | context.read()快捷写法 | context.read<XBloc>() |
watch | context.watch()快捷写法 | context.watch<XBloc>() |
select | context.select()快捷写法 | context.select((XBloc bloc) => ...) |
这些组件均来自flutter_bloc包,模板中的create、builder、listener、child等槽位与真实 Widget 构造签名一一对应,可直接使用;read/watch/select则对应BuildContext上的扩展方法,是 Flutter Bloc 8+ 时代推荐的三件套写法。
测试片段
| 快捷前缀 | 作用 | 展开内容要点 |
|---|---|---|
bloctest | 创建blocTest | 生成带测试描述、build:、act:、expect:的完整测试用例 |
mockbloc | 创建公开MockBloc子类 | class MockXBloc extends MockBloc<XEvent, XState> implements XBloc {} |
_mockbloc | 创建私有MockBloc子类 | 同上,类名前加下划线 |
mockcubit | 创建公开MockCubit子类 | class MockXCubit extends MockCubit<XState> implements XCubit {} |
_mockcubit | 创建私有MockCubit子类 | 同上,类名前加下划线 |
fake | 创建公开Fake子类 | class FakeX extends Fake implements X {} |
_fake | 创建私有Fake子类 | 同上,类名前加下划线 |
mock | 创建公开Mock子类 | class MockX extends Mock implements X {} |
_mock | 创建私有Mock子类 | 同上,类名前加下划线 |
以bloctest为例,展开模板为:
blocTest<${1:Subject}${2:Bloc}, $1State>( 'emits [${3:MyState}] when ${4:MyEvent} is added.', build: () => $1$2(), act: (bloc) => bloc.add($4()), expect: () => const <$1State>[$3()], );其中MockBloc、MockCubit、Mock、Fake均来自mocktail包,配合bloc_test的blocTest可以写出无 mockito 代码生成的纯 Dart 测试,这也是bloc_test官方推荐的做法。
Freezed 片段
| 快捷前缀 | 作用 | 展开内容要点 |
|---|---|---|
fstate | 创建 Freezed 状态 | const factory ClassName.stateName(...) = _StateName; |
fevent | 创建 Freezed 事件 | const factory ClassName.eventName(...) = _EventName; |
这两个片段用于在使用freezed生成不可变数据类时快速书写状态/事件的工厂构造,例如:
const factory CounterState.loading() = _CounterLoading;与其它编辑器扩展的协同
Zed 扩展与仓库中另外两个官方编辑器扩展定位互补:VSCode 扩展(extensions/vscode)除片段外还提供"New Bloc"、"Wrap with BlocBuilder" 等代码动作与命令;IntelliJ 插件(extensions/intellij)则基于 Kotlin 实现生成器与意图动作。而 Zed 扩展的独特价值在于:它以极轻量的方式内置了语言服务器,让bloc_lint的诊断能力原生融入编辑体验,无需像在其它编辑器中那样依赖单独的 lint 插件或终端命令。
常见问题与排查
- 语言服务器迟迟未启动:首次使用需要联网从 GitHub Releases 下载
bloc_tools(固定 tag 为bloc_tools-v0.1.0-dev.22),请确认网络可访问该发布源;若企业内网受限,可通过 Zedlsp配置中的bloc.binary.path指向手动放置的二进制。 - 诊断未随输入实时更新:确认项目根目录存在
analysis_options.yaml且正确启用了 bloc_lint 相关规则;保存analysis_options.yaml后语言服务器会自动对所在目录重新诊断。 - 片段未生效:确认当前文件语言为 Dart,且扩展已成功安装;扩展片段仅注册于 Dart 语言(见 extension.toml 中的
languages = ["Dart"])。 - 如何验证语言服务器版本:在终端执行
bloc --version可查看当前bloc_tools版本,bloc --help可查看全部子命令(见 bloc_tools.dart)。
总结
Bloc 官方 Zed 扩展以一份轻量清单(extension.toml)把"片段补全 + 语言服务器诊断"两项能力打包进 Zed,其代码片段覆盖从Bloc/Cubit类、Flutter Provider/Builder 组件到blocTest与 Mock 替身的全链路日常开发;语言服务器则通过自动下载bloc_tools二进制并与bloc_lint规则引擎联动,把 lint 诊断实时带入编辑器。对于在 Zed 中开发 Dart/Flutter 并采用 Bloc 状态管理方案的用户,这套扩展是开箱即用、与官方工具链深度集成的推荐选择。
- 前端
【免费下载链接】bloc
A predictable state management library that helps implement the BLoC design pattern
相关推荐
Zed 扩展开发指南:用 extension.toml 注册多语言代码片段(Snippets)
Zed 扩展开发指南:用 extension.toml 注册多语言代码片段(Snippets) Zed 的扩展机制不只限于语言、语法树与主题,开发者还可以让扩展
开发工具代码编辑器桌面应用CQEngine终极指南:5个技巧掌握Java内存数据库查询优化
CQEngine终极指南:5个技巧掌握Java内存数据库查询优化 想象一下,你正在处理一个包含数百万条记录的Java集合,每次查询都需要遍历整个数据集,性能瓶颈
多语言代码片段的扩展与贡献指南
多语言代码片段的扩展与贡献指南 本文详细介绍了30 seconds of code项目中Python、CSS和React等多个语言的技术特色与最佳实践,包括Py
教程文档
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考