创建一个新的插件以扩展 CLI#
虽然 JupyterLite 应用程序的大部分行为可以通过扩展进行配置或修改,但这可能无法满足所有需求。也可以通过_插件_来扩展底层的jupyter lite CLI。
自定义_插件_可以对已构建的 lite 应用程序的_输出文件夹_执行任何操作,以及修改其他_插件_(包括构成核心 API 的插件)的行为。
一些用例
- 发布复杂的前端扩展 
- 可预测地修补已构建应用程序中的文件 
- 代码检查、测试、压缩或其他验证和优化技术 
注意
选择_插件_是为了将这些组件与浏览器端的_插件_和前端的_扩展_区分开来,并且所有jupyter lite核心行为都作为_插件_实现。
CLI 架构#
在深入构建插件之前,值得了解它们在 CLI 整体结构中的位置。
为了从多个源下载、解压和更新静态文件和配置,CLI 使用了多层。
| 组件 | 示例 | 作用 | 
|---|---|---|
| 应用 | 加载配置并解析 CLI 参数 | |
| 管理器 | 加载插件,运行 | |
| 插件 | 生成任务计划并实现操作 | |
| 
 | 收集逻辑生命周期任务 | |
| 
 | 任务的细粒度排序 | |
| 
 | 具有任务和文件依赖关系的一组操作 | |
| Action | 
 | 实际移动和更新文件 | 
插件的结构#
最简单的插件以以下签名初始化
class MyAddon:
    __all__ = ["status"]
    def status(self, manager):
        yield dict(name="hello", actions=[lambda: print("world")])
- __all__成员列出了插件实现的_钩子_- 钩子也可以带有 - pre_和- post__阶段_前缀
 
- 如所宣传的钩子实现 
值得注意的是
- status阶段不应有副作用
- init阶段主要保留给“黄金版”内容
- build主要保留给用户创作内容
提示
请参阅此 JupyterLite 仓库中的现有示例,了解其他钩子实现。
生成任务#
每个钩子实现都应返回一个可迭代的doit 任务,其最小形式为
def post_build(manager):
    yield dict(
        name="a:unique:name", # will have the Addon, and maybe a prefix, prepended
        actions=[["things", "to", "do"]],
        file_dep=["a-file", Path("another-file")],
        targets=["an-output-file"],
    )
App 级别的任务已经根据它们的钩子父级配置了doit.create_after,这意味着任务可以_自信地_依赖其父级(由任何其他插件)已经存在的文件。
虽然不是_必需的_,但拥有准确的file_dep和targets有助于确保已构建的应用程序始终处于一致状态,_而无需_大量返工。
BaseAddon#
一个便捷类,jupyterlite_core.addons.base.BaseAddon可以扩展以提供许多有用的功能。它扩展了traitlets.LoggingConfigurable,并将LiteManager设为_插件_的parent,从而允许它通过jupyter_lite_config.json按名称配置
{
  "LiteBuildConfig": {
    "ignore_sys_prefix": true
  },
  "MyAddon": {
    "enable_some_feature": true
  }
}
…或通过命令行。
jupyter lite build --MyAddon.enable_some_feature=True
短 CLI#
继承自BaseAddon(或以其他方式继承自traitlets.Configurable)的_插件_可以告知父应用程序它公开了额外的 CLI _别名_和_标志_,用于执行以及使用--help查询时。
提示
鼓励_插件_作者使用共同前缀对他们的别名和标志进行分组。
别名#
_别名_将 CLI 参数映射到单个特性。
from traitlets import Int
class MyFooAddon(BaseAddon):
    __all__ = ["status"]
    aliases = {
      "how-many-foos": "MyFooAddon.foo",
    }
    foo = Int(0, help="The number of foos").tag(config=True)
    # ...
警告
_插件_不得重载核心别名或先前加载的插件的别名。
标志#
_标志_将 CLI 参数映射到任意数量的traitlets.Configurable类上的任意数量的特性
from traitlets import Int, Bool
class MyFooBarAddon(BaseAddon):
    __all__ = ["status"]
    flags = {
      "foo-bar": (
        {"MyFooBarAddon": {"foo": 1, "bar": True}},
        "Foo once, and bar",
      )
    }
    foo = Int(0, help="The number of foos").tag(config=True)
    bar = Bar(False, help="Whether to bar").tag(config=True)
    # ...
注意
_插件_可以增强现有标志的行为,但不得覆盖先前注册的配置值。帮助文本将附加换行符。
打包#
_插件_通过entry_points进行广告,例如在pyproject.toml中
[project.entry-points."jupyterlite.addon.v0"]
my-unique-addon = "my_module:MyAddon"
一般指南#
- 值得研究 - BaseAddon及其子类如何处理某些任务
- 记住可重现性,尽可能多地缓存,并利用 - file_deps、- targets和- uptodate来保持构建速度