Comments

Если честно, немного не понятно, зачем плодить модульные broadcast и сами $module, когда можно общаться через единую шину (в примере $rootBroadcast) с помощью сообщений, одним из обязательных параметров которого будет имя модуля. причем, если нет желание писать имя модуля в событии явно, его также можно задекларировать в прототипе вуя как $moduleName. Наличие класса типа ModuleEvent даст возможность понимать где какие события отсылаются/обрабатываются. Это может быть полезным при погружении и фикса багов.

Добрый день. Спасибо за комментарий! Да, действительно такая возможность существует и реализована в $rootBroadcast как вы и заметили (события из модуля дублируются в нем, снабженные в качестве первого параметра именем модуля). Единственная причина такого дробления — некоторое удобство. Для работы исключительно в скоупе модуля нет необходимости держать в голове его название и добавлять его каждый раз. Наши задачи в 90% покрываются именно таким взаимодействием, поэтому решили что это приемлемо.

А можно все это организовать через нативный window.postMessage, который не зависит от фреймворков и здорово спасает, если у вас их, вдруг, несколько на проект.

Добрый день. Спасибо за комментарий! Честно говоря, не приходила в голову использовать postMessage для такой тривиальной задачи, но вероятно работать будет. Для нас ценность этого конкретного решения в интегрированности и максимально простом апи
А хотим мы встроить в наше приложение шину событий.


Средствами Vuex мы и так вроде имеем шину событий.
Любой компонент может подписаться на изменения в любом store. Это помимо встроенной реактивности — что тоже уже шина событий.

ИМХО может вам просто пересмотреть как вы организовали свое хранилище (Vuex store).

Добрый день. Спасибо за ваш комментарий. Да, конечно Vuex подразумевает реактивность и в 95% случаев нам ее достаточно. Тем не менее есть ~5% случаев, в которых требуется именно реакция на событие а не реакция на изменение данных. Теоретически можно протащить флаги в стор для этого и как-то действовать через них, но им же нужно потом восстанавливать значение и в принципе следить за консистентностью дополнительно. Мы наступили пару раз на грабли с таким подходом и решили перейти на более безопасный в нашей парадигме паттерн Pub/Sub
Зачем замусоривать прототип? Можно вполне элегантно через provide\inject.
Добрый день. Благодарю за ваш комментарий. Да, это и правда рабочий вариант. В нашем решении мы больше сделали упор на генеричность, но ваше более декларативно. Возможно если где-то мы столкнемся с проблемой генеричного подхода, воспользуемся вашим вариантом.

Поздравляю вас, вы в одном решении использовали кажется все антипаттерны вью.
Расширение прототипа — во вью3 оставят только как штуку для обратной совместимости легаси плагинов. Больше не рекомендуется к использованию.
Во вью3 с новым композишн апи нельзя использовать миксины.
Во вью3 удалят $on, $off, $once.
Во вью3 удалят как минимум из доки упоминания $root, $parent

Добрый день! Спасибо за ваш комментарий и за предупреждение. В нашем решениях мы исходим из реалий в которых работаем на текущий момент. Уверен, что в vue3 будет какой-то свой, предпочтительный на тот момент, способ предоставлять доступ к некоторым условно внешним объектам. Мы определенно воспользуемся им, чтобы реализовать замещающую функциональность.

Пожалуйста, не делайте так в ваших приложениях. Для реализации Pub\Sub есть множество готовых решений и они не требуют какой-то специальной интеграции для Vue.
Здесь действительно целый огород из плохих практик:


  1. Шина на Vue (готовится стать deprecated во Vue 3), считается плохой практикой и разработчики Vue это признали сами.
  2. Обращение к $parent — повышает связанность компонентов и работает неявно. Такой код будет очень сложно поддерживать потому что непонятно кто что вызывает.
  3. Миксины. Особенно глобальные миксины. О минусах миксинов писали много раз, но я повторю: конфликты имён, непонятно что добавляет миксин без чтения кода самого миксина, сложно определить кто пропатчил контекст компонента когда миксинов несколько.

Для хранения глобального состояния и глобальной обработки событий используйте Vuex или Provide\Inject. Если вам нужна связь только по событиям используйте Pub\Sub (но я не смог придумать такой кейс если честно).

Добрый день. Спасибо за то, что внимательно прочитали статью и за такой подробный комментарий. Есть о чем задуматься. Коротко про кейсы:
0. Задача с Pub/Sub действительно довольно тривиальная и реализаций есть множество — тот же Rx например. Дело в том что конкретно это решение призвано решить очень утилитарную проблему максимально просто и быстро и быть максимально прозрачным в использовании — поэтому хотелось бы решить все без дополнительных зависимостей и желательно без доп документации
1. На момент написания этого плагина шина на Vue не являлась плохой практикой. Да и в принципе шина событий это паттерн проектирования — ее плохое использование может быть плохой практикой, а сама по себе она просто инструмент. Как вы сами отметили существует много альтернативных решений — мы использовали конкретно Vue только из соображений зависимостей
2. В целом это совершенно верно в случаях обычного кода и мы не допускаем такого в компонентах. Но в данном случае мы имеем дело с генеричным кодом. Обращение к $parent здесь служит для оценки контекста и по факту именно резолвит связанность в ее прикладном понимании (грубо говоря тот оверхед, который необходим чтобы решение заработало в новом контексте). Опять же результат отработки кода консистентен не зависимо от результатов анализа $parent — событие все равно будет запущено или проксированно. Поэтому лично я не вижу в этом проблемы
3. Совершенно согласен с вашим утверждением насчет миксинов. Не скажу что совсем нет случаев оправданных для их использования, но они единичны и использовать их надо аккуратно. В данном случае, отмечу снова, мы говорим не про код компонентов, а про генеричное расширение общее для всего приложения, поэтому нет необходимости держать в голове что-то специфичное конкретному контексту — только приложению целиком.

Про provide/inject я написал выше. В целом мне кажется что каждый выбирает инструменты исходя из конкретной задачи. Я не говорю, что этот вариант решения единственный, или лучший, или универсальный, либо что с его помощью нельзя выстрелить в ногу. Это просто конкретное решение конкретной задачи, который можно использовать (или не использовать) по своему усмотрению
А как же тогда лучше будет общаться, например, соседним компонентам, если нельзя теперь будет использовать шину?
Всё круто, но вынести бы ещё сам объект с методом install (плагин) в отдельный файл и просто в main.js уже вызывать vue.use()
Добрый день. Спасибо за комментарий! Безусловно можно так код организовать) мы пока не стали так делать потому что он довольно лаконичный. Но возможно в перспективе, если будем наращивать функционал, так и сделаем.
Идея интересная: для событий бизнес-логики использовать Vuex, а для «реакции нашего компонента на событие, произошедшее в другом компоненте, которое само по себе никак не связано с потоком данных» использовать шину. Как будете дисциплинировать разработчиков придерживаться такого деления? Есть подозрение, что разработчики не смогут точно отделять одно от другого и будут использовать и Vuex и шину для всего.
Добрый день! Спасибо за комментарий)
Здесь вопрос организации процесса разработки конечно, поэтому за всех не могу говорить, могу только за свою команду)
У нас с этим не возникло проблем по двум причинам:
1. При внедрении плагина мы сразу озвучили какие случаи мы решаем с помощью шины, а какие нет. На практике каждое ее использование обсуждается и согласовывается, потому что случаев ее использования очень не много — примерно 5%. Дело просто в том, что эти 5% при других способах порождают неоправданно большой оверхэд если делать их через Vuex или однонаправленный поток. Если буквально — результат асинхронного действия как-то отражается на модели данных и это можно наблюдать через watch? Используй Vuex. Если нет — используй шину.
2. Контроль на код-ревью)
Only those users with full accounts are able to leave comments. Log in, please.