Эта статья на самом деле готовилась 11 месяцев, потому что, хотя мы начали использовать архитектуру микро-фронтенда Angular в начале года, продукт официально не выпущен, и его возможность не может быть проверена на практике в производственной среде. , наш продукт был официально недоступен.Пришло время поделиться нашим опытом на пути использования микро-фронтенда Angular (яма, на которую мы ступили), я надеюсь расти и развиваться вместе с сообществом Angular, если у вас есть определенное понимание микро-фронтенда и уже в проекте Пытался игнорировать предыдущие главы.
Что такое микрофронтенд
За последние два года термин «микрофронтенд» часто появлялся в поле зрения каждого. модули или приложения во внешнем интерфейсе могут быть решены.Связывание, так что внешние подмодули независимо хранятся, работают независимо и развертываются независимо.
Так в чем же разница между микрофронтендом и микросервисом?
На следующем рисунке представлена схематическая диаграмма микросервисов. Микросервисы в основном представляют собой бизнес-модули, которые разбиты по определенным правилам, независимо разрабатываются и развертываются независимо. После развертывания они маршрутизируются и перенаправляются через Nginx. модули Проблемы с вызовами, а также аутентификация, ведение журнала и даже присоединение к уровню шлюза
Для микросервисов разделение и развязка модулей в основном завершены, но микро-фронтенд другой: фронтенд-приложение представляет собой единое целое во время выполнения, требующее агрегации и даже взаимодействия и коммуникации.
Зачем вам нужен Micro Front-end
- Увеличивается количество системных модулей, одно приложение становится раздутым, эффективность разработки низка, а скорость сборки падает;
- Расширение персонала требует, чтобы несколько фронтенд-команд разрабатывались и развертывались независимо друг от друга, если все они будут разрабатываться на одном складе, это принесет ряд проблем;
- Для решения устаревших систем новые модули должны использовать новейшие платформы и технологии, а старые системы продолжают использоваться.
Сравнение нескольких схем микроинтерфейса
Способ | описывать | преимущество | недостаток | степень сложности |
---|---|---|---|---|
переадресация маршрута | Переадресация маршрутизации не является строго микроинтерфейсом, и навигация может быть разделена между несколькими подмодулями. | Просто и легко реализовать | Опыт не очень хороший, переключите приложение, чтобы обновить всю страницу | 🌟 |
Вложенные фреймы | Одно вложение iframe для каждого дочернего приложения | Изоляция песочницы между приложениями | Многократная загрузка скриптов и стилей | 🌟🌟 |
состав времени сборки | Независимое складирование, независимая разработка, общая упаковка во время строительства, слияние приложений | Упрощение управления зависимостями и извлечение общих модулей | Невозможно развернуть независимо, технологический стек и зависимые версии должны быть унифицированы. | 🌟🌟 |
композиция во время выполнения | Каждое подприложение создается независимо, а основное приложение отвечает за управление приложением, загрузку, запуск, выгрузку и механизм связи во время выполнения. | Хороший опыт, настоящая независимая разработка, независимое развертывание | Сложный, необходимо спроектировать загрузку, механизм связи, невозможно достичь полной изоляции, необходимо решить проблему конфликта зависимостей, конфликта стилей. | 🌟🌟🌟 |
Web Components | Каждое подприложение должно использовать технологию веб-компонентов для написания компонентов или использовать фреймворк для создания | лицом к будущему | Незрелый, нужно наступить на яму | 🌟🌟🌟 |
Выше приведено лишь краткое сравнение нескольких методов реализации. Конечно, эти решения не являются взаимоисключающими. Какое решение выбрать, зависит от вашего бизнес-сценария. Следующие предпосылки имеют решающее значение для выбора технологии:
- Является ли это монолитным приложением SPA?
- Является ли технологический стек унифицированным и нуждается ли он в поддержке межкадровых вызовов?
- Вам нужна полная изоляция между приложениями?
Мы — платформа SaaS корпоративного уровня. Это должно быть единое приложение SPA. Стек технологий полностью Angular. Нет необходимости в полной изоляции между приложениями. Вместо этого нам нужно использовать общие стили и компоненты, чтобы избежать повторной загрузки.
Итак, выбор:运行时组合
строить планы.
Путь выбора передовых технологий Worktile
В настоящее время на рынке не так много решений для микро-интерфейса, и следует выбрать то, которое обладает наивысшей степенью внимания и зрелости.single-spa
В Китае также есть много команд, у которых есть свои собственные микроинтерфейсные фреймворки, такие как единая спа-система с открытым исходным кодом.qiankun — возможно, самое полное решение для микроинтерфейса, которое вы когда-либо видели, и фодаляmooaИ бесчисленные внутренние решения (недавно Alifeibing также открыл исходный кодрешение микроинтерфейса icestark для больших рабочих столов, поддерживает только React и Vue)
Когда мы делаем технический выбор, первое соображениеsingle-spa
а такжеmooa
, single-spa
Зрелость должна быть наивысшей, типовая документация идеальна,mooa
Фреймворк микроинтерфейса master-slave, созданный для Angular, наиболее соответствует нашему бизнесу и технологиям.После периода исследований мы, наконец, решили разработать набор библиотек микроинтерфейса, которые соответствуют нашим собственным (потому что он относительно прост, я не осмеливаюсь назвать его фреймворком), в основном потому, что наш бизнес имеет следующие требования, которые не выполняются или трудновыполнимы в вышеуказанных фреймворках, и даже требуют высокой степени кастомизации.
- Продукт представляет собой структуру master-slave, а Portal включает в себя левую навигацию, уведомление о сообщениях и управление подприложениями.
- Необходимость связи между несколькими подприложениями, главное приложение или подприложение должны открыть страницу сведений или перейти по маршруту других подприложений.
- Определенная страница подприложения A может загружать компонент подприложения B.
- Основываясь на двух вышеуказанных характеристиках, необходимо обеспечить режим сосуществования, то есть, хотя в настоящее время отображается приложение B, необходимо обеспечить возможность нормального вызова приложения A. Если оно уничтожено, его нельзя вызвать другими приложениями.
- Требуется предварительная загрузка
- Стили подприложений также необходимо загружать независимо.
- Маршрутизация, будь то в основном приложении или подприложении, опыт маршрутизации должен соответствовать одному приложению.
я побежалsingle-spa
а такжеmooa
Примеры в основном представляют собой простые экраны рендеринга.Как только вам нужно будет соответствовать вышеуказанным характеристикам, вам все равно нужно будет изменить много вещей.mooa
Реализация должна быть более полной и подходящей для нас, но в ее примере есть некоторые проблемы с роутингом, страница прыгает, а роутинг не меняется, упаковка отказалась от Angular CLI, и ссылка на уровень кодаsingle-spa
API можно еще раз упростить.Поскольку он заточен под Angular, думаю, он должен больше соответствовать Angular.Конечно, не исключено, что автор захочет позже поддерживать React и Vue.Неоспорим тот факт, чтоphodal
Я хорошо разбираюсь в микро-фронтендах и написал много хороших статей о микро-фронтендах.microfrontends, и даже опубликовал единственную книгу по микро-фронтендам «Front-end Architecture — From Getting Started to Micro-frontends», я также использовал многие её идеи и методы реализации для справки при реализации микро-фронтендов.
Создание микрофронтенда с помощью Angular
Использование Angular для реализации микроинтерфейса на самом деле сложнее, чем React и Vue, потому что Angular включает компиляцию AOT, модуль, Zone.js, совместное использование сервисов и т. д. страница.
Выберите, следует ли компилировать или загружать все приложение после динамической загрузки модулей.
В монолитном приложении Angular должен быть корневой модуль AppModule, а затем каждый функциональный модуль FeatureModule, каждый функциональный модуль может иметь свою маршрутизацию, конечно, эти фич-модули можно загружать лениво с помощью роутинга, но в архитектуре микро-фронтенда , Каждый подмодуль хранится независимо, и то, как загрузить подмодуль в корневой модуль во время выполнения, представляет собой техническую сложность.
- Первое решение состоит в том, чтобы рассматривать каждый подмодуль как функциональный модуль, а затем упаковывать и компилировать его вместе с основным приложением при упаковке.Это самое простое, но это не может быть развернуто отдельно, и каждое развертывание представляет собой полное обновление.
- Второе решение состоит в том, чтобы рассматривать подмодуль как функциональный модуль, загружать подмодуль через SystemJsNgModuleLoader в основном приложении, а затем компилировать и запускать (Примечание: в новой версии от SystemJsNgModuleLoader отказались).
- Третье решение состоит в том, что каждый подмодуль является независимым приложением.Как и основное приложение, он имеет свой AppModule и маршрутизацию.При выборе этого решения необходимо решить проблему синхронизации маршрутизации нескольких приложений.Кроме того, текущая библиотека зависимостей Angular: Если ее нельзя использовать непосредственно во время выполнения, каждое подприложение необходимо скомпилировать вместе, и невозможно извлечь общедоступные библиотеки зависимостей (могут быть другие решения)
- Четвертый вариант — скомпилировать все подмодули в веб-компоненты для использования.Я давно не изучал его глубоко.Выбрать этот вариант для прямого использования компонентов точно не проблема, но я не знаю, как быть с маршрутизация после использования веб-компонентов.
В итоге мы выбрали самое сложное третье решение, так как новый движок рендеринга Ivy решит проблему прямого использования сторонних зависимых библиотек во время выполнения после официального релиза, а веб-компоненты мы подробно не изучали, т.к. третье решение в настоящее время хорошо работает.
Регистрация приложений, загрузка, механизм уничтожения
Это основа и ядро всех микро-фронтенд-приложений, но я думаю, что это самое простое и легкое в реализации.Главное, что нужно сделать, это:
- Обеспечьте функцию динамической загрузки статических ресурсов
-
Настройте правила субприложения, в том числе: имя приложения, префикс маршрутизации, файл статического ресурса.
this.planet.registerApps([ { name: 'app1', hostParent: '#app-host-container', routerPathPrefix: '/app1', selector: 'app1-root', scripts: ['/static/app1/main.js'], styles: ['/static/app1/styles.css'] }, // ... ]);
Загрузка приложения: найдите соответствующее подприложение в соответствии с URL-адресом текущей страницы, затем загрузите статические ресурсы приложения и вызовите предопределенную функцию запуска для непосредственного запуска приложения.В Angular это запуск корневого модуля.
platformBrowserDynamic().bootstrapModule(AppModule)
.- Предварительная загрузка приложения: другие приложения будут предварительно загружены после рендеринга и запуска текущего приложения и не будут отображаться.
- Уничтожить использование приложения
appModuleRef.destroy();
В основном достаточно иметь дело с простыми сценариями в соответствии с вышеуказанными шагами, но если вы хотите, чтобы приложения сосуществовали, это будет по-другому.bootstrapped
Государство скрыто, а не уничтожено, толькоActive
Статус заявки будет отображаться на текущей странице.
маршрутизация
Поскольку каждое подприложение выбирается как независимое приложение Angular, а несколько подприложений могут сосуществовать одновременно, синхронизация маршрутизации нескольких приложений и переходы становятся проблемой, и необходимо поддерживать переходы маршрутизации между приложениями и связью. между приложениями, рендеринг компонентов и другие сценарии. Я думаю, что маршрутизация — самая сложная проблема, с которой мы сталкиваемся в архитектуре микроинтерфейса.
В настоящее время наш подход заключается в настройке маршрутов всех подприложений в маршрутизации основного приложения, а компоненты настроены наEmptyComponent
, Таким образом, при переходе на маршрут подприложения основное приложение будет соответствовать состоянию пустого маршрута и не сообщит об ошибке Каждому подприложению необходимо добавить общий пустой маршрутEmptyComponent
{
path: '**',
component: EmptyComponent
}
Кроме того, также необходимо синхронно обновлять маршруты других приложений при переключении маршрутов, иначе текущий статус маршрутизации каждого приложения будет несогласованным, и при переключении произойдет неудачный переход.
- Когда основной маршрут приложения переключается, найдите все запущенные в данный момент подприложения, используйте
router.navigateByUrl
Синхронный прыжок - Когда маршрут подприложения переключается, основной маршрут приложения синхронизируется, и другие подмаршруты в состоянии запуска синхронизируются одновременно.
Я просмотрел множество фреймворков для микроинтерфейса, в том числеsingle-spa
, в основном маршрутизацией не занимаются, и разработчику полностью предоставлено заполнить дыру.single-spa
Пример Angular в основном уничтожает приложение Angular после переключения.Поскольку нет сосуществования, нет необходимости решать проблему маршрутизации нескольких приложений.Конечно, как независимое от фреймворка решение для микроинтерфейса, он может сделать только этот шаг , Бар.
После того, как движок рендеринга Ivy будет официально выпущен, подприложения могут быть скомпилированы в модули, которые можно запускать напрямую.Если все приложение имеет только один маршрут, это будет намного проще.
Общие глобальные сервисы
Для некоторых глобальных данных мы обычно храним их в сервисе, а затем подприложения могут делиться ими напрямую, например:当前登录用户
,多语言服务
И т. д., простой обмен данными можно монтировать прямо в окно.Чтобы каждое подприложение использовало один и тот же глобальный сервис и сервис в модуле, мы инстанцируем эти сервисы в основном приложении, но затем в AppModule каждого суб-приложение.Используйте предоставление для сброса значения основного приложения.Конечно, эти бизнес-разработчики, которым не нужно устанавливать субприложения самостоятельно, были инкапсулированы в библиотеке бизнес-компонентов и настроены глобально.
{
provide: AppContext,
useValue: window.portalAppContext
}
связь между приложениями
Существует много способов взаимодействия между приложениями, мы используем базовые возможности браузера.CustomEvent
, поверх этого инкапсулированногоGlobalEventDispatcher
Служба взаимодействует (конечно, вы также можете использовать ее для монтирования глобального объекта на объекте окна), сценарий заключается в том, что субприложение хочет открыть страницу сведений другого субприложения.
// App1
globalEventDispatcher.dispatch('open-task-detail', { taskId: 'xxx' });
// App2
globalEventDispatcher.register('open-task-detail').subscribe((payload) => {
// open dialog of task detail
});
Компоненты вызывают друг друга между приложениями
в нашем敏捷开发
В подпродукте должна отображаться страница сведений о пользовательской истории.测试管理
Связанные тестовые случаи и статус выполнения теста приложения, затем компонент списка тестовых случаев помещается в测试管理
подприложение является наиболее подходящим, тогда страница сведений о пользовательской истории должна быть в敏捷开发
Как загрузить в приложение测试管理
Определенный компонент приложения является проблемой.
Этот кусок используетсяAngular CDK 中的 DomPortalOutlet
Динамически создавать компоненты и указывать рендеринг в контейнере, что гарантирует, что создание этого динамического компонента все еще测试管理
Модули просто рендерятся в других приложениях.
const portalOutlet = new DomPortalOutlet(container, componentFactoryResolver, appRef, injector);
const testCasesPortalComponent = new ComponentPortal(TestCasesComponent, null);
portalOutlet.attachComponentPortal(testCasesPortalComponent);
Инжиниринг
Использование микроинтерфейса для разработки приложений должно решать не только технические проблемы Angular, но и некоторые инженерные проблемы, такие как разработка, совместная работа и развертывание, например:
- Извлечение общей библиотеки зависимостей
- Как начать разработку локально
- Как упаковать и развернуть и как уведомить основное приложение о сгенерированном файле хэш-ресурса
Применение извлечения общедоступной библиотеки зависимостей, чтобы избежать повторной упаковки библиотек классов и уменьшить объем упаковки, что требует реализации пользовательской конфигурации Webpack.Сначала мы полностью настроили Webpack для упаковки приложений Angular.Как только мы это сделаем, мы потеряем многие удобные функции, предоставляемые CLI , библиотека классовangular-builders, его роль на самом деле состоит в том, чтобы объединить пользовательскую конфигурацию Webpack с конфигурацией Webpack, сгенерированной Angular CLI, так что нужно написать лишь небольшое количество пользовательской конфигурации, а остальные по-прежнему используют функцию упаковки CLI, и почти должны напиши сам Аналогичный инструмент тоже.
Поместите необходимые публичные зависимости в основное приложениеscripts
, а затем настроить в подприложенииexternals
,Например:moment
lodash
rxjs
такая библиотека.
const webpackExtraConfig = {
optimization: {
runtimeChunk: false // 子应用一定要设置 false,否则会报错
},
externals: {
moment: 'moment',
lodash: '_',
rxjs: 'rxjs',
'rxjs/operators': 'rxjs.operators',
highcharts: 'Highcharts'
},
devtool: options.isDev ? 'eval-source-map' : '',
plugins: [new WebpackAssetsManifest()]
};
return webpackExtraConfig;
Основная функция WebpackAssetsManifest — генерироватьmanifest.json
файл, цель состоит в том, чтобы установить соответствующую связь между сгенерированным хэш-файлом и позволить основному приложению загрузить правильный файл ресурсов.
Конфигурация локальной разработкиproxy.conf.js
Прокси-доступ к файлам ресурсов каждого вложенного приложения, включая вызовы API.
Библиотека микрофронтенда на основе Angular ngx-planet
Выше приведены некоторые технические трудности и наши решения, с которыми мы столкнулись при использовании Angular для создания приложений микроинтерфейса.После исследований мы, наконец, решили разработать набор библиотек микроинтерфейса, которые соответствуют нашим бизнес-сценариям и были адаптированы только для Angular.
Адрес репозитория на гитхабе:ngx-planet
Онлайн-демонстрация:planet.ngnice.com
Не осмеливаюсь сказать "самое законченное решение для микро-интерфейса, которое вы когда-либо видели", но, по крайней мере, сообщество Angular видело решения, которые можно полноценно использовать в продакшн-средах.API соответствует Angular Style, и многие отечественные производители в основном игнорировали микроинтерфейсные решения.С существованием фреймворка Angular четыре подпродукта R&D Worktile полностью основаны наngx-planet
Строительство и развитие, после почти года хождения по яме и практики, в основном полностью доступны.
Я надеюсь, что у сообщества Angular будет больше решений для микроинтерфейса, и мы вместе добьемся прогресса. С нашим решением определенно много проблем. Мы также приветствуем ваши предложения и жалобы по улучшению. Мы также продолжим работу над микроинтерфейсом Angular. Ищете библиотеку микроинтерфейса для Angular, попробуйте ngx-planet.
В дальнейшем будем исследовать схемы оптимизации и улучшения под движок рендеринга Ivy.
Официальный сайт Worktile:worktile.com
Автор этой статьи: Сюй Хайфэн, старший инженер Worktile
Статья впервые появилась в "Официальный блог Worktile"Пожалуйста, укажите источник.