Давайте вместе создадим приложение с микро-интерфейсом

В этой статье я расскажу, как реализовать приложение с микро-интерфейсом с единой спа-системой и федерацией модулей в Webpack.

Пример репозитория

Вот окончательная база кода на GitHub:



СОДЕРЖАНИЕ

Микро-фронтенды

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

Это позволяет вам:

  • Развернуть самостоятельно
  • Используйте несколько UI-фреймворков (React, Vue.js и Angular) в одном месте
  • Отделите часть компонентов пользовательского интерфейса от большой кодовой базы

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

одноместный спа

Single-spa - это фреймворк, который позволяет легко настраивать внешнее микро-приложение.

Абстрагируя жизненные циклы для всего приложения, single-spa позволяет использовать несколько фреймворков пользовательского интерфейса на одной странице.

Это также дает возможность:

  • Развернуть самостоятельно
  • Выполнить отложенную загрузку
  • Внедрение новых фреймворков без каких-либо изменений для существующего приложения

С single-spa у вас есть два варианта выбора экосистемы для совместного использования зависимостей:

Идея карт импорта состоит в том, чтобы сопоставить URL-адрес инструкции импорта JavaScript с библиотеками. Например, если вы импортируете moment в свой код,

import moment from "moment";

Вам нужно будет предоставить браузеру следующие карты:

<script type="importmap">
{
  "imports": {
    "moment": "/node_modules/moment/src/moment.js"
  }
}
</script>

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

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

Но мы не будем использовать это в нашем приложении. Вместо этого мы воспользуемся преимуществами новой технологии в Webpack 5.

Объединение модулей в Webpack

Модульная федерация была введена в Webpack 5. Его основная цель - совместное использование кода и библиотек между приложениями.

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

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

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

Целью объединения модулей является совместное использование кода JavaScript между приложениями, а не пользовательского интерфейса. Итак, общий код можно использовать в приложении.

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

Обзор приложения

К настоящему времени мы рассмотрели основную идею микро-интерфейсов и объединения модулей.

Далее мы рассмотрим реализацию простого демонстрационного приложения, чтобы понять, как они работают вместе.

Давайте посмотрим, что составляет приложение:

  • Домашнее приложение, которое обрабатывает все приложения микро-интерфейса.
  • Приложение для навигации, которое показывает пользовательский интерфейс верхнего и нижнего колонтитула, созданный React.
  • Приложение тела, которое показывает элемент тела страницы, созданной Vue.js.

Настроить Root package.json

Перед реализацией приложения с микро-интерфейсом мы создаем package.json в корне. Три приложения включены в одно репо как монорепозиторий, поэтому мы будем использовать пряжу, чтобы делиться некоторыми пакетами во всем приложении.

Создайте package.json в корневом каталоге, например:

Затем установите зависимости.

yarn

Домашнее приложение

Затем мы создаем домашнее приложение, которое координирует каждое микро-интерфейсное приложение. Домашняя страница обрабатывает задачу, которая отображает HTML-страницу и JavaScript, который регистрирует приложения.

Давайте посмотрим на структуру дома:

├── packages
│   └── home
│       ├── package.json
│       ├── public
│       │   └── index.html
│       ├── src
│       │   └── index.ts
│       ├── tsconfig.json
│       └── webpack.config.js

Затем мы шаг за шагом создаем эти файлы.

Сначала создайте package.json:

И создайте webpack.config.js:

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

Чтобы понять, как это работает, мы рассмотрим три основных концепции.

пульты

Поля remotes принимают имя федеративного приложения микро-интерфейса, которое будет использовать код. В этом случае домашнее приложение будет использовать приложение для навигации и приложение для тела, поэтому нам нужно указать их имена в поле remotes, например:

remotes: {
  navigation: 'navigation',
  body: 'body',
},

Мы рассмотрим гораздо больше деталей при реализации приложения для навигации и тела.

разоблачает

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

exposes: {
  Button: './src/Button',
},

общий

Это shared список всех зависимостей, используемых для поддержки экспортируемых файлов. Например, если вы экспортируете компонент Vue.js, вам нужно будет указать vue в общем разделе, например:

shared: ['vue'],

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

Далее мы создадим public/index.html:

И создайте src/index.ts:

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

Приложение для навигации

Теперь, когда мы настроили домашнее приложение, давайте реализуем приложение для навигации.

Вот структура приложения для навигации:

├── packages
│   ├── home
│   │   ├── package.json
│   │   ├── public
│   │   │   └── index.html
│   │   ├── src
│   │   │   └── index.ts
│   │   ├── tsconfig.json
│   │   └── webpack.config.js
│   └── navigation
│       ├── package.json
│       ├── src
│       │   ├── Footer.tsx
│       │   ├── Header.tsx
│       │   └── index.ts
│       ├── tsconfig.json
│       ├── webpack.config.js

Мы экспортируем компоненты Footer и Header в домашнее приложение.

Для этого мы сначала создаем эти файлы. Создайте navigation/package.json:

Приложение для навигации будет создано React, поэтому установите зависимости и создайте navigation/webpack.config.js:

Обратите внимание на publicPath и ModuleFederationPlugin.

publicPath - это базовое имя удаленного URL-адреса, которое будет использоваться в домашнем приложении. В этом случае приложение для навигации будет обслуживаться по адресу http://localshot:3001.

Поле exposes принимает два компонента: Header и Footer. Это экспортирует их в домашнее приложение.

Как указывалось ранее, нам нужно будет указать общие библиотеки в разделе shared. В этом случае нам нужно написать react, react-dom и single-spa-react.

Затем создайте src/Header.tsx и src/Footer.tsx:

Зарегистрируйте приложение для навигации

Теперь мы готовы начать экспорт навигационного приложения.

Далее регистрируем его в домашнем приложении. Чтобы зарегистрировать приложение микро-фронтендов, необходимо выполнить следующие действия:

  • Включить тег скрипта
  • Список в пультах
  • Добавить регистрацию
  • Включите контейнер div

Давайте пройдемся по этим шагам.

Включить тег скрипта

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

Перейдите к home/public/index.html и включите тег скрипта.

<!DOCTYPE html>
<html lang="en">
<head>
    <script src="http://localhost:3001/remoteEntry.js"></script>
    ...
</head>

Как указывалось ранее, publicPath навигационного приложения - http://localhost:3001, а имя файла - remoteEntry.js.

Список в пультах

Далее перейдите к home/webpack.config.js и укажите раздел пультов:

remotes: {
  home-nav: 'navigation',
},

navigation - это имя конфигурации в navigation/webpack.config.js:

plugins: [
  new ModuleFederationPlugin({
    name: 'navigation',
    library: { type: 'var', name: 'navigation' },
    filename: 'remoteEntry.js',
    remotes: {},
    exposes: {
      Header: './src/Header',
      Footer: './src/Footer',
    },
    shared: ['react', 'react-dom', 'single-spa-react'],
  }),
],

home-nav - это имя, используемое в домашнем приложении.

Вы можете изменить имя импорта, изменив ключ на все, что захотите.

Добавить регистрацию

Далее регистрируем приложение для навигации в home/src/index.ts:

registerApplication принимает три вещи:

  • Название приложения
  • Функция для загрузки кода приложения
  • Функция, определяющая, активно или неактивно приложение.

Функция импорта указывает имя ключа remotes, как указано выше.

() => import('home-nav/Header'),

Включите контейнер div

Наконец, мы пишем контейнер div, который используется для включения компонентов Header и Footer.

Перейдите к home/public/index.html и добавьте их:

По умолчанию, без опции, single-spa найдет single-spa-application:{app name} и отобразит HTML-код ниже.

В этом случае мы уже зарегистрировали Header и Footer как header и footer, поэтому он найдет идентификаторы single-spa-application:header и single-spa-application:footer.

Давай попробуем это.

Перед этим обязательно установите зависимости:

yarn

И запускаем сервер в корне:

yarn start

Итак, перейдите по адресу http: // localhost: 3000, и вы обнаружите, что два компонента React успешно отрисованы.

Вроде хорошо работает.

Приложение для тела

Далее мы создадим приложение для тела. Приложение body будет создано на Vue.js, но процесс реализации будет почти таким же, как и в приложении для навигации.

Давай сделаем это быстро.

Структура приложения body:

├── packages
│   ├── body
│   │   ├── package.json
│   │   ├── src
│   │   │   ├── App.vue
│   │   │   ├── app.js
│   │   │   └── index.js
│   │   ├── tsconfig.json
│   │   └── webpack.config.js

Создайте body/package.json:

И создайте body/webpack.config.js:

Создайте body/src/App.vue и body/src/app.js:

Зарегистрируйте приложение Body

Затем мы зарегистрируем тело в домашнем приложении, как мы делали это раньше для навигации.

Перейдите к home/public/index.html и добавьте тег скрипта:

<head>
    <script src="http://localhost:3001/remoteEntry.js"></script>
    <script src="http://localhost:3002/remoteEntry.js"></script>
    ...
</head>

Затем перейдите к home/webpack.config.js и добавьте home-body:

remotes: {
  'home-nav': 'navigation',
  'home-body': 'body',
},

Затем перейдите на home/src/index.ts, чтобы зарегистрировать его:

Наконец, добавьте контейнер div для этого в home/public/index.html:

Давай проверим это.

Запустить установочные зависимости:

yarn

И запускаем сервер в корне:

yarn start

Перейдите по адресу http: // localhost: 3000:

Отлично - вы видите, что компонент Vue успешно отрисован.

Заключение

В этой статье мы рассмотрели, как реализовать приложение с микро-интерфейсом, используя Single SPA и Module Federation в Webpack.

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

Хотя есть и недостатки, такие как сложность конфигурации и затраты на обучение, я думаю, что указанные выше преимущества перевешивают недостатки.

Надеюсь, эта статья заинтересовала вас микро-интерфейсами!