Демонстрация микро-фронтенда (singleSpa + React)

JavaScript

предисловие

Наша команда работает над системой XX, стек технологийReactВ настоящее время система становится большей и большей, затраты на разработку и обслуживание увеличиваются, и весь проект должен быть упакован каждый раз, что является трудоемким и трудоемким трудоемким. После рассмотрения было решено разделить его в несколько проектов и объединить их в полную систему. Архитектура Micro-Frontend является очень хорошим выбором.

Микрофронтенды имеют следующие преимущества:

  1. Обслуживание одного проекта: например,商品模块Вытащенный для формирования проекта, он может поддерживаться командой в одиночку, достигая хорошей развязки
  2. Уменьшенная сложность: нет необходимости разрабатывать во всей интегрированной огромной системе, избегая огромного количества кода, быстрой компиляции во время разработки и повышения эффективности разработки.
  3. Отказоустойчивость: ошибка в одном проекте не влияет на всю систему
  4. Гибкий технологический стек: можно использовать vue, react, angular и т. д., включая другие интерфейсные технологические стеки, и тем, кто знает vue, не нужно заново учиться реагировать

Самым большим преимуществом для нас является单项目维护.

экспонат

Пример схемы пользовательского интерфейса

Делим весь микрофронтенд на две части:

  1. Основной проект (Main): Часть красного поля, как родитель всего проекта, отвечает за отображение модуля меню и модуля заголовка.
  2. Подприложения: часть синего поля, роль подпроекта заключается в отображении конкретного бизнеса.

Анимированный дисплей

Наблюдайте за изменением адресной строки, который содержит/app1/xxxа также/app2/xxx, который на первый взгляд является переключением между двумя страницами в проекте, на самом делеиз двух отдельных проектов, app1 и app2 из разных репозиториев git.

Диаграмма микроинтерфейсной архитектуры

Весь процесс примерно таков: пользователь обращается к index.html, затем запускает загрузчик модулей Js, загрузчик регистрирует каждый проект в соответствии с конфигурационным файлом (project.config) всей системы, система сначала загружает основной проект (основной), а затем будет динамически загружать соответствующие подпроекты в соответствии с префиксом маршрутизации

Наша архитектура также ссылается на множество хороших статей в Интернете, из которых можно сослаться на основные статьи.Арири Специальности/архив/110…

О проекте.config

примерно так

[
 {
    isBase: false,
    name: 'app1',
    version: '1.0.0',
    //通过该路由前缀匹配加载当前入口文件
    hashPrefix: '/app1',
    //入口文件
    entry: 'http://www.xxxx.com/app1/dist/singleSpaEntry.js',
    //顶级Store
    store: 'http://www.xxxx.com/main/dist/store.js'
  }
  ......
]

Здесь project.config используется в производственной среде.Мы загружаем упакованные файлы в OSS (или CDN), а затем синхронизируем текущую упакованную конфигурацию проекта с сервером.Сервер интегрирует все конфигурации проекта в project.config.При доступе к индексу .html, будет получен project.config, а затем single-spa зарегистрируется по этим конфигурациям и загрузит соответствующий проект по маршруту.

Технические подробности

single-spa

Мы нашли несколько репозиториев, реализующих микрофронтенды, и после сравнения решили их использовать.single-spa.

Наш технологический стек — реакция, и нам нужно использовать single-spa-react для создания записи подпроекта Код ключа выглядит следующим образом:

import singleSpaReact from 'single-spa-react';

const reactLifecycles = singleSpaReact({
  React,
  ReactDOM,
  rootComponent: Root,
  domElementGetter
});

export function bootstrap(props) {
  return reactLifecycles.bootstrap(props);
}

export function mount(props) {
  return reactLifecycles.mount(props);
}

export function unmount(props) {
  return reactLifecycles.unmount(props);
}

Если вы используете vue, вы можете использовать single-spa-vue

Затем в системном файле входа прописать все проекты:

import * as singleSpa from 'single-spa';

singleSpa.registerApplication(
    'app1',
    () => SystemJS.import('app1-entry.js'),
    () => location.hash.startsWith(`#/app1`),
    props
  );

Подробную информацию можно найти на официальном сайте single-spa.single-spa.js.orgЗдесь много примеров

Webpack и SystemJs

Мы используемlernaУнифицированное управление пакетами зависимостей всех проектов и унифицированные версии всех зависимых пакетов, что очень удобно для обслуживания.

Используйте функцию dll webpack для извлечения общих зависимостей всех проектов, таких как react, react-dom, react-router, mobx и т.д.

Чтобы облегчить динамическую загрузку проекта, мы также обращаемся к идеям онлайн-боссов и используемsystemjs, мы используем версию 0.20.19. С systemjs вам нужно изменить libraryTarget в Webpack:

output: {
    publicPath: 'http://www.xxxxx.com/',
    filename: '[name].js',
    chunkFilename: '[name].[chunkhash:8].js',
    path: path.resolve(__dirname, 'release'),
    libraryTarget: 'amd', //注意 这里使用 amd 的规范
    library: 'app1'
  },

Мы не использовалиumdспецификация, использованиеamdспецификация и не использует карты импорта в systemjs функция, но напрямую через project.config для динамической загрузки записи модуля.

связь между приложениями

По этому поводу я тоже видел планы некоторых больших парней.Наверное во всех проектах есть стор.При регистрации записи все сторы ставятся в очередь.Когда нужно обновить состояние в сторе, вызывается диспетчеризация синхронизировать все магазины.

Мой подход такой же, как и для традиционного одностраничного приложения. В системе должен быть только один Магазин верхнего уровня. Поскольку Магазин верхнего уровня обычно хранит общее состояние всей системы, такое как меню, информация о пользователе и т. д., Ставлю в Основной проект, но при упаковке This Store извлекается отдельно:

entry: {
    singleSpaEntry: './src/singleSpaEntry.js',
    store: './src/store' //单独一个入口
  },

При регистрации передайте этот Store в каждый проект:

//顶级Store
const mainStore = await SystemJS.import(storeURL);

singleSpa.registerApplication(
    'app1',
    () => SystemJS.import('http://www.x.com/app1/entry.js'),
    hashPrefix('/app1'),
    { mainStore }
);
singleSpa.registerApplication(
    'app2',
    () => SystemJS.import('http://www.x.com/app2/entry.js'),
    hashPrefix('/app1'),
    { mainStore }
);

Таким образом можно управлять только этим магазином, что очень удобно. Примечание. Я использую Mobx для управления состоянием.

Интерфейсное развертывание

Способ развертывания очень прост. Я сам написал плагин веб-пакета, чтобы передать упакованный дистрибутив в OSS, а затем отправить конфигурацию проекта на сервер. Сервер (NodeJs) организует project.config в соответствии с поступающей конфигурацией проекта. Затем пользователь получит project.config при доступе к index.html.В это время single-spa регистрирует все проекты в соответствии с конфигурацией, а затем извлекает соответствующий файл записи проекта js файл в соответствии с маршрутом.

Поместите смонтированный DOM подпроекта в основной проект

Наше требование состоит в том, чтобы Main был Layout всего проекта, а mount Dom подпроекта тоже был в Main проекте, это значит, что подпроекты не могут быть смонтированы до полного рендеринга Main проекта. Я сослался на реализацию некоторых микрофронтендов в интернете, и позаимствовал метод domElementGetter:

function domElementGetter() {
  let el = document.getElementById('sub-module-wrap');
  if (!el) {
    el = document.createElement('div');
    el.id = 'sub-module-wrap';
  }
  let timer = null;
  timer = setInterval(() => {
    if (document.querySelector('#content-wrap')) {
      document.querySelector('#content-wrap').appendChild(el);
      clearInterval(timer);
    }
  }, 100);

  return el;
}

demo

демонстрационный адрес:GitHub.com/viand/m признает…Эта демонстрация предоставляет только справку на микроконце, фактическую разработку и развертывание, вам нужно увидеть вас

заключительные замечания

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