Ordem de precedência dos componentes do tema

Percebi que os componentes do tema parecem ser executados na ordem de instalação. Por exemplo, se eu instalar A e depois B, os scripts de A são incluídos nas páginas geradas antes dos de B.

Posso contar com isso? Existe alguma visualização que mostre essa ordem? Ao visualizar os componentes instalados, eles aparecem listados em ordem alfabética.

Preferiria uma maneira de executar ações explicitamente antes de um componente específico. No meu caso, quero executar ações antes do componente TOC (relacionado a este tópico). Pela documentação do Ember, parece que as funções agendadas para uma determinada fila são executadas na ordem em que foram agendadas. Isso torna a ordem de agendamento essencial no meu caso.

Isso não é algo em que você possa confiar; em vez disso, APIs adequadas devem controlar isso. Você pode usar inicializadores do Ember para controlar isso até certo ponto. @eviltrout pode ter algumas ideias específicas se você puder colar o código de exemplo que está tentando agendar.

Este é o código que estou executando:

<script type="text/discourse-plugin" version="0.8">
    const { run } = Ember;
    
    api.decorateCooked($elem => {
        run.scheduleOnce("actions", () => {
          // Deve ser executado antes das ações agendadas pelo componente TOC.
        });
    })

O componente TOC usa a mesma interface para agendar suas ações.

De acordo com a documentação do Ember, a interface de agendamento:

Adiciona o alvo/método passado e quaisquer argumentos opcionais à fila nomeada para ser executada no final do RunLoop

O termo “adiciona” sugere uma ordem FIFO das ações agendadas. Portanto, a ordem em que a chamada a schedule é feita é crítica aqui.

Percebi que, ao tentar reordenar a execução do JavaScript reinstalando e desinstalando o componente TOC (o que, aparentemente, tem o efeito colateral feliz de fazer o JavaScript do TOC ser executado por último), as regras de CSS agora são aplicadas nesta ordem :slight_smile:

Sinto que o tópico de ordenação para a colocação de código de componentes de tema é bastante importante. Se a ordem for oficialmente “indefinida”, não há como os componentes esperarem interagir.

Talvez a interação entre componentes não seja um objetivo. Mas acho que, com uma heurística de ordenação (por exemplo, declarar que um arquivo de componente ocorra antes ou depois do arquivo de outro componente com o mesmo nome — isso seria presumivelmente definido no about.json), esse problema não é tão difícil.

Do meu lado, estou começando a achar que fazer um fork do componente TOC é o caminho certo com base no que estou tentando fazer.

Sempre que você criar ou instalar um tema ou componente, o Discourse atribuirá um ID a ele. Se você visitar a página desse componente, deverá ver esse ID na URL (o número no final)

component id in the URL

Quando esse componente é adicionado ao seu tema, sua ordem de execução parece ser baseada no seu ID — em um nível muito básico (fazendo um console.log sem qualquer adiamento). Assim, o 233 será executado antes do 234, e assim por diante.

Isso funciona na maioria dos casos porque alterações subsequentes geralmente são adicionadas em novos componentes, então simplesmente funciona.

A longo prazo, poderíamos fazer com que a ordem respeite a lista de componentes que você adicionou ao tema

mas isso não está em nenhum roteiro no momento.

O que você realmente precisa é da ordem dos inicializadores. Não acho que seja possível fazer isso a menos que você mova seu código para o novo modo de criar JS de tema. Esse método permite que você dê um nome ao inicializador e defina a ordem de execução. Por exemplo, digamos que eu tenha este arquivo

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

e ele se pareça com isso

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

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

e eu tenha outro inicializador que se pareça com isso

/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")
    });
  }
}

Se eu quiser garantir que bar seja executado após foo, posso adicionar um argumento after: a ele, o que garantirá que ele seja executado após o nome do inicializador que eu passar ali. Então, para fazer bar ser executado após foo, eu faria isso em

/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");
    });
  }
};

Muito obrigado pelas orientações detalhadas! Considerando meus problemas relacionados ao componente TOC (aos quais você também respondeu — obrigado novamente), fiz um fork do TOC e movi o código dependente para dentro desse componente. Isso está relacionado aos IDs dos títulos — especificamente à necessidade de controlá-los a partir do post para lidar com duplicatas e colisões com IDs de elementos do núcleo.

Acho que, dado o que estou fazendo com a documentação, parte do qual é um pouco fora do comum, essa é a abordagem correta.