Практика микро-интерфейса на вынос Meituan

внешний интерфейс
Практика микро-интерфейса на вынос Meituan

задний план

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

  • Система ПК: система доставки в один магазин ПК-терминал
  • Система H5: система доставки в один магазин, конец H5
  • Система KA: ПК-терминал системы доставки в несколько магазинов

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

  • Сторона ПК и сторона H5 имеют одну и ту же бизнес-линию.Основная бизнес-логика непротиворечива, пользовательский интерфейс очень отличается.
  • Сторона ПК и сторона КА имеют одну и ту же бизнес-линию.Часть бизнес-логики непротиворечива, разница в пользовательском интерфейсе небольшая.

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

  • как действоватьМультиплексирование на физическом уровне(коды на разных концах находятся в репозиториях Git по разным адресам).
  • как действоватьПовторное использование логического уровня(Как одна и та же логика с разных сторон может быть абстрагирована одним кодом).

Здесь мы сосредоточимся на повторном использовании на физическом уровне, то есть: как внедрить независимые трехтерминальные системы (разные склады) в наш уровень повторного использования в физическом пространстве? Мы попробовали пакеты NPM, поддерево Git и другие методы «общих файлов» и обнаружили, что наиболее эффективным методом повторного использования является размещение трех систем в одном хранилище для устранения изоляции в физическом пространстве, а не подключение разных физических пространств. Конечно, технологический стек нашей трехтерминальной системы такой же, поэтому мы выполнили преобразование, как показано ниже:

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

  • Новые линейки бизнес-продуктов быстро растут.В то же время, чтобы максимизировать эффективность повторного использования трехтерминальной системы, файлы помещаются в одно и то же хранилище для управления, что приводит к чрезвычайно быстрому увеличению количества файлов и растущие трудности в управлении и совместном развитии.
  • Чем больше и больше файлов, тем более неконтролируемой является файловая структура, тем сложнее становится решение для развития бизнеса.
  • С увеличением количества файлов скорость разработки, сборки и развертывания становится все медленнее и медленнее, а качество разработки продолжает снижаться.
  • Физической изоляции между различными направлениями бизнеса нет, и перекрестные направления бизнеса путают друг друга. Например, компонент с названием направления бизнеса Б появляется в направлении бизнеса А.

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

анализ спроса

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

точка спроса Преимущества и требования
Развязка (1) Он разделен на разные склады для обслуживания в соответствии с областями бизнеса Разработчики разных направлений бизнеса более независимы, и разные направления бизнеса не влияют друг на друга. (2) Физический уровень разделен, адресация ускорена, а новые функции и ошибки могут быть изменены быстрее. (3) Логический уровень разделен, чтобы предотвратить путаницу в ссылках, и не будет ситуации, когда бизнес-линия A ссылается на B компоненты бизнес-линии.
Ускорьте опыт (1) Быстрый запуск среды разработки для улучшения опыта разработки. (2) Бизнес-направление упаковывается по запросу, быстро развертывается и запускается.
менее инвазивный Решение с микроинтерфейсом сводит к минимуму инвазивность изменения исходного кода, не требует крупномасштабной трансформации и снижает или даже устраняет затраты на регрессионное тестирование.
низкая стоимость обучения Разработчикам не нужно осознавать наличие разделений, поддерживать опыт разработки одностраничных приложений и не нужно изучать дополнительные правила.
Единый стек технологий В целях унификации совместного строительства и осаждения технологий проекты внутри команды объединены в стек технологий React, а использование разных стеков технологий для разработки запрещено.

выбор плана

После приведенного выше анализа спроса мы исследовали микроинтерфейсные решения в отрасли и в компании и резюмировали следующие решения и их основные характеристики:

  • NPM-стиль: Подпроекты выпускают исходный код в виде пакетов NPM; упакованные выпуски сборок по-прежнему управляются базовым проектом и интегрируются во время упаковки.
  • iframe: подпроекты могут использовать разные технологические стеки; подпроекты полностью независимы без каких-либо зависимостей; базовые проекты и подпроекты должны установить механизм связи; нет одностраничного приложения; управление адресами маршрутизации затруднено.
  • Универсальный центральный пьедестал: Подпроекты могут использовать разные стеки технологий, подпроекты полностью независимы и не имеют зависимостей, унифицированно управляются базовым проектом и комплектуются в соответствии с регистрацией, монтированием и выгрузкой узлов DOM.
  • Специальная центральная направляющая пьедестала: Между поднаправлениями используется один и тот же стек технологий; базовый проект и подпроект могут разрабатываться и развертываться отдельно; подпроект имеет возможность повторного использования общедоступной инфраструктуры базового проекта.

Анализируя характеристики каждой схемы, мы сравнили основные проблемы, как показано в следующей таблице:

план Можно ли унифицировать стек технологий индивидуально упакованный Развернуть отдельно Упаковка и скорость развертывания Работа с одностраничным приложением Скорость переключения подпроектов Сложности в общении между проектами Существующие инженерные инвазивные стоимость обучения
NPM-стиль да (не обязательно) нет нет медленный да быстрый нормальный высокий высокий
iframe да (не обязательно) да да нормальный нет медленный высокий высокий Низкий
Универсальный центральный пьедестал да (не обязательно) да да нормальный да медленный высокий высокий высокий
Специальная центральная направляющая пьедестала да (обязательно) да да быстрый да быстрый нормальный Низкий Низкий

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

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

Обзор практики микро-фронтенда

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

Видно, что вся схема очень проста и понятна, то есть выполняется по бизнес-линии.разделение на уровне маршрута. Всю систему можно разделить на две части:

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

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

Изменения в бизнесе под архитектурой микро-фронтенда

После трансформации практики микро-фронтенда структура нашего бизнеса претерпела следующие изменения:

Как показано на рисунке выше, мы выполнили разделение бизнес-линий микроинтерфейса:

  • Первоначальная система ПК, система H5 и система KA были преобразованы в базовую систему ПК, базовую систему H5 и базовую систему KA соответственно.
  • Исходное поднаправление бизнеса было разделено на отдельные подсклады и стало подпроектами бизнес-направления (6 вертикальных столбцов с черными прямоугольниками на рисунке выше).
  • Подпроект бизнес-линии соответственно включает терминал ПК, терминал H5, терминал KA и код уровня мультиплексирования бизнес-линии (три столбца сплошного цвета на приведенном выше рисунке).

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

Внедрение решения микроразветвления делает наш бизнес не толькоСохраняет возможность повторного использования по вертикали,важнееИмеет возможность масштабирования по горизонтали, как бы ни была раздута продуктовая бизнес-линия, мы легче с ней справимся. Итак, что мы сделали для достижения вышеуказанных возможностей? Мы объясним подробно ниже.

Микро-интерфейс пьедестала с центральной маршрутизацией на основе стека React

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

Динамическое решение

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

динамическая маршрутизация

Схема динамической маршрутизации состоит в том, чтобы разделить уровень маршрутизации.Во-первых, нам нужно определить, что использовать для управления маршрутизацией? Многие реализации, как правило, используют специально созданные маршруты для управления модулями. Например, фреймворк с открытым исходным кодом Single-Spa реализует собственный набор мониторинга маршрутизации для переключения подпроектов и требует, чтобы подпроекты реализовывали определенные интерфейсы регистрации, монтирования, выгрузки и другие интерфейсы для завершения динамической связи между подпроектами и базой. проекты, а также требует специальной системы управления модулями, такой как systemjs, чтобы помочь в этом процессе. Несомненно, это будет дорого стоить преобразования нашего исходного проекта, и необходимо будет добавить дополнительные библиотеки, что приведет к накладным расходам с точки зрения размера пакета. Более того, разработчики подпроектов должны быть знакомы с этими специфическими интерфейсами, а стоимость обучения относительно высока. Очевидно, что это нерентабельно для наших бизнес-сценариев и потребностей.

Итак, что мы выбираем для управления маршрутизацией? В итоге мы использовали React-Router, который сохранил наш оригинальный стек технологий без изменений, и при этом вмешательство в проект было минимальным, почти незначительным. Кроме того, React-Router может полностью удовлетворить наши потребности, и он будет автоматически помогать нам управлять загрузкой и выгрузкой страниц, вместо повторной инициализации всего суб-приложения каждый раз, когда мы переключаем маршруты, поэтому он также оптимален с точки зрения Скорость загрузки.Опыт одностраничного приложения согласован.

Реализация также очень проста, как показано ниже:

На приведенной выше блок-схеме показан процесс загрузки и отображения подпроекта, когда мы переключаемся на маршрут подпроекта в базовом проекте. Ключевым шагом здесь является процесс загрузки файла записи подпроекта и динамической регистрации маршрутизации подпроекта. Поскольку мы используем React-Router, очевидно, что это будет сделано с использованием предоставляемых им динамических возможностей. Этот процесс также очень легкий.Поскольку React-Router был обновлен с версии 4 до «деструктивного уровня», мы исследовали два способа динамической загрузки маршрутизации (в настоящее время мы используем React-Router версии 5), как показано в таблице. ниже:

Версия React-маршрутизатора динамическая нагрузка
3 Используйте API getChildRoutes Route для асинхронной загрузки маршрутов.
4 и выше В версии 4 и выше React-Router сильно изменился в плане реализации, то есть он больше не берет централизованную маршрутизацию pre-registered routing как концепцию дизайна, а изменяет идею маршрутизации как компонента . Для динамически загружаемой маршрутизации это динамическая загрузка компонентов, что упрощает реализацию нашей динамической загрузки, не полагаясь на какой-либо API, просто напишите асинхронный компонент.

В React-Router версии 3 реализованы следующие основные идеи кода:

// react-router V3 用于接收子工程的路由
export default () => (
    <Route
        path="/subapp"
        getChildRoutes={(location: any, cb: any) => {
            const { pathname } = location.location;
            // 取路径中标识子工程前缀的部分, 例如 '/subapp/xxx/index' 其中xxx即路由唯一前缀
            const id = pathname.split('/')[2];
            const subappModule = (subAppMapInfo as any)[id];
            if (subappModule) {
                if (subappRoutes[id]) {
                    // 如果已经加载过该子工程的模块,则不再加载,直接取缓存的routes
                    cb(null, [subappRoutes[id]]);
                    return;
                }
                // 如果能匹配上前缀则加载相应子工程模块
                currentPrefix = id;
                loadAsyncSubapp(subappModule.js)
                    .then(() => {
                        // 加载子工程完成
                        cb(null, [subappRoutes[id]]);
                    })
                    .catch(() => {
                        // 如果加载失败
                        console.log('loading failed');
                    });
            } else {
                // 可以重定向到首页去
                goBackToIndex();
            }
        }}
    />
);

В React-Router версии 4 реализованы следующие основные идеи кода:

export const AyncComponent: React.FC<{ hotReload?: number; } & RouteComponentProps> = ({ location, hotReload }) => {
    // 子工程资源是否加载完成
    const [ayncLoaded, setAyncLoaded] = useState(false);
    // 子工程url配置信息是否加载完成
    const [subAppMapInfoLoaded, setSubAppMapInfoLoaded] = useState(false);
    const [ayncComponent, setAyncComponent] = useState(null);
    const { pathname } = location;
    // 取路径中标识子工程前缀的部分, 例如 '/subapp/xxx/index' 其中xxx即路由唯一前缀
    const id = pathname.split('/')[2];
    useEffect(() => {
        // 如果没有子工程配置信息, 则请求
        if (!subAppMapInfoLoaded) {
            fetchSubappUrlPath(id).then((data) => {
                subAppMapInfo = data;
                setSubAppMapInfoLoaded(true);
            }).catch((url: any) => {
                // 失败处理
                goBackToIndex();
            });
            return;
        }
        const subappModule = (subAppMapInfo as any)[id];
        if (subappModule) {
            if (subappRoutes[id]) {
                // 如果已经加载过该子工程的模块,则不再加载,直接取缓存的routes
                setAyncLoaded(true);
                setAyncComponent(subappRoutes[id]);
                return;
            }
            // 如果能匹配上前缀则加载相应子工程模块
            // 如果请求成功,则触发JSONP钩子window.wmadSubapp
            currentPrefix = id;
            setAyncLoaded(false);
            const jsUrl = subappModule.js;
            loadAsyncSubapp(jsUrl)
                .then(() => {
                    // 加载子工程完成
                    setAyncComponent(subappRoutes[id]);
                    setAyncLoaded(true);
                })
                .catch((urlList) => {
                    // 如果加载失败
                    setAyncLoaded(false);
                    console.log('loading failed...'); 
                });
        } else {
            // 可以重定向到首页去
            goBackToIndex();
        }
    }, [id, subAppMapInfoLoaded, hotReload]);
    return ayncLoaded ? ayncComponent : null;
};

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

Динамический магазин

Для уровня Магазина наш исходный проект использует Redux, а подпроекты могут естественным образом получать доступ к глобальному Магазину посредством динамической регистрации маршрутов, поэтому доступ к Магазину может поддерживаться автоматически. Итак, что, если подпроект хочет зарегистрировать собственное глобальное хранилище? И мы также использовали redux-saga в качестве решения для асинхронной обработки. Как redux-saga динамически регистрируется? Или мы можем достичь нашей цели, используя их соответствующие API? Как видно из рисунка ниже, поддержка Dynamic Store может быть осуществлена ​​с небольшими затратами на преобразование.

Динамический CSS

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

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

Другая проблема заключается в том, как убедиться, что CSS подпроекта не конфликтует с другими подпроектами. Мы решаем эту проблему, используя плагин PostCSS для создания пространства имен для каждого набора правил CSS в соответствии с уникальным идентификатором направления деятельности, назначенным подпроекту при компиляции подпроекта. Разработчики подбизнес-направления не осведомлены и могут написать стиль подпроекта без «умственной нагрузки».

Информационная схема конфигурации маршрутизации

После того, как схема динамической загрузки определена, как базовый проект может узнать путь к ресурсам подпроекта, а затем загрузить соответствующие ресурсы JS и CSS? Нам нужен набор картографической информации. Как показано на рисунке ниже, уникальным идентификатором бизнес-линии является ключ, а соответствующим статическим адресом ресурса — значение. Таким образом, когда базовый проект переключается на подпроект, информация о конфигурации может быть извлечена, и соответствующий подпроект может быть точно найден при переключении маршрута, а затем может быть выполнен последующий процесс загрузки ресурсов. Возможный вопрос: если JS и CSS слишком велики, можно ли их разделить?

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

Схема интерфейса субинженерии

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

import reducers from 'common/store/labor/reducer';
import sagas from 'common/store/labor/saga';
import routes from './routes/index';
function registerApp(dep: any = {}): any {
    return {
        routes, // 子工程路由组件
        reducers, // 子工程Redux的reducer
        sagas, // 子工程的Redux副作用处理saga
    };
}
export default registerApp

Здесь мы выставляем три объекта подпроекта: самое главное здесь — это компонент маршрутизации маршрутов, который пишет маршруты React-Router (версия 4 и выше). Разработчикам подпроектов нужно только настроить объект маршрутов без каких-либо затрат на обучение.Код выглядит следующим образом:

/**
 * 子工程路由注册说明
 * 如注册的路由如下:
 * path: 'index'
 * 路由前缀会被追加上,路由前缀规则见变量urlPrefix
 * 在主工程的访问路劲为:/subapp/${工程注册名称}/index
 */
const urlPrefix = `/subapp/${microConfig.name}/`;
const routes = [
    {
        path: 'index',
        component: IndexPage,
    },
];
const AppRoutes = () => (
    <Switch>
        {
            routes.map(item => (
                <Route
                    key={item.path}
                    exact
                    path={`${urlPrefix}${item.path}`}
                    component={item.component}
                />
            ))
        }
        <Redirect to="/" />
    </Switch>
);
export default AppRoutes;

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

Схема мультиплексирования

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

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import * as ReactRouterDOM from 'react-router-dom';
import * as Axios from 'axios';
import * as History from 'history';
import * as ReactRedux from 'react-redux';
import * as Immutable from 'immutable';
import * as ReduxSagaEffects from 'redux-saga/effects';
import Echarts from 'echarts';
import ReactSlick from 'react-slick';
​
function registerGlobal(root: any, deps: any) {
    Object.keys(deps).forEach((key) => {
        root[key] = deps[key];
    });
}
registerGlobal(window, {
    // 在这里注册暴露给子工程的全局变量
    React,
    ReactDOM,
    ReactRouterDOM,
    Axios,
    History,
    ReactRedux,
    Immutable,
    ReduxSagaEffects,
    Echarts,
    ReactSlick,
});
export default registerGlobal;

План процесса

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

Процесс разработки

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

Горячее обновление

В процессе разработки мы надеемся, что наш опыт разработки согласуется с опытом разработки одностраничных приложений, а также поддерживает горячие обновления. Из-за нашего разделения фактически есть два сервиса, а именно базовый и подпроект, поэтому мы выполнили поддержку горячего обновления, как показано выше: в module.hot подпроекта, запустив хук JSONP в базовом проекте снова Чтобы уведомить базовый проект, снова запустить renderApp для достижения цели горячего обновления страницы, когда подпроект обновляет код. Основной код выглядит следующим образом:

// 在子工程入口文件
import routes from './routes/index';
function registerApp(dep: any = {}): any {
    return {
        routes,
    };
}
if ((module as any).hot) {
    (module as any).hot.accept('./routes/index', (): any => {
        window.wmadSubapp(registerApp, true); // 支持子工程热加载的信息传递
    });
}
export default registerApp

Имитация данных

В настоящее время существует три способа имитации данных в подпроекте: во-первых, локальная имитация в базе, которая, естественно, поддерживается, поскольку базовый проект разработан на основе Девяти строительных лесов Takeout Engineering и поддерживает локальную имитацию. Во-вторых, поддержка локальных макетов подпроектов. Третий — использовать общедоступный фиктивный сервис YAPI. В настоящее время функция Mock, разработанная подпроектом, выполняется в сочетании с первым методом и третьим методом.

План развертывания

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

Весь процесс развертывания размещается в Talos (инструмент развертывания, разработанный Meituan), а информация о конфигурации размещается в Portm (собственно разработанное файловое хранилище в Meituan) (через подключаемый модуль Talos UpdatePubInfo-To-Portm для обновления наших информация о конфигурации). После того, как статические ресурсы загружены в CDN, информация о конфигурации может быть обновлена ​​для вызова основного проекта, что завершает процесс перехода подпроекта в онлайн. Используя существующие сервисы Meituan, мы быстро выполнили весь процесс развертывания и запуска подпроектов по отдельности.

план отката

В сценарии развертывания мы развертываем через Talos, который сам имеет возможности отката. Благодаря тому, что выпуск подпроектов принципиально не отличается от выпуска обычных проектов, все статические ресурсы размещаются на CDN, а разные версии различаются значением contenthash статических ресурсов, поэтому при откате, Talos извлекает предыдущую версию (или предыдущую версию) статических ресурсов, а затем обновляет нашу информацию о конфигурации через Portm для завершения. Весь процесс ничем не отличается от обычных проектов, а персоналу релиза достаточно просто нажать кнопку отката.

Решение для мониторинга

После изменения исходного режима разработки мы также убрали несколько ключевых узлов для мониторинга и оповещения. Используя Meituan CAT (уже открытый исходный код на GitHub) и Skynet (внутренняя система мониторинга Meituan), мы сообщали информацию о конфигурации подпроекта, загрузку статических ресурсов и другие узлы соответственно, а также подсчитывали показатель успешности загрузки подпроекта. своевременно устранять возможные проблемы с переключением подпроектов. Конкретная ситуация показана на следующем рисунке:

Верхнее левое изображение — это пример статистики, основанной на измерении терминала, а верхнее правое изображение — это пример статистики на стороне ПК о количестве успешных загрузок по линейке продуктов. По умолчанию подсчитываются данные за текущий день, а отображение «-» указывает на отсутствие данных. На данный момент существует три типа мониторинга загрузки ресурсов: JSON, JS и CSS, статистика сбоев загрузки ресурсов также включает эти три типа. Мониторинг Skynet осуществляется на минутном уровне.Если в течение каждой минуты происходит сбой загрузки, будет выдан сигнал тревоги.Случайные тревоги могут быть вызваны проблемами с сетью пользователя.Если возникает большое количество тревог, следует обратить внимание.

Суммировать

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

  • Проект разделен в соответствии с доменом (направлением деятельности), улучшена ремонтопригодность проекта, связанные домены связаны, а несвязанные домены разделены.
  • Подинжиниринг предусматривает физическое повторное использование грунта на трех концах ПК, Н5 и КА, что устраняет проблему расширения проекта и позволяет контролировать размер проекта.
  • Скорость упаковки подпроектов снижена с минут до секунд, что улучшает опыт разработки и ускоряет запуск.
  • Разработка подпроектов поддерживает горячие обновления, и процесс разработки не ухудшается.
  • Подпроекты можно самостоятельно разрабатывать, развертывать и запускать отдельно, а бизнес-направления не влияют друг на друга.
  • Общие затраты на инженерную трансформацию низки, подключаемая разработка, отсутствие навязчивого кода и нормальное развитие бизнеса могут быть завершены за короткий период времени.
  • Стоимость обучения для разработчиков низкая, а опыт разработки одностраничных приложений полностью сохраняется, и разработчики могут быстро приступить к работе.
  • В настоящее время в рекламной части Meituan уже запущено много направлений подбизнеса в модели микро-интерфейса. Кроме того, в разработке находится несколько подпроектов микроинтерфейса, а остальные поднаправления бизнеса в основном проекте также могут быть безболезненно перенесены, чтобы в будущем стать подпроектами. Мы также собрали много отзывов в ходе этого процесса и продолжим думать и совершенствоваться на практике в будущем. Во время этого процесса мы знаем, что есть еще много несовершенств и даже проблем.Вы можете связаться с нами и дать нам ценные мнения или рекомендации. Конечно, вы также можете присоединиться к нашей команде и строить вместе.

об авторе

Чжан Сяо, Вэй Сяо и Тяньяо — инженеры отдела исследований и разработок отдела доставки еды Meituan.

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

Команда фронтенда Meituan Food Delivery ищет старших специалистов по фронтенд-разработке и фронтенд-разработке. Мы предоставляем сервисную платформу монетизации для продавцов и предоставляем пользователям высококачественный рекламный опыт, который является важным звеном в реализации бизнеса на вынос. Приглашаем всех друзей присоединиться и вместе создавать лучшие рекламные продукты. Заинтересованные студенты могут отправлять свои резюме по адресу: tech@meituan.com (отметьте в теме письма: Meituan Food Delivery Advertising Front-end Team)