api.modifyClass иногда (!) не работает

Edit: переклассифицировано как ошибка.
Полное воспроизведение ниже.

Я использую api.modifyClass в компоненте темы.

На большинстве страниц это работает нормально, но в некоторых темах свойство не добавляется к модели пользователя при перезагрузке страницы. Я не могу понять, почему это работает на большинстве тем, но не работает на некоторых, или что общего у тем, где это не работает.

Понимает ли кто-нибудь, что я делаю не так здесь?

TL;DR Добавление api.container.lookup для модели ниже modifyClass обходит эту проблему.

1 лайк

Ого, кажется, я знаю!

Думаю, вам нужно добавить pluginId:

<script type="text/discourse-plugin" version="0.1">
  api.modifyClass('model:user', {
    pluginId: 'my-plugin',
    testProperty: function() {
      return 1;
    }
  });
</script>

В более новых версиях это обязательно. Вчера я даже отправил несколько PR для тем, чтобы добавить это поле. Похоже, я наконец-то становлюсь разработчиком плагинов и тем.

2 лайка

Спасибо, Джей! Это действительно помогло на моём тестовом экземпляре.
Но, к сожалению, это не универсальное решение — проблема всё ещё сохраняется :frowning:

1 лайк

Да, pluginId, я полагаю, нужен для предотвращения повторного применения модификаций. Отсутствие этого параметра не должно объяснять, почему модификация вообще не была выполнена ни разу?

1 лайк

Черт. Только что думал, что я что-то понимаю. :crying_cat_face:

Мне казалось, что если что-то ещё изменяет класс, то это может быть гонка, чтобы увидеть, кто это сделал. Но JavaScript для меня всё ещё в основном загадка.

2 лайка

Это всё ещё проблема в коде, поэтому её стоит поднять.

1 лайк

Да, это тоже пришло мне в голову. Но это всё равно не работает на тестовом сайте, где это единственный компонент темы.

1 лайк

Из любопытства, если вы добавите это в компонент темы, например:

  • /javascripts/discourse/initializers/test-init.js.es6

изменится ли или улучшится ли поведение?

Не уверен, семантически ли эти вещи идентичны…

… теоретически оба варианта должны оцениваться при обновлении браузера, после чего гонка условий на переходе маршрута становится неактуальной, так как модификация уже должна быть применена…

1 лайк

Нет, поведение осталось прежним.

Я создал компонент темы с файлом javascripts/discourse-test/initializers/initialize-discourse-test.js.es6:

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

export default {
  name: 'discourse-test-initializer',
  initialize(){
    console.log('here1');
    withPluginApi("0.1", api => {
      console.log('here2');

      api.modifyClass('model:user', {
        pluginId: 'test',
        testFunction: function() {
          console.log('here3');
          return 2;
        }
      });

    });
  }
}

На каждой странице выводится:

here1
here2

В некоторых темах выполнение Discourse.currentUser.testFunction() в консоли работает и выводит here3 и 2.

В других темах это не работает (Uncaught TypeError: Discourse.currentUser.testFunction is not a function).

2 лайка

Хорошо, я получил уведомление от полезного поста, который, похоже, был удалён в это время.
Предложение не сработало, но в нём содержался намёк, который помог мне решить эту проблему.

Добавление следующего фрагмента ниже неработающего кода последовательно устраняло проблемы, с которыми я сталкивался. Я протестировал это на нескольких независимых форумах, как на стабильной версии, так и на версии с тестами. Думаю, это должно быть переклассифицировано как #баг

<script type="text/discourse-plugin" version="0.1">
const userModel = api.container.lookup("model:user");
</script>

@Johani, спасибо за вашу помощь!

2 лайка

Переклассифицирую это как баг.

Я добавил console.log в код API плагинов app/assets/javascripts/discourse/app/lib/plugin-api.js, чтобы он выводил сообщение каждый раз, когда вызывается modifyClass.

Я удалил все внешние плагины, чтобы убедиться, что конфликта нигде нет.

Воспроизведение:

  • создайте пустой форум на ветке stable (без Ember CLI). Это также не работает на ветке tests-passed (без Ember CLI). Я не тестировал это с Ember CLI.

  • добавьте компонент темы со следующим кодом в раздел Common - Head

#1 Работает

<script type="text/discourse-plugin" version="0.1">
    api.modifyClass('model:user', {
      pluginId: 'test-tc',
      testFunction: function() {
        return 1;
      } 
    });
</script>
  • загрузите главную страницу

  • в консоли появится сообщение: modifyClass called for model:user _application-08d9058ddd37ba80992f770509f4919ad0738a17f14fb85167b1dc1f32f8b56e.js:23490:16 Object { pluginId: "test-tc", testFunction: testFunction() }

  • введите в консоли Discourse.currentUser.testFunction()

  • будет выведено значение 1

#2 Не работает

  • перейдите к любой теме, например, “Добро пожаловать в Discourse”, и обновите страницу
  • в консоли появятся те же логи с сообщением “modifyClass called”
  • введите в консоли Discourse.currentUser.testFunction()
  • будет выведено сообщение об ошибке: Uncaught TypeError: Discourse.currentUser.testFunction is not a function

#3 Не работает с предупреждением

  • добавьте одну строку в начало компонента темы, чтобы он выглядел так:
<script type="text/discourse-plugin" version="0.1">
    const userModel = api.container.lookup("model:user");

    api.modifyClass('model:user', {
      pluginId: 'test-tc',
      testFunction: function() {
        return 1;
      } 
    });

</script>
  • перейдите к любой теме, например, “Добро пожаловать в Discourse”, и обновите страницу
  • в консоли появятся те же логи с сообщением “modifyClass called”
  • в консоли появится предупреждение: "model:user" was already cached in the container. Changes won't be applied.
  • введите в консоли Discourse.currentUser.testFunction()
  • будет выведено сообщение об ошибке: Uncaught TypeError: Discourse.currentUser.testFunction is not a function

#4 Работает

  • переместите строку lookup в конец компонента темы, чтобы он выглядел так:
<script type="text/discourse-plugin" version="0.1">
    api.modifyClass('model:user', {
      pluginId: 'test-tc',
      testFunction: function() {
        return 1;
      } 
    });

    const userModel = api.container.lookup("model:user");
</script>
  • перейдите к любой теме, например, “Добро пожаловать в Discourse”, и обновите страницу
  • в консоли появятся те же логи с сообщением “modifyClass called”
  • введите в консоли Discourse.currentUser.testFunction()
  • будет выведено значение 1 :partying_face:
4 лайка

Возвращаясь к этому:

В Discourse 2.8 и выше при использовании Discourse.User.current().testFunction() случай №2 всё ещё не работает.

1 лайк

У меня тоже возникла проблема с modifyClass, не уверен, связана ли она с этим?: Issues overriding getters in a controller (3.0.0)

Я только что улучшил наше предупреждение для подобных ситуаций:

а также подготовил документацию, объясняющую причину проблемы и способы её решения:

Думаю, это должно устранить все вопросы, поднятые в этой теме. Если нет, пожалуйста, приведите пример кода, вызывающего ошибку, и я разберусь.

11 лайков

Эта тема была автоматически закрыта через 3 дня. Новые ответы больше не принимаются.