Объявление класса по-разному для разных версий Dojo без дублирования кода?

#javascript #dojo #ibm-connections

#javascript #dojo #ibm-connections

Вопрос:

У меня есть iWidget, разработанный для IBM Connections, и мой код javascript зависит от Dojo (который по умолчанию включен в Connections).
В настоящее время он работает в Connections 4.0 и 4.5, но не работает в Connections 5.0 (выпущен на прошлой неделе), поскольку Dojo был обновлен до версии v1.9 и жалуется на мое использование dojo.require .

Эти сообщения появляются в консоли браузера, когда мой виджет пытается загрузиться в Connections 5.0:

Избегайте вызова dojo.require() для загрузки классов во время выполнения, используйте вместо этого net.jazz.ajax.xdloader.load_async(). Функции '(анонимной)' требуется класс 'dojox.atom.io.model'.
Избегайте вызова dojo.require() для загрузки классов во время выполнения, используйте вместо этого net.jazz.ajax.xdloader.load_async(). Для функции '(анонимной)' требуется класс 'dojox.atom.io.Connection'.

Я хочу создать условный код, который использует разные способы определения моего класса виджетов и требует других модулей Dojo в зависимости от версии Dojo.

Виджет javascript в настоящее время выглядит следующим образом:

 dojo.provide('insightCommunityWidgetClass');
dojo.require('dojox.atom.io.model');
dojo.require('dojox.atom.io.Connection');

dojo.declare('insightCommunityWidgetClass',null,{
    // Class fields and methods. Currently 680 lines uncompressed.
});  

Я еще не создал версию, которая работает с Dojo 1.9 / Connections 5.0, но я думаю, что это выглядело бы примерно так (и мне нужно, чтобы имя моего файла javascript соответствовало желаемому имени класса):

 define(['dojo/_base/declare','dojox.atom.io.model','dojox.atom.io.Connection'], function(declare){
    return declare(null, {
        // Class fields and methods.
    });
});
  

Как я могу поместить оба этих файла в один файл и выбирать между ними, не дублируя тело класса?

Обновить:
Я попробовал некоторый условный код, проверяя (define amp;amp; define.amd) , как предложил Дмитрий, протестировал это на подключениях 4.0 и 4.5, и получаю очень странное поведение.

Временно игнорируя любые попытки не дублировать мой класс, вот некоторый условный код, который я использовал точно так, как показано, с сильно уменьшенным классом виджетов:

 if (define amp;amp; define.amd) {
    console.log('Declaring insightWidgetClass with AMD (new method).');
    define(['dojo/_base/declare','dojox/atom/io/model','dojox/atom/io/Connection'],
        function(declare){
            return declare(null,{
                SVC_INV: 1,
                onLoad: function() {
                    console.log('insightWidgetClass onLoad.');
                }
            });
        }
    );

} else {
    console.log('Declaring insightWidgetClass with dojo.declare (old method).');
    dojo.provide('insightWidgetClass');
    dojo.require('dojox.atom.io.model');
    dojo.require('dojox.atom.io.Connection');

    dojo.declare('insightWidgetClass',null,{
        SVC_INV: 1,
        onLoad: function() {
            console.log('insightWidgetClass onLoad.');
        }
    });
}  

Похоже, это вообще не выполняется. Ни одно из моих console.log сообщений не отображается в консоли браузера.

Если я закомментирую условные обозначения и сделаю так, чтобы единственным активным кодом был блок после else , он запускается. Я получаю «объявление … (старый метод)» и консольные сообщения «insightWidgetClass onLoad».

Я подумал, что, возможно, включение вызовов Dojo provide , require и declare в любой тип блока может вызвать проблему, поэтому я протестировал простое помещение рабочего кода в if (true) { блок, и это все еще работает.

Последнее, что я пробовал на данный момент, — это добавить эту строку перед всем остальным, чтобы посмотреть, что define такое:

 console.log('dojo define',define);  

… что нарушает его. В моем коде вообще нет сообщений консоли.
Затем я удаляю define аргумент из этой новой строки, так что он просто отправляет строку на консоль, и код снова работает.
Похоже, что любое упоминание define идентификатора автоматически останавливает выполнение остальной части кода.
В консоли нет ошибок или предупреждений, указывающих на проблему. Все, что я могу сказать на это, это: WTF?!

Теперь вместо этого вернемся к проверке dojo.version .

Комментарии:

1. Просто предложение. Вы могли бы попробовать вложить код, специфичный для версии dojo, используя dojo.version смотрите здесь для деталей.

2. @frank — Я знаю об dojo.version объекте, но я не вижу из этой документации, как я могу избежать дублирования всего тела моего класса, когда для разных версий Dojo нужно изменить только строки dojo.provide , dojo.require и dojo.declare .

3. Известен другой модуль, который имеет dojo.has . смотрите здесь подробности, которые могут быть полезны для вашего сценария. dojo.has может использоваться согласно этому руководству для создания конкретных сборок . Надеюсь, это поможет

Ответ №1:

Обычно оба должны по-прежнему работать, dojo.provide() и dojo.require() устарели, но не удалены полностью. Просто убедитесь, что ваш dojo загружается в синхронном режиме.

Кроме того, способ кодирования AMD представлен в Dojo 1.7, что означает, что он также должен поддерживаться в IBM Connections 4.5 (хотя я не знаю об IBM Connections 4).

Но если вы действительно хотите использовать обе базы кода, вы можете просто ссылаться на один и тот же объект вместо его дублирования, например:

 var myModule = {
    // Class fields and methods.
};
if (dojo.version.major == 1 amp;amp; dojo.version.minor == 9) {
    define(['dojo/_base/declare','dojox.atom.io.model','dojox.atom.io.Connection'], function(declare){
        return declare(null, myModule);
    });
} else {
    dojo.provide('insightCommunityWidgetClass');
    dojo.require('dojox.atom.io.model');
    dojo.require('dojox.atom.io.Connection');

    dojo.declare('insightCommunityWidgetClass',null, myModule);  
}
  

Или вы могли бы использовать следующую проверку:

 if (typeof define === 'function' amp;amp; define.amd) {
    // AMD style code
} else {
    // Non-AMD style code
}
  

Это подход, используемый большинством библиотек с перекрестной загрузкой. Библиотеки, которые работают как на загрузчиках AMD (Dojo, Require.js ), но также на Node.js или просто с помощью глобального пространства имен используйте аналогичный фрагмент кода, чтобы определить, как они загружают свой модуль.

Комментарии:

1. Я действительно пытался сделать это таким образом. Похоже, у платформы widget есть проблема с этим. Ошибок нет, но метод onLoad виджета никогда не запускается, когда я пишу его таким образом. Я собираюсь попробовать определить класс как функцию с помощью прототипированных методов, как в пункте 1.2 phpied.com/3-ways-to-define-a-javascript-class .

2. Также отметим, что проверка на define amp;amp; define.amd кажется хорошим предложением; лучше, чем проверка номеров версий.

3. @ScottLeis Действительно, я думаю, что это предпочтительный способ проверки этих вещей. Многие библиотеки делают это, например, взгляните на Moment.js в котором выполняется аналогичная проверка: github.com/moment/moment/blob/develop/moment.js#L2723

4. Я обновил свой вопрос подробностями странной проблемы, которую я пытался проверить define . Я снова попытался установить переменную класса (как в вашем ответе), и теперь это, похоже, работает в соединениях 4.0 и 4.5, поэтому, должно быть, я допустил какую-то ошибку, когда это решение изначально не удалось. В настоящее время возникают большие проблемы с нашей средой Connections 5.0 (Dojo 1.9), поэтому может пройти несколько дней, прежде чем я смогу подтвердить ответ.

5. В вашем старом коде, который вы используете dojo.require() , в AMD есть разница между require() и define() . define() работает, только если модуль позже импортируется внутри require() функции. Так define() работает только для определения модулей, но для того, чтобы использовать этот модуль, вам нужно require() это.

Ответ №2:

Это не ваш код, он должен работать как есть. Недавно мы столкнулись с той же проблемой и определили причину.

В Connections 5 используется AMD-версия Jazz framework, которая предоставляет собственный загрузчик dojo. Этот фреймворк используется для объединения необходимых модулей dojo в один JS-файл, что ограничивает количество запросов к серверу. К сожалению, этот загрузчик больше не обрабатывает синхронную загрузку модулей. Сбой с предупреждением, о котором вы сообщали, когда dojo.require() запрашивает модуль, который еще не загружен агрегатором. Если модуль уже был загружен, потому что он был частью агрегированного файла Jazz, тогда он работает. Это объясняет, почему вы можете dojo.require() использовать некоторые модули, но не все из них.

-> Обходной путь заключается в развертывании пакета OSGi на стороне сервера, чтобы получить нужные вам модули из агрегированного JS-файла. Для этого существует документированная точка расширения. Это может разблокировать вас и одновременно повысить производительность вашей страницы.

Теперь мы открыли PMR для службы поддержки IBM. Команда разработчиков работает над разрешением. Мы надеемся, что они смогут исправить ситуацию в ближайшее время.

Мы сообщили о следующих проблемах:

  • dojo.require()
  • dojo.требуется локализация()
  • dojo.registerModulePath()/требовать({пути:})

Если вы подумаете о чем-то другом, пожалуйста, дайте мне знать.

Комментарии:

1. Спасибо, Филипп. Это очень интересно. Я буду следить за любыми исправлениями подключений, связанными с этим.

2. Как я понял, это должно быть исправлено в C5 CR1, а также с iFix, если вам это нужно раньше.