Предстоящие изменения ядра, которые могут нарушить работу некоторых тем/компонентов (12 апреля)

На следующей неделе я объединю этот PR, который позволяет темам и компонентам иметь тесты QUnit, но он также меняет способ обработки/транспилирования JavaScript тем в Discourse. Реализовать эти изменения обратно совместимым образом очень сложно без переработки значительной части кода ядра (что, в свою очередь, может привести к другим изменениям, нарушающим обратную совместимость), поэтому при обновлении вашего сайта JavaScript ваших тем/компонентов может перестать работать.

В этом посте я объясню, какие изменения могут повлиять на ваши темы/компоненты и что нужно сделать, чтобы исправить ситуацию.

1. JavaScript внутри тегов <script type="text/discourse-plugin"> будет выполняться с включенным строгом режиме

Это изменение не влияет на JS-код, который находится вне тегов <script type="text/discourse-plugin">. Если ваш код находится в обычных тегах <script> или в отдельных файлах .js, вы полностью защищены от этого изменения.

Самый простой способ проверить, затронут ли ваша тема или компонент этим изменением, — обернуть ваш JS-код в вызываемое сразу выражение функции (IIFE) и добавить "use strict"; в начало кода. Например, предположим, что сейчас ваш код темы выглядит так:

<script type="text/discourse-plugin" version="0.8.11">
  a = 5;
  console.log(a);
</script>

После обертки в IIFE он должен выглядеть так ("use strict"; важен, так как включает строгий режим, и мы хотим проверить, как ведет себя наш код в этом режиме):

<script type="text/discourse-plugin" version="0.8.11">
  (function() {
    "use strict";
    a = 5;
    console.log(a);
  })();
</script>

Если после этого ваш компонент перестал работать, значит, при обновлении сайта он сломается. Чтобы исправить код, настоятельно рекомендую сначала ознакомиться с документацией MDN по строгому режиму JavaScript, а затем проверить, не делает ли ваша тема/компонент ничего запрещенного в строгом режиме. Если да, то нужно рефакторить код, чтобы исключить такие действия.

Самая вероятная ошибка, с которой вы столкнетесь, — это ReferenceError при объявлении переменной без ключевого слова var (или let/const). В примере выше строка a = 5; вызовет исключение ReferenceError в строгом режиме, так как мы забыли добавить var. Исправленный код выглядит так:

<script type="text/discourse-plugin" version="0.8.11">
  (function() {
    "use strict";
    var a = 5;
    console.log(a);
  })();
</script>

После завершения тестирования/исправления кода вы можете смело удалить IIFE и строку "use strict";.

2. Пути к модулям JavaScript тем будут иметь префикс с ID темы.

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

Когда тема или компонент, поставляемый с отдельными файлами JavaScript, устанавливается на экземпляр Discourse, система перебирает все файлы JavaScript и создает модуль для каждого из них. Каждый модуль должен иметь уникальный идентификатор (также известный как путь), поэтому Discourse использует путь к файлу (с небольшими изменениями) в качестве пути модуля.

Например, если ваша тема/компонент имеет файл по адресу javascripts/discourse/helpers/my-helper.js, Discourse создаст модуль для этого файла и назначит ему путь discourse/helpers/my-helper. Этот модуль будет содержать транспилированную версию JavaScript из исходного файла.

Преимущество модулей в том, что вы можете импортировать классы/функции/объекты и т. д. из одного модуля в другой. Например, вы можете импортировать функцию xyz из my-helper в другие модули, используя оператор import следующим образом:

// javascripts/discourse/controllers/my-theme-controller.js

import { xyz } from "discourse/helpers/my-helper";

PR, который я объединю на следующей неделе, добавит префикс к путям модулей тем. Таким образом, в нашем примере my-helper изменится с discourse/helpers/my-helper на discourse/theme-<theme_id>/helpers/my-helper. Это означает, что наш оператор import перестанет работать, так как путь к модулю изменится. Чтобы исправить это, нужно просто изменить путь в операторе import с абсолютного на относительный, как показано ниже:

// javascripts/discourse/controllers/my-theme-controller.js

import { xyz } from "../helpers/my-helper";

Теперь наш оператор import должен работать снова. Посмотрите эти PR 1 и 2 для реальных примеров компонентов, затронутых пунктом (2), и того, как они были исправлены.

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

Надеюсь, это поможет. Если у вас возникнут вопросы, пожалуйста, дайте мне знать!

31 лайк

Спасибо за подробный разбор :slight_smile:

Отразится ли это на «абсолютных» путях к файлам в плагине, используемом в компоненте темы? Например, компоненты темы, работающие с плагином layouts, требуют наличия вспомогательных функций в самом плагине layouts, как в этом примере:

requirejs('discourse/plugins/discourse-layouts/discourse/lib/layouts')

См., например, виджет списка категорий layouts.

Похоже, что изменение пути здесь согласуется с пространством имен ресурсов в конвейере ресурсов плагина (используются идентификаторы тем вместо имен плагинов), и пути к ресурсам плагина, используемые в компоненте темы, останутся неизменными. И что require, как в примере выше, продолжит работать. Так ли это?

7 лайков

Да, всё верно :+1:

6 лайков

@loginerror, думаю, вы найдете эту тему полезной :wink:

7 лайков

@Terrapop
Кажется, у вас были по этому поводу опасения.

5 лайков

Мы уже исправили наш код, когда это было выкатано на ограниченное время.

5 лайков