Порядок приоритета компонентов темы

Я заметил, что компоненты темы, по-видимому, выполняются в порядке установки. Например, если я установил A, а затем B, скрипты A включаются в сгенерированные страницы раньше, чем B.

Могу ли я на это рассчитывать? Есть ли где-то представление, показывающее этот порядок? При просмотре установленных компонентов они перечислены в алфавитном порядке.

Мне предпочтительнее иметь возможность явно запускать действия до определённого компонента. В моём случае я хочу запускать действия до компонента TOC (связано с этой темой). Согласно документации Ember, запланированные функции для данной очереди выполняются в порядке планирования. В моём случае порядок планирования имеет решающее значение.

На это полагаться нельзя; вместо этого этим должны управлять правильные API. Вы можете использовать инициализаторы Ember, чтобы контролировать это в некоторой степени. @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 здесь имеет решающее значение.

Я заметил, что при попытке изменить порядок выполнения JavaScript-кода путём переустановки и удаления компонента TOC (что, по-видимому, имеет счастливый побочный эффект — выполнение JavaScript-кода TOC в последнюю очередь) — CSS-правила теперь применяются именно в таком порядке :slight_smile:

Мне кажется, тема порядка размещения кода компонентов темы довольно важна. Если порядок официально «не определён», то компоненты не могут надеяться на взаимодействие.

Возможно, взаимодействие компонентов не является целью. Но я считаю, что с эвристикой определения порядка (например, объявить, что файл компонента должен находиться до или после файла другого компонента с тем же именем — это, вероятно, должно быть определено в about.json) эта проблема решается не так уж сложно.

Со своей стороны, я начинаю думать, что форк компонента TOC — это правильный путь, исходя из того, что я пытаюсь сделать.

Каждый раз при создании или установке темы или компонента Discourse присваивает ему уникальный идентификатор. Если вы перейдёте на страницу этого компонента, то увидите этот идентификатор в URL (число в конце).

component id in the URL

Когда компонент добавляется в вашу тему, порядок его выполнения, по-видимому, определяется его идентификатором — на очень базовом уровне (например, при выводе в консоль без отложенного выполнения). Таким образом, 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");
    });
  }
}

Если я хочу убедиться, что bar выполняется после foo, я могу добавить аргумент after: к нему. Это обеспечит выполнение после инициализатора с указанным именем. Таким образом, чтобы bar выполнялся после foo, я должен сделать следующее в файле

/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 (на которые вы тоже ответили — ещё раз спасибо), я сделал форк TOC и перенёс зависимый код в этот компонент. Это связано с идентификаторами заголовков: в частности, возникает необходимость управлять ими из поста, чтобы обрабатывать дубликаты и конфликты с идентификаторами основных элементов.

Учитывая то, что я делаю с документацией, часть из которой довольно нетрадиционна, я считаю, что это правильный подход.