Практика микроинтерфейсных приложений на основе qiankun

внешний интерфейс
Практика микроинтерфейсных приложений на основе qiankun

Автор: Чжан Яньцин

бизнес фон

Платформа облачной музыкальной рекламы Dsp (платформа на стороне спроса) разделена на контрактную платформу (Vue framework) и торговую платформу (React framework).По историческим причинам выбор фреймворка не был унифицирован.В последнее время появились новые требования , и то же самое нужно добавить к двум платформам одновременно.Поскольку все они являются платформами DSP, на более позднем этапе может быть много таких требований, поэтому, учитывая повторное использование компонентов и снижение затрат на обслуживание, я думаю о том, как унифицировать стек технологий и подключить систему React к проекту Vue для презентации.

项目应用结构

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

Честно говоря, моей первой реакцией было вложение iframe, но каждый, кто использовал технологию iframe, знает ее боль:

  • Проблема со стеком истории браузера вперед/назад
    Неважно, как глубоко вы пробираетесь в iframe, если вы сделаете 10 000 шагов назад, опыт будет действительно неудобным.
  • связь приложения
    Иногда основное приложение может хотеть знать только параметры URL подсистемы, но приложение iframe отличается от своего источника, вам нужно подумать о других способах получения параметров, наиболее часто используемый из нихpostMessageохватывать
  • тайник
    iframeПосле того, как обновление приложения будет подключено к сети, откройте систему, и вы обнаружите, что система обращается к кешу для отображения старого контента, который необходимо решить с помощью временной метки или принудительно обновить.


Другой — использовать распределение MPA + маршрутизация.Когда пользователь обращается к странице, Nginx отвечает за распределение по различным бизнес-приложениям в соответствии с маршрутизацией, и каждое бизнес-приложение завершает сборку ресурсов и возвращает их в браузер.Этот метод требует интерфейс, навигация Все выглядит одинаково.

  • преимущество:
    • Многокадровая разработка;
    • Независимое развертывание и эксплуатация;
    • Полная изоляция между приложениями.
  • недостаток:
    • Плохой опыт, и каждое независимое приложение долго загружается;
    • Из-за полной изоляции общие места, такие как навигация и верхняя часть, сильно изменились, а возможность повторного использования стала очень плохой.


Есть также несколько основных микроинтерфейсных решений:


  • Режим док-станции: в основном на основе распределения маршрутов базовое приложение отслеживает маршруты и загружает различные приложения в соответствии с правилами маршрутизации, чтобы добиться разделения между приложениями.
  • EMP: Федерация модулей Webpack5, децентрализованное микроинтерфейсное решение, которое может легко реализовать совместное использование ресурсов и связь между приложениями на основе изоляции приложений;

В целом, iframe в основном используется для простых сторонних систем с низкими требованиями к производительности, MPA не может удовлетворить текущие потребности бизнеса с точки зрения затрат на внедрение и опыта, режим пьедестала и EMP являются хорошим выбором, поскольку qiankun присутствует в отрасли. широко используется и является зрелым, и, наконец, я выбрал qiankun

Цянькунь

qiankun(Qiankun) запускается Ant Financial на основеSingle-SpaВнедренная интерфейсная микросервисная структура по существу все ещераспределение маршрутовСервисная структура qiankun отличается от исходной схемы Single-Spa, которая использует JS Entry для загрузки подприложений, qiankun использует HTML Entry для замены и оптимизации.

JS Entryограничения на использование:

  • Ограничьте один файл записи JS
  • Статические ресурсы, такие как изображения и CSS, должны быть упакованы в JS.
  • Разделение кода не применяется


По сравнению с JS Entry, HTML Entry намного удобнее в использовании.После того, как проект настроен с заданным файлом ввода, qiankun самостоятельно извлекает ресурсы запроса, анализирует файловые ресурсы JS и CSS и вставляет их в заданный контейнер, идеально ~

HTML Entry

Способ JS Entry обычно заключается в том, что подприложения вводят ресурсы в Entry Script, подобно Single-Spa.пример;

HTML Entry использует формат HTML для организации ресурсов подприложения.Основное приложение получает статические ресурсы подприложения через Fetch html, и в то же время HTML-документ вставляется в контейнер основного приложения как дочерний узел. . Он более удобен для чтения и сопровождения, ближе к эффекту после монтирования последней страницы, и нет проблем с двунаправленным экранированием.

программная практика

Поскольку проект Vue разработан, нам необходимо преобразовать его в исходный проект. Очевидно, что проект Vue выбран в качестве базового приложения. Для разработки новых требований используется Create React App для создания подприложений React. Далее давайте взгляните на конкретную реализацию.

Модификация базового приложения

База (основная) построена с помощью vue-cli. Мы сохраняем ее первоначальную структуру кода и логику без изменений. На этой основе мы предоставляем смонтированный DIV-контейнер для под-приложения, который также заполняется в той же области отображения контента.

qiankun нужно только ввести в базовое приложение.Для удобства управления мы добавляем новый каталог и называем его микро.Идентификационный каталог содержит код преобразования микро-интерфейса для инициализации глобальной конфигурации.Преобразование выглядит следующим образом :

Файл конфигурации маршрутизации app.js

// 路由配置
const apps = [
  {
    name: 'ReactMicroApp',
    entry: '//localhost:10100',
    container: '#frame',
    activeRule: '/react'
  }
];

Функция регистрации конфигурации приложения

import { registerMicroApps, start } from "qiankun";
import apps from "./apps";

// 注册子应用函数,包装成高阶函数,方便后期如果有参数注入修改app配置
export const registerApp = () => registerMicroApps(apps);

// 导出 qiankun 的启动函数
export default start;

Компонент макета

<section class="app-main">
  <transition v-show="$route.name" name="fade-transform" mode="out-in">
    <!-- 主应用渲染区,用于挂载主应用路由触发的组件 -->
    <router-view />
  </transition>

  <!-- 子应用渲染区,用于挂载子应用节点 -->
  <div id="frame" />
</section>
import startQiankun, { registerApp } from "../../../micro";
export default {
  name: "AppMain",
  mounted() {
    // 初始化配置
    registerApp();
    startQiankun();
  },
};

Здесь будут использоваться два важных API qiankun:

  • registerMicroApps
  • start

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

Давайте разберемся с процессом регистрации субприложений qiankun на схеме:启动流程图

  • После внедрения зависимости сначала будет инициализирован параметр идентификационной переменной.xx_QIANKUN__, который используется подприложением для оценки среды и т. д.
  • когда цянькунь пройдетactiveRuleправила, чтобы определить, следует ли активировать субприложение
    • activeRuleКогда это строка, она будет перехвачена автономно перехватом маршрутизации.
    • activeRuleКогда это функция, судите, активировать ее или нет, в соответствии с возвращаемым значением функции.
  • Когда суб-приложение активировано, адрес статического ресурса суб-приложения будет проанализирован через HTML-Entry и смонтирован в соответствующем контейнере.
  • Создайте среду песочницы, найдите функции жизненного цикла подприложений и инициализируйте подприложения.

Создайте субприложение qiankun

Мы создаем приложение проекта React на основе Create React App, Из приведенного выше описания процесса мы знаем, что подприложение должно предоставить ряд функций жизненного цикла для вызова qiankun и изменить его в файле index.js:

Добавьте файл public-path.js

Добавьте внешний слой каталогаpublic-path.jsфайл, когда суб-приложение монтируется под основное приложение, если какие-то наши статические ресурсы наследуютсяpublicPath=/конфигурации, доменное имя, которое мы получим, будет основным доменным именем приложения, что вызовет ошибки загрузки ресурсов.К счастью, Webpack предоставляет метод модификации следующим образом:

if (window.__POWERED_BY_QIANKUN__) {
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}

настройки базы маршрутов

Потому что, как правило, основное приложение перехватывает изменения маршрутизации браузера, чтобы активировать загрузку подприложений. Например, в приведенном выше коде прописаны наша конфигурация маршрутизации и правила активации.activeRule: /react,Что это значит? Это означает, что когда браузерpathnameсоответствовать/react, субприложение будет активировано, но если наша конфигурация маршрутизации субприложения выглядит следующим образом:

<Router>     
  <Route exact path="/" component={Home} />
  <Route path="/list" component={List} />  
</Router>      

Как мы реализуем доменные имена/reactМогут ли соответствующие компоненты быть загружены правильно? Вы, должно быть, испытали необходимость доступа к вторичному каталогу доменного имени. Здесь то же самое. Мы можем судить, находится ли он в среде qiankun, и настроить базу следующим образом:

const BASE_NAME = window.__POWERED_BY_QIANKUN__ ? "/react" : "";
...
<Router base={BASE_NAME}>
...
</Router>     

добавить функцию жизненного цикла

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

/**
 * bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap。
 * 通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等。
 */
export async function bootstrap() {
  console.log("bootstraped");
}

/**
 * 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
 */
export async function mount(props) {
  console.log("mount", props);
  render(props);
}

/**
 * 应用每次切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例
 */
export async function unmount() {
  console.log("unmount");
  ReactDOM.unmountComponentAtNode(document.getElementById("root"));
}

Примечание. Все функции цикла рождения должны быть обещаны.

Изменить конфигурацию упаковки

module.exports = {
  webpack: (config) => {
    // 微应用的包名,这里与主应用中注册的微应用名称一致
    config.output.library = `ReactMicroApp`;
    // 将你的 library 暴露为所有的模块定义下都可运行的方式
    config.output.libraryTarget = "umd";
    // 按需加载相关,设置为 webpackJsonp_ReactMicroApp 即可
    config.output.jsonpFunction = `webpackJsonp_ReactMicroApp`;

    config.resolve.alias = {
      ...config.resolve.alias,
      "@": path.resolve(__dirname, "src"),
    };
    return config;
  },

  devServer: function (configFunction) {
    return function (proxy, allowedHost) {
      const config = configFunction(proxy, allowedHost);
      // 关闭主机检查,使微应用可以被 fetch
      config.disableHostCheck = true;
      // 配置跨域请求头,解决开发环境的跨域问题
      config.headers = {
        "Access-Control-Allow-Origin": "*",
      };
      // 配置 history 模式
      config.historyApiFallback = true;

      return config;
    };
  },
};

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

  • жизненный цикл воздействия: UMD позволяет qiankun сопоставлять функции жизненного цикла по имени приложения.
  • Междоменная конфигурация: основное приложение получает ресурсы через Fetch, поэтому для решения междоменной проблемы необходимо разрешить междоменный доступ.

Резюме: упорядочите процесс перехода, определите путь перехода подприложения в маршрутизаторе основного приложения, как показано на рисунке ниже, используйте qiankun, чтобы раскрыть смонтированный жизненный цикл вызывающего компонента.loadMicroAppМетод загружает субприложение, переходит к маршруту, определенному субприложением, и используетaddGlobalUncaughtErrorHandlerа такжеremoveGlobalUncaughtErrorHandlerОтслеживайте и обрабатывайте исключения (например, сбой при загрузке субприложения) и загружайте субприложение, когда субприложение прослушивает маршрут перехода (выше<Router>Компонент, определенный в компоненте, завершает переход от основного приложения к подприложению.

{
    path: '/xxx',
    component: Layout,
    children: [
      {
        path: '/xxx',
        component: () => import('@/micro/app/react'),
        meta: { title: 'xxx', icon: 'user' }
      }
    ]
  },

Проблемы, возникшие в проекте

1,Подпрограмма не загрузилась успешно

Если система подприложения не загружается после запуска проекта, мы должны открыть консоль, чтобы проанализировать причину:

  • В консоли нет ошибки: подпрограмма не активирована, проверьте правильно ли настроены правила активации
  • Контейнер монтирования не найден: проверьте, находится ли контейнер DIV в qiankun.startОн должен существовать, если его нельзя гарантировать, его необходимо выполнить после монтирования DOM.


2,Режим маршрутизации приложения Dock

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

3.Беспорядок в стиле CSS

Поскольку qiankun по умолчанию не включает песочницу CSS для изоляции стилей, когда основное приложение и подприложения создают путаницу стилей, мы можем включить{ strictStyleIsolation: true }Настройте, чтобы включить строгий стиль изоляции. В настоящее время субприложение будет обернуто узлом Shadow Dom. Я думаю, что все знакомы с этим, и это согласуется со схемой изоляции страниц и пользовательских компонентов стиля в апплете WeChat.

4.Кроме того, в процессе доступа суммируются несколько моментов, требующих внимания.

  • Хотя qiankun поддерживает jQuery, он не очень удобен для доступа к старым проектам многостраничных приложений, каждую страницу необходимо модифицировать, а стоимость также высока.Iframe рекомендуется для доступа к таким старым проектам;
  • Поскольку метод qiankun извлекает JS-файлы и структуры DOM через HTML-Entry, он фактически совместно использует один и тот же документ с основным приложением.Если подприложение и основное приложение определяют одни и те же события одновременно, они будут влиять друг на друга. Например, используяonClickилиaddEventListenerДать<body>Добавляя событие клика, песочница JS не может устранить его влияние, приходится полагаться на обычную спецификацию кода.
  • Развертывание немного громоздко, и междоменные проблемы необходимо решать вручную.


5.Некоторые вопросы, возможно, потребуется рассмотреть в будущем

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

Суммировать

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

Если есть проблемы или ошибки в статье, пожалуйста, исправьте и обменяйте, спасибо!

Эта статья была опубликована сКоманда внешнего интерфейса NetEase Cloud Music, Любое несанкционированное воспроизведение статьи запрещено. Мы набираем front-end, iOS и Android круглый год.Если вы готовы сменить работу и любите облачную музыку, присоединяйтесь к нам на grp.music-fe(at)corp.netease.com!