云计算百科
云计算领域专业知识百科平台

Dart SDK 分析服务器插件包结构全解析:Target、Host、Bootstrap 与 Plugin 四包模型

  • 编程语言
  • 编译器
  • 语言运行时
  • 标准库
  • 开发工具

【免费下载链接】sdk

The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.

项目地址:
https://gitcode.com/gh_mirrors/sdk1/sdk

点击查看 免费下载

导读

Dart SDK 分析服务器插件(analyzer plugin) 是扩展 dart analyze、编辑器诊断、代码补全与重构能力的关键机制:工具(tool)通过运行插件来接收外部贡献的分析结果。本文以官方教程 Package Structure 为核心骨架,结合仓库内 pkg/analyzer_plugin 的真实源码实现,系统拆解插件的四包模型(target / host / bootstrap / plugin)、发现与加载流程、bootstrap 包的强制结构以及插件的隔离执行机制。读完本文,你将能正确设计一个分析服务器插件的目录布局,并理解插件是如何被工具自动发现、启动与通信的。

一、插件机制与“工具”的抽象

插件被用于允许外部贡献参与到工具产生的分析结果中。目前,分析服务器(analysis server)是唯一支持插件的工具,但 Dart 团队计划将插件支持扩展到命令行分析器(command-line analyzer)乃至其他工具。因此,官方文档统一将运行插件的工具泛称为 the tool。

插件用 Dart 编写,与分析服务器运行在同一个 VM 中,但每个插件运行在独立的 isolate 中(参见 introduction.md)。工具与插件之间通过一组基于请求/响应/通知的线协议通信,这部分协议在 pkg/analyzer_plugin/doc/api.html 中定义。

二、四包模型:一次说清四个角色的职责

为了描述工具如何使用插件,官方文档引入了四个相互区分的包。理解这四个概念是设计插件架构的第一步。

包名角色定位关键特征
target package 目标包 工具正在为其产生分析结果的包;若工具是分析服务器,即用户在客户端打开并正在开发的包
host package 宿主包 包含定位与运行插件所需信息的包,其中内嵌 bootstrap 包;target 包需依赖它(普通依赖或 dev 依赖均可)
bootstrap package 引导包 内嵌于宿主包中的小型包,用于加载 plugin 包
plugin package 插件包 包含插件实际实现的包

若对 Dart 包(package)概念不熟悉,建议先了解 Dart 的包管理器 pub 的工作方式。

值得强调的是依赖方向:target 包必须声明对 host 包的依赖(普通依赖或 dev 依赖皆可),工具才能据此发现 host 包、进而定位并运行其中内嵌的 bootstrap 包。

三、官方推荐的结构:为什么 bootstrap 与 plugin 分开

从技术上来说,你可以把 bootstrap 包与 plugin 包合并成一个包。但官方文档明确推荐保持两者分离,理由非常实际:

对于没有选择启用该托管插件的用户而言,分离结构能最小化需要额外下载的文件数量。

也就是说,用户可能只是普通依赖了 host 包(例如某个框架包),而并不想启用它的插件功能。若 bootstrap 与 plugin 合并,那么插件实现的大量文件也会被一并拉取;分开存放则可以让“不启用插件”的用户只下载 bootstrap 这个轻量壳。

典型案例:angular 包

文档给出的真实案例是 angular 包。angular 包自身内嵌了一个 bootstrap 包;当一个实现 Web 应用的 target 包依赖 angular 包时,只需在分析选项中将 angular 列为 approved host package(受批准的宿主包),angular 插件就会被运行。

四、插件发现:analysis_options.yaml 中的 approved host 列表

工具只有在被明确告知的情况下才会运行插件来分析 target 包。发现机制分两步:

  • 工具在 target 包关联的 analysis_options.yaml 中查找受批准的宿主包列表,其形式为:
  • analyzer:
    plugins:
    – host_package_1
    – host_package_2

  • 若列出的宿主包可以通过 target 包关联的 .packages 文件解析到,工具便在宿主包中查找 <host_package>/tools/analyzer_plugin 目录;若该目录存在且包含有效的 bootstrap 包,则 bootstrap 包会被作为插件运行。
  • 因此,从配置到生效的完整链路是:analysis_options.yaml 白名单 → .packages 解析宿主包 → 宿主包内 tools/analyzer_plugin 目录 → bootstrap 包启动 → plugin 包加载。在源码层面,这一“插件被运行”的落点是 pkg/analyzer_plugin/lib/src/driver.dart 中的 Driver 类,它代表一个正在运行的插件实例,负责与服务器的通信并将请求转发给插件。

    五、Bootstrap 包的强制结构

    前面三个包(target、host、plugin)都可以是任意合法的 Dart 包结构,唯独 bootstrap 包必须包含两个特定文件:

    1. tools/analyzer_plugin/pubspec.yaml

    该文件供 pub 命令生成 .packages 文件,用于解析 bootstrap 包内出现的 package: URI。典型情况下,它只需声明对 plugin 包的一个依赖即可,例如:

    name: my_plugin_bootstrap
    environment:
    sdk: '>=3.0.0 <4.0.0'
    dependencies:
    my_plugin:
    path: ../my_plugin

    注意:虽然从技术上讲依赖可以任意,但官方强调“通常唯一需要的依赖就是对 plugin 包的依赖”,这保证了 bootstrap 包的轻量性。

    2. tools/analyzer_plugin/bin/plugin.dart

    这是插件的入口点。由于每个插件都运行在独立 isolate 中,入口函数必须具备如下签名:

    void main(List<String> args, SendPort sendPort) {
    // Invoke the real main method in the plugin package.
    }

    main 的函数体通常只有一行:调用 plugin 包中负责创建并启动插件的函数。例如,借助 analyzer_plugin 包提供的 ServerPluginStarter(见 starter.dart):

    import 'dart:isolate';
    import 'package:analyzer_plugin/starter.dart';
    import 'package:my_plugin/my_plugin.dart';

    void main(List<String> args, SendPort sendPort) {
    ServerPluginStarter(MyPlugin()).start(sendPort);
    }

    ServerPluginStarter 的工厂构造会创建 Driver 实例;Driver.start(SendPort) 内部通过 PluginIsolateChannel(sendPort) 建立与服务器的通信通道,并调用插件实例的 start(channel) 开始监听请求(见 channel.dart 与 plugin.dart 中的 ServerPlugin.start)。入口点收到 SendPort、建立通道并启动插件,这正是 main 签名中 SendPort 参数的用途。

    六、插件执行:临时目录、pub 解析与独立 isolate

    当一个 bootstrap 包被决定运行时,工具的加载流程如下:

  • 将包含 bootstrap 包的目录内容复制到一个临时目录;
  • 在该临时目录中运行 pub 命令,为 bootstrap 包生成 .packages 文件;
  • 在自己的 isolate 中运行 tools/analyzer_plugin/bin/plugin.dart。
  • 采用“复制到临时目录再运行 pub”的方式,是为了保证 bootstrap 包的分析与依赖解析独立、干净,不污染宿主包或 target 包的环境;而“独立 isolate 运行”保证了插件之间、插件与服务器之间互不阻塞。服务器通过 plugin.versionCheck 请求验证插件与服务器的 API 版本兼容性,通过 plugin.shutdown 请求在关闭时通知插件释放资源(详见 introduction.md)。

    七、落地实践:从包结构到最小插件

    推荐的仓库布局

    综合四包模型与 bootstrap 强制结构,一个典型的插件项目目录如下:

    my_plugin/ # plugin package:插件实现
    lib/
    my_plugin.dart # 定义 ServerPlugin 子类
    pubspec.yaml

    my_host/ # host package:宿主包,内嵌 bootstrap
    lib/
    my_host.dart
    tools/
    analyzer_plugin/ # bootstrap package
    bin/
    plugin.dart # 入口点:void main(List<String>, SendPort)
    pubspec.yaml # 声明对 my_plugin 的依赖
    pubspec.yaml

    consumer_app/ # target package:被分析的包
    analysis_options.yaml # analyzer.plugins 白名单
    .packages # 解析 host 包依赖
    pubspec.yaml # 依赖 my_host

    最小插件的核心类

    plugin 包中的插件实现类继承 ServerPlugin(源码见 plugin.dart)。一个最小实现需要提供构造器、三个 getter(name、version、fileGlobsToAnalyze)以及两个方法(createAnalysisDriver、sendNotificationsForSubscriptions),参见教程 Getting Started 中的示例骨架:

    class MyPlugin extends ServerPlugin {
    MyPlugin(ResourceProvider provider) : super(provider);

    @override
    List<String> get fileGlobsToAnalyze => <String>['**/*.dart'];

    @override
    String get name => 'My fantastic plugin';

    @override
    String get version => '1.0.0';

    @override
    AnalysisDriverGeneric createAnalysisDriver(ContextRoot contextRoot) {
    // TODO: implement createAnalysisDriver
    return null;
    }

    @override
    void sendNotificationsForSubscriptions(
    Map<String, List<AnalysisService>> subscriptions) {
    // TODO: implement sendNotificationsForSubscriptions
    }
    }

    其中 name 与 version 会在遇到问题时出现在错误信息中,fileGlobsToAnalyze 声明插件关心的文件 glob 模式。从源码可以看出(plugin.dart),ServerPlugin 内部通过 OverlayResourceProvider 访问文件系统、用 SubscriptionManager 管理订阅、并统一在 _getResponse 中分发 analysis.*、completion.*、edit.* 与 plugin.* 等请求——这些正是插件与服务器通信协议的服务端实现。

    八、继续深入

    本主题在官方教程中属于系列文章的一环。若想继续实现具体功能,可依次阅读同目录下的其余章节(均位于 pkg/analyzer_plugin/doc/tutorial/):

    • Creating Edits:组装 assists、fixes 与 refactorings 所需的编辑操作
    • Providing Quick Assists 与 Providing Quick Fixes:上下文相关的代码操作
    • Providing Code Completions:代码补全建议
    • Providing Navigation Information、Providing Occurrences Information、Providing Outline Information、Providing Folding Information:编辑器导航、标记、大纲与折叠支持
    • Debugging Plugins:通过状态页、instrumentation log 与 DevTools 排查插件问题

    插件的完整通信协议定义与分析能力封装,可在 pkg/analyzer_plugin/lib 的 plugin/、protocol/、channel/ 与 utilities/ 子目录中进一步研读;pkg/analyzer_plugin/test/plugin/ 下各 mixin 测试(如 assist_mixin_test.dart、completion_mixin_test.dart)则提供了各功能接口的调用与验证示例,可作为实现参考。

    赞

    分享

    • 编程语言
    • 编译器
    • 语言运行时
    • 标准库
    • 开发工具

    【免费下载链接】sdk

    The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.

    项目地址:
    https://gitcode.com/gh_mirrors/sdk1/sdk

    点击查看 免费下载

    上一篇:
    Pitaya RPC系统揭秘:Sys RPC与User RPC的区别与应用场景

    下一篇:
    EBAZ4205网络功能实战:10/100M以太网PHY配置与性能测试

    创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » Dart SDK 分析服务器插件包结构全解析:Target、Host、Bootstrap 与 Plugin 四包模型
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!