Практика микрофронтенда

Микросервисы

При разработке интерфейса toB мы часто сталкиваемся со следующими дилеммами:

  1. Проект становится все больше и больше, а упаковка все медленнее и медленнее
  2. В команде много членов, функции продукта сложны, конфликты кода часты, а влияние велико.
  3. Я хочу делать продукты SaaS в своем сердце, но клиенты всегда хотят настраивать

У разных команд могут быть разные подходы к решению этих проблем. Сегодня, с бурным развитием front-end разработки и бурным развитием front-end инжиниринга, я хотел бы представить еще одну попытку — микро-front-end.

Что такое микрофронтенд

Так что же такое микро-фронтенд? Микро-интерфейс в основном опирается на концепцию внутренних микросервисов. Проще говоря, это разделение внешнего проекта монолита на небольшие проекты один за другим. Не стоит недооценивать эти маленькие проекты, они тоже «воробьи маленькие, но у них есть все внутренние органы», и они вполне способны к самостоятельной разработке и эксплуатации. Эти небольшие проекты будут координировать всю систему для реализации отображения и взаимодействия всех страниц.

Это можно понять в отличие от микросервисов:

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

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

Зачем использовать микрофронтенды

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

Во-первых, это скорость упаковки. Шесть месяцев назад наш бисайд-проект был еще монолитом. На тот момент было более 20 зависимостей, более 60 общедоступных компонентов, более 200 страниц и более 700 интерфейсов. Мы использовали Webpack 2 с подключаемым модулем DLL, включенным HappyPack 4. Компиляция с 4 потоками на моем личном хосте занимает около 5 минут. И если его не разделить, у нас сейчас почти 400 страниц и более 1000 интерфейсов.
Что означает это время? Это не только отнимает время у разработчиков, но и влияет на эффективность всей команды. Когда он выйдет в онлайн, в Docker, CI и других средах, затраты времени будут увеличены. Если после деплоя будет несколько багов, и их нужно исправлять онлайн сразу, то я не знаю, сколько это продлится.
После использования преобразования микро-интерфейса у нас в настоящее время есть 26 проектов микро-интерфейса, а среднее время упаковки составляет 30-45 секунд (обратите внимание, что DLL + HappyPack здесь не применялись).

На самом деле на скорость загрузки страницы сильно не влияет, т.к. после CDN и gzip размер ресурсов приемлемый. Я просто хочу показать вам некоторые интуитивные изменения данных. Полгода назад упакованный app.js весил 5 МБ (1 МБ после gzip), vendor.js — 2 МБ (700 КБ после gzip) и app.css — 1,5 МБ (250 КБ после gzip). Таким образом, первый экран будет передавать около 2 МБ контента. После разделения для первого экрана в настоящее время необходимо передать только около 800 КБ.

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

Тогда есть настройка. То, что мы делаем, является продуктом toB, и, вероятно, все практики хотят сделать стандартную версию продукта SaaS. Однако из-за ограничений общей рыночной среды и функций продукта некоторые клиенты часто сталкиваются с требованиями локализации и настройки. Локализация будет иметь соображения безопасности кода: лучше всего не давать клиентам исходный код, а худшее — покупать только исходный код функции для заказчика. От простого к сложному, настройку можно разделить на независимые новые модули, преобразование существующих модулей и замену существующих модулей.
С помощью технологии микроинтерфейса мы можем легко достичь нижнего предела безопасности локализованного кода — предоставить клиенту только внешний исходный код модуля, который он приобрел. Самый простой самостоятельный новый модуль в кастомизации тоже стал простым: команда доставки может добавить новый проект микро-фронтенда, и его не нужно включать в существующий проект НИОКР и не занимает ресурсы команды НИОКР. Преобразование существующих модулей в кастомизацию также может быть реализовано лучше: например, если на стандартную страницу нужно добавить панель, новый проект микроинтерфейса тоже может реагировать на URL-адрес страницы (конечно, он должен контролироваться в порядке), вставьте новый узел DOM в соответствующее место на странице.

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

другие цели

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

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

Как модифицировать существующий проект

«Разговоры дешевы, покажите мне код». Давайте посмотрим на конкретное преобразование ниже! Наши микро-интерфейсные проекты можно разделить на портальные проекты, бизнес-проекты и общие проекты.

портальная инженерия

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

// 业务工程的名称
customer: {
    // URL 匹配模式
    matchUrlHash: ['^/customer'],
    // 微前端地址
    target: 'http://localhost:8101/mfe-customer/index.html',
    // 资源匹配模式
    resourcePatterns: ['/app.*.css$', '/vendor.*.css$', '/manifest.*.js$', '/vendor.*.js$', '/app.*.js$'],
}

Портал будет периодически, асинхронно и параллельно загружать ресурсы бизнес-проектов и регистрировать их, в это время эти бизнес-проекты не будут загружены. Причина, по которой нам нужны адрес (target) и ресурс (resourcePatterns) бизнес-проекта, заключается в том, чтобы точно знать путь к ресурсам, таким как app.js, vendor.js, app.css и другим ресурсам, которые он содержит, при загрузке. . Потому что каждый раз, когда бизнес-проект изменяется, пути к ресурсам, такие как app.js, будут иметь новые хэш-значения содержимого файла (Hash), что приводит к непредсказуемым путям. И его index.html Путь фиксирован. Мы читаем HTML, анализируем его содержимое и сопоставляем путь к таким ресурсам, как app.js, с помощью регулярных выражений.

Когда портал работает, он будет прослушивать изменения URL. В настоящее время мы поддерживаем только хэш URL (например, #/customer). Когда Hash изменяется, он соответствует бизнес-проекту, а затем выполняет работу по выгрузке и загрузке. Этот механизм в основном используетsingle-spaдостичь, но принцип так прост.

import { registerApplication } from 'single-spa';
registerApplication('customer', 
    // 下载微前端工程,获取三个函数钩子:bootstrap、mount、unmount
    () => {
        const html = fetch(mfeConfig.target);
        const {cssUrls, jsUrls} = match(html, mfeConfig.resourcePatterns);
        loadCss(cssUrls);
        loadJs(jsUrls);
        return windows['mfe:customer'];
    },
    // 对当前浏览器 URL Hash 进行匹配,如果匹配(返回 true),则加载该微前端(调用 mount);否则卸载(调用 unmount)
    () => {
        return match(window.location.hash, mfeConfig.matchUrlHash);
    },
    mfeConfig.customProps
);

бизнес инжиниринг

Бизнес-проект — это обычный микро-интерфейсный проект, обычно один модуль на проект. У бизнес-проекта есть две роли: одна — интерфейсный проект, который может выполняться независимо, а другая — среда выполнения, управляемая порталом. Первый в основном используется для нашей локальной разработки, а второй — для онлайн-интеграции. При самостоятельной работе он ничем не отличается от исходного фронтенд-проекта. Возьмите в качестве примера проект Vue, по-прежнему используйтеnew Vue({el: '#app'})для запуска и отображения страницы.

new Vue({
    el: '#app',
    i18n,
    router,
    store,
    template: '<App/>',
    components: { App }
});

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

if(!window.IS_IN_MFE){ // 独立运行时
    new Vue({...})
} else { // 受控运行时
    module.exports = {
        bootstrap(){ // 注册时执行
        },
        mount(customProps){ // 加载时执行
            return Promise.resolve().then(()=>{
            instance = new Vue({...})
            })
        },
        unmount(){ // 卸载时执行
            return Promise.resolve().then(()=>{
            instance.$destroy()
            })
        }
    }
}

Конфигурация Webpack для онлайн-среды:

output: {
    libraryTarget: "umd",
    library: 'mfe:customer'
}

Чтобы определить, контролируется он или нет, это можно сделать, оценив глобальную переменную. Такие какwindow.IS_IN_MFE, проект портала установит его вtrue.

Чтобы поддерживать одновременную разработку нескольких локальных проектов, нам необходимо указать определенный и эксклюзивный номер порта для каждого проекта микроинтерфейса. Например, начните с 8100 и увеличивайте по одному. В то же время для поддержки онлайн-развертывания нам также необходимо указать определенный и эксклюзивный базовый путь (префикс) для каждого проекта микроинтерфейса. Таким образом, разные пути могут использоваться для независимого доступа под одним и тем же доменным именем. Путь един с/mfe-начать, как/mfe-customer. Это то, что показано в примере конфигурации бизнес-проекта на портале выше.

Специальная бизнес-инжиниринг: mfe-navs

Структура страницы нашего продукта разделена на три части: верхняя панель, боковая панель и средняя область содержимого. Верхняя панель и боковая панель остаются в основном неизменными во время процесса перехода на страницу. Поэтому мы также выделяем их как независимый микро-интерфейсный бизнес-проект под названиемmfe-navs. Он будет соответствовать всем URL-адресам, а это означает, что при посещении любого URL-адреса он будет загружен и гарантированно будет загружен первым. Когда он загружается, он предоставляет привязку DOM для области промежуточного содержимого на странице (#app:) для монтирования при загрузке других бизнес-проектов.

Общая инженерия

Как вы можете видеть выше, каждый бизнес-проект — это независимый интерфейсный проект, поэтому будут одни и те же зависимости, такие как Vue, moment, lodash и т. д. Если это содержимое упаковано в собственный файл vendor.js, это неизбежно приведет к слишком большой избыточности кода и увеличению нагрузки на память при работе браузера. Мы помещаем эти общедоступные зависимости, общедоступные компоненты, CSS, шрифты и т. д. в проект, который упаковывается проектом, экспортируя зависимости и компоненты и внедряя их в глобальную в виде UMD.

основной.js:

import Vue from 'vue'; // 公共依赖
import VueRouter from 'vue-router';
import VueI18n from 'vue-i18n';
import '@/css/icon-font/iconfont.css';
import ContentSelector from '@/components/ContentSelector'; // 公共组件

Vue.use(VueI18n); // 大家都要这么做,我们就代劳吧!

module.exports = {
    'vue': Vue,
    'vue-router': VueRouter,
    'content-selector': ContentSelector,
};

Конфигурация веб-пакета:

output: {
    libraryTarget: "umd",
    library: 'mfe:common'
}

Бизнес-проекты внедряются в проект через внешние зависимости Webpack (внешние). Таким образом, эти общедоступные коды не будут включены при упаковке бизнес-проекта.

var externalModules = ['vue', 'vue-router', 'content-selector'];

module.exports = { // webpack 配置项
    // ...
    externals: (context, request, callback)=>{
        if(externalModules.includes(request)){
            callback(null, 'root window["mfe:common"]["'+request+'"]')
        } else {
            callback();
        }
    },
}

Эпилог

Вышеизложенное — это часть нашего опыта в трансформации и практике микро-фронтенда. Впереди долгий путь, и есть еще много областей, требующих улучшения, таких как поддержка режима истории, лучшая интеграция i18n, оптимизация порядка загрузки и персонализация различных бизнес-проектов и т. д. В дополнение к этим чисто техническим исследованиям, на основе наличия микроинтерфейсов и микросервисов, команда также может рассмотреть возможность вертикального разделения: группа самостоятельно отвечает за часть бизнеса, и у нее есть собственная разработка микроинтерфейса и разработка микросервисов. . Объединение их в единое целое, от технического управления до управления персоналом, также является направлением исследований нашей разработки программного обеспечения. Надеюсь, что они могут принести вам некоторые мысли и помощь!