Коммуникация между микроприложениями

В современном фронтенд-разработке архитектура микроприложений становится всё более востребованной. В контексте Vue.js это означает, что несколько независимых приложений или компонентов могут сосуществовать на одной странице, взаимодействуя друг с другом без жёсткой зависимости. Ключевая задача — организовать эффективную, надёжную и масштабируемую коммуникацию между этими приложениями.


Локальные события и шина событий

Для связи между Vue-компонентами внутри одного приложения традиционно используются $emit и props. Однако для микроприложений этот подход часто оказывается недостаточным, так как компоненты могут принадлежать разным экземплярам Vue.

Шина событий (Event Bus) позволяет решить эту проблему. Создаётся отдельный экземпляр Vue, который выступает в роли посредника:

// event-bus.js
import Vue from 'vue';
export const EventBus = new Vue();

Использование:

// Отправка события
EventBus.$emit('updateUser', { name: 'Alice' });

// Подписка на событие
EventBus.$on('updateUser', (payload) => {
  console.log(payload.name);
});

Ключевые моменты:

  • Применяется для передачи простых событий между независимыми приложениями.
  • Не создаёт жёстких зависимостей между микроприложениями.
  • Требует очистки подписок для предотвращения утечек памяти.

Глобальное состояние с Vuex

Для более сложных сценариев обмена данными между микроприложениями используется Vuex или аналогичные state-менеджеры. Центральное хранилище обеспечивает единый источник правды и реактивность для всех подключенных приложений.

Пример настройки Vuex для нескольких микроприложений:

// store.js
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export const store = new Vuex.Store({
  state: {
    user: null,
    settings: {}
  },
  mutations: {
    setUser(state, payload) {
      state.user = payload;
    },
    setSettings(state, payload) {
      state.settings = payload;
    }
  },
  actions: {
    updateUser({ commit }, user) {
      commit('setUser', user);
    }
  }
});

Подключение в приложении:

import { store } from './store';

new Vue({
  store,
  render: h => h(App)
}).$mount('#app1');

new Vue({
  store,
  render: h => h(App)
}).$mount('#app2');

Преимущества:

  • Централизованное управление состоянием.
  • Реактивное обновление всех приложений при изменении данных.
  • Возможность разделения модулей для изоляции логики отдельных микроприложений.

Использование внешних событий через window

Для полностью независимых приложений, загружаемых динамически, эффективным решением становится использование глобальных событий браузера (CustomEvent):

// Отправка события
window.dispatchEvent(new CustomEvent('themeChanged', { detail: { theme: 'dark' } }));

// Подписка на событие
window.addEventListener('themeChanged', (event) => {
  console.log(event.detail.theme);
});

Особенности:

  • Позволяет взаимодействовать между приложениями, загруженными разными фреймворками.
  • Не требует общего Vue-экземпляра или хранилища.
  • События легко отслеживаются и дебажатся в браузере.

Микрофронтенд-фреймворки и интеграция

Vue.js часто используется вместе с micro-frontend подходами: Single-SPA, Module Federation (Webpack 5) или Qiankun. Эти фреймворки предоставляют инфраструктуру для:

  • Динамической загрузки микроприложений.
  • Изоляции стилей и зависимостей.
  • Управления жизненным циклом приложений (mount, unmount, update).
  • Организации безопасной коммуникации через глобальные события или центральное хранилище.

Пример интеграции через Single-SPA:

import { registerApplication, start } from 'single-spa';

registerApplication({
  name: 'vueApp1',
  app: () => import('./vueApp1/main.js'),
  activeWhen: ['/app1']
});

registerApplication({
  name: 'vueApp2',
  app: () => import('./vueApp2/main.js'),
  activeWhen: ['/app2']
});

start();

Коммуникация между приложениями в этом случае строится на базе событий или shared state, предоставляемого фреймворком.


Рекомендации по архитектуре

  • Минимизировать прямые зависимости. Микроприложения должны быть как можно более независимыми.
  • Выбирать способ коммуникации под задачу: EventBus для простых уведомлений, Vuex для реактивного состояния, CustomEvent для полностью независимых приложений.
  • Очистка ресурсов. Подписки на события должны удаляться при размонтировании приложения.
  • Обеспечивать масштабируемость. При росте числа микроприложений централизованное хранилище и шина событий упрощают управление состоянием.

Практический пример комбинированного подхода

Микроприложение 1 изменяет тему сайта, микроприложение 2 реагирует на изменение темы:

// theme-bus.js
import Vue from 'vue';
export const ThemeBus = new Vue();

// app1.vue
ThemeBus.$emit('changeTheme', 'dark');

// app2.vue
ThemeBus.$on('changeTheme', (theme) => {
  document.body.className = theme;
});

При масштабировании можно заменить ThemeBus на Vuex-модуль или CustomEvent для глобальной коммуникации, сохранив реактивность и изоляцию.


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