主题组件的优先级顺序

我注意到主题组件似乎是按照安装顺序执行的。例如,如果我先安装 A 再安装 B,那么在生成的页面中,A 的脚本会排在 B 之前。

这一点是否可以依赖?是否有某个视图可以显示这个顺序?在查看已安装的组件时,它们似乎是按字母顺序列出的。

我更希望能有一种方式,明确地在某个特定组件之前执行操作。在我的情况下,我想在 TOC 组件之前执行操作(相关讨论见 此话题)。根据 Ember 文档,针对某个队列调度的函数会按照调度顺序执行。因此,在我的场景中,调度顺序至关重要。

这个不能依赖,应该由适当的 API 来控制。你可以使用 Ember 的初始化工具(initializers)在一定程度上进行控制。如果你能粘贴出你尝试调度的示例代码,@eviltrout 可能会有一些具体的建议。

这是我正在运行的代码:

<script type="text/discourse-plugin" version="0.8">
    const { run } = Ember;
    
    api.decorateCooked($elem => {
        run.scheduleOnce("actions", () => {
          // 必须在 TOC 组件的调度操作之前运行。
        });
    })

TOC 组件使用相同的接口来调度其操作

根据 Ember 文档,schedule 接口:

将传入的目标/方法以及任何可选参数添加到指定队列中,以便在 RunLoop 结束时执行

术语“添加”暗示了调度操作的 FIFO(先进先出)顺序。因此,此处对 schedule 的调用顺序至关重要。

我注意到,在我尝试通过重新安装和卸载 TOC 组件来调整 JavaScript 执行顺序时(这似乎碰巧使得 TOC JavaScript 最后运行),CSS 规则现在按照以下顺序应用了::slight_smile:

我觉得主题组件代码放置的顺序问题相当重要。如果官方规定顺序为“未定义”,那么组件之间就无法指望进行交互。

也许组件交互并非目标。但我认为,如果采用某种排序启发式方法(例如,声明一个组件文件出现在另一个同名组件文件之前或之后——这可以在 about.json 中定义),这个问题就不算太难解决。

就我个人而言,基于我目前的目标,我开始认为分叉 TOC 组件是正确的做法。

每次创建或安装主题或组件时,Discourse 都会为其分配一个 ID。如果您访问该组件的页面,应该可以在 URL 中看到该 ID(末尾的数字)。

URL 中的组件 ID

当该组件被添加到您的主题中时,其执行顺序似乎是基于其 ID 的——在最基本的层面上(在不进行任何延迟的情况下执行 console.log)。因此,233 会在 234 之前运行,依此类推。

这在大多数情况下都能正常工作,因为后续的更改通常会被添加到新组件中,因此一切正常。

从长远来看,我们可以让执行顺序遵循您在主题中添加的组件列表的顺序。

但目前这并不在任何路线图之中。

您真正需要的是初始化器的顺序。我认为,除非您将代码迁移到创建主题 JavaScript 的新方法,否则无法实现这一点。该方法允许您为初始化器指定名称和执行顺序。例如,假设我有这样一个文件:

/javascripts/discourse/initializers/initialize-for-foo.js

内容如下:

import { withPluginApi } from "discourse/lib/plugin-api";

export default {
  name: "foo",
  initialize() {
    withPluginApi("0.8.7", api => {
      console.log("foo")
    });
  }
}

我还有另一个初始化器,内容如下:

/javascripts/discourse/initializers/initialize-for-bar.js

import { withPluginApi } from "discourse/lib/plugin-api";

export default {
  name: "bar",
  initialize() {
    withPluginApi("0.8.7", api => {
      console.log("bar")
    });
  }
}

如果我希望确保 barfoo 之后运行,我可以为其添加一个 after: 参数,这将确保它在所传递的初始化器名称之后运行。因此,要让 barfoo 之后运行,我会在以下文件中这样做:

/javascripts/discourse/initializers/initialize-for-bar.js

import { withPluginApi } from "discourse/lib/plugin-api";

export default {
  name: "bar",
+ after: "foo",
  initialize() {
    withPluginApi("0.8.7", api => {
      console.log("bar");
    });
  }
};

非常感谢这些详细的建议!鉴于我与 TOC 组件相关的其他问题(您也回复了,再次感谢),我已经 fork 了 TOC 并将依赖代码移到了该组件中。这与标题 ID 有关——特别是需要从帖子层面控制 ID,以处理重复项以及与核心元素 ID 的冲突。

考虑到我正在进行的文档工作,其中部分内容有些非传统,我认为这是正确的做法。