Какие существуют практики для сабжа?
Допустим, есть некие общие функции, которые необходимы и в клиентском JS, и в bemhtml.
Как наиболее корректно и с минимумом костылей избежать копипаста? Пока напрашивается некий модуль, который будет:
- Средствами сборщика импортироваться в блок, реализующий клиентский JS, который потом цепляется зависимостями куда надо.
- Расширять BEMContext, но для этого модуль тоже надо импортировать сначала.
Это выглядит работающим решением, но вызывает сомнения в плане адекватности. Можно ли изящнее?
Скорее всего вы не должны этого хотеть. В клиентском JS есть (может быть) BEMHTML. Можете подробнее описать кейс?
@gwer Есть решение на уровне сборки: https://github.com/enb/enb-bemxjst#%D0%9F%D0%BE%D0%B4%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-%D1%81%D1%82%D0%BE%D1%80%D0%BE%D0%BD%D0%BD%D0%B8%D1%85-%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA
@Realetive, я неоднократно задавался вопросом наличия такового желания, и избавиться от него не удалось. Например, из данных, прилетающих от бэкэнда, нужно уметь формировать отчёт как в HTML, так и в более простом текстовом формате. Для построения отчёта данные нужны как в сыром виде, так и в некотором отформатированном. Можно эти данные отформатировать на бэкэнде, и продублировать их в сыром и форматированном виде на клиент. Но, допустим, что мы не хотим или не можем этого сделать.
@tadatuta, надо потыкать, но выглядит отличным решением проблемы. Благодарю.
Потыкал. Но всё же проблема решена не до конца.
Создаю ym-модуль. Допустим, desktop.blocks/my/my.js. Добавляю в deps, в .enb/make.js прописываю модуль в requires. Модуль доступен в клиентском JS, в клиентском BEMHTML. А в серверном BEMHTML чуда не происходит. Так понимаю, проблема в том, что модуль относится к клиентской технологии и в серверную сборку не попадает. Если это так, каким образом его наиболее аккуратно можно подсунуть в нужное место?
@gwer
Если смотреть на конфиг сборки в
project-stub
илиbem-express
, то за сборку серверного и клиентского BEMHTML отвечают отдельные части конфига: сервер и клиент.Результатом использования опции requires является генерация вызова
onInit()
, где происходит предоставление запрошенного модуля так, что он становится доступен поthis.require('lib-name')
внутри любого шаблона. При этом такое подключение достаточно универсальное: можно подключить как просто файл с глобальными переменными, так и CommonJS-модуль — это разрулится в build time.Чтобы написать универсальный модуль, который будет работать и как CommonJS и в браузере с
ym
, можно добавить экспорт по условию. Что-то в духе (не тестровал, могут быть опечатки): ```js (function(global) {// эта строка символизирует некий полезный универсальный код var myModule = function() {};
// добавляем экспорт в зависимости от окружения if (module && module.exports) {
} else if (modules) {
} else {
}
})(this);
Надеюсь, это отвечает на вопрос.
@tadatuta, спасибо за развёрнутые ответы.
1). Это понятно. 2, 3) Так и не понял, можно серверной части скормить YM или обязательно предоставлять второй интерфейс (CommonJS, например)?
В доке сказано, что для CommonJS нужен относительный путь. Столкнулся с проблемой, заключающейся в том, что удаётся заставить работать только с абсолютными. Глубоко не копал, но, на первый взгляд, проблема в том, что внутри require путь разворачивается до абсолютного, а в качестве аргумента передаётся относительный.
Бросаемая ошибка:
Error: Cannot find module '../../desktop.blocks/my/my2.js'
, изнутри этого самого require. Путь правильный (содержимое инлайнится, да и при неправильном пути ошибки другие). Если передавать абсолютный путь, то всё работает. Пакеты npm и project-stub актуальные на текущий час. Что-то делаю не так?Пока что удаётся завести лишь с модулем, имеющим два интерфейса (YM, CommonJS), и с выбором способа доставки модуля внутри BEMHTML в зависимости от окружения (
require(path)
/this.require(name)
). Это уже неплохо, работает, но всё ещё грязновато. Хочется чище, насколько это позволяют инструменты.Можно лишь при условии, что
ym
будет доступна на сервере (она-то кроссплатформенная и потенциально работать может, но есть ли смысл ее тянуть? Я бы предпочел добавить экспорт в CommonJS, но это скорее дело вкуса).Кажется, дока вероломно брешет, у нас в коде вот так:
Верно ли я понял, что речь о том, что в одних и тех же шаблонах на клиенте и на сервере приходится использовать разный способ получения модуля? Если так, то определенно можно собрать так, чтобы всегда использовать только
this.require(name)
, для этого все и задумывалось.В остальном, вроде, звучит нормально.
Идеи понял. Всё завелось. Спасибо.