Привет, Хабр! Меня зовут Евгений Лабутин, я разработчик в МТС Digital. Сегодня я расскажу вам о своем рецепте приготовления микрофронтендов без использования каких либо фреймворков. Ведь такие фреймворки как Webpack Module Federation, Single-SPA, SystemJS и подобные вам просто не нужны для написания микрофронтендов, ровно так же как вам не нужен jQuery для написания современных фронтендов. Ведь все необходимое для разработки и работы Микрофронтендов уже встроено во все современные браузеры. Интересно? Добро пожаловать в статью.

Терминология

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

  • микросервис — это небольшая независимая программа работающая на стороне сервера и выполняющая задачи в небольшой области ответственности. Мою прошлую статью про микросервисы можно почитать по ссылке;

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

Именно такая характеристика как встраивание посредством динамического импорта отличает микрофронтенд от подключения внешней библиотеки и сборки монолита.

Где использовался микрофронтенд

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

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

Второй проект — SMS-рассылка, в нем микрофронтенды используются как инструмент миграции с legacy-кода из razor на современный стек на NextJS.

Микрофронтенд как инструмент масштабирования

Сначала давайте покажу как использовались микрофронтенды для масштабирования проекта МТС Твой бизнес. Наше приложение имело следующую архитектуру:

И микрофронтенды помогали решать следующие задачи:

Задача 1: Переиспользование общих компонентов между разными приложенииями.

У нас было несколько микросервисов и встал вопрос — как переиспользовать общие элементы, а не копировать их между микросервисами. Ответ очевиден: такие общие элементы как Шапка, Футер, Формочки, Виджеты вынести в отдельный проект и подключать к Микросервисам как Микрофронтенды.

Причем не все приложения написаны на Реакте. У нас также были приложения, написанные на Tilda. И там привычные инструменты встраивания через сборку просто не работают.

Задача 2: Встраивание элементов нашего кабинета в партнерские кабинеты

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

Мы решили вынести функционал отображения состояния сервиса и функцию оплаты приложения в микрофронтенды и встроить их в партнерские кабинеты. Таким образом клиенту не надо было никуда переходиться для оплаты сервиса партнера.

Задача 3: Переиспользование инфраструктурной логики между микросервисами

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

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

Требования к микрофронтендам

Исходя из тех задач, которые должны решать микрофронтенды, были сформированы следующие требования:

  • независимость от внешнего проекта. Наши микрофронтенды встраивались не только в проекты написанные на Реакте, но и в тильду, в партнерские продукты, написанные на совершенно разных технологиях. Поэтому на окружение хостового приложения надеяться не стоит. Так мы решили все необходимые зависимости — встраивать в Микрофронтенд, включая Реакт и библиотеки;

  • использование микрофреймворков и легковесных библиотек. В связи с тем, что в наш микрофронтенд входили все его зависимости, решение могло быть тяжеловесным и ухудшать опыт пользователя в приложениях, куда встраивается микрофронтенд. А для того, чтобы не вредить хостовым приложениям нашими микрофронтендами, мы решили отказаться от тяжеловесных фреймворков и библиотек. Поэтому вместо тяжеловесных React, Angular, Vue лучше взять их легковесные аналоги Preact, Svelte, SolidJS и тому подобные. В частности, мы использовали Preact, так как он позволяет переиспользовать опыт, полученный от разработки на React;

  • использовать модули. Микрофронтенд должен встраиваться в хостовое приложение посредством динамического импорта. Динамический импорт поддерживает уже 95% браузеров. И подключение посредствам динамического импорта гораздо удобнее, чем подключение посредством встраиваемого скрипта;

  • не использовать глобальные переменные. Глобальные переменные могут привести к конфликтам на хостовом приложении. Поэтому нельзя использовать ни глобальные JS переменные, ни глобальные CSS переменные. И если использование модулей решает проблемы с JS-переменными, то для CSS надо в принципе отказаться от CSS-переменных. И с этой задачей отлично помогает справиться подход CSS-in-JS и такие библиотеки как Styled Components;

  • независимость от внешних настроек стилей. Все мы используем CSS Reset чтобы стили во всех браузерах выглядели одинаково. Но мы используем разные CSS Reset. И не стоит надеяться что CSS Reset, настроенный в вашем проекте, работает так же, как CSS Reset, написанный в хостовом приложении. Поэтому микрофронтенды должны иметь свой собственный CSS Reset, который будет иметь область действия только в вашем микрофронтенде;

  • использовать авторизацию по OpenID. Наши микрофронтенды встраивались не только в домены mts.ru, но и в домены партнеров. А авторизация посредством кук на разных доменах не работает, так как куки работают только в рамках своих доменов. Для решения этой проблемы необходимо передавать авторизацию не посредством кук, а посредством заголовков или в теле запросов.

Создание микрофронтендов

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

Для этого мы создаем JS-файл, который экспортирует наружу две функции render и clear.

Пример функции render:

import ReactDOM from "react-dom";
import {resolve} from "first-di";
import {App} from "./../../components/App";
import {Logger} from "./../../helpers/Logger";

const logger = resolve(Logger);
let memRootElement: HTMLElement | null = null;

export const render = (elem: HTMLElement, config?: Config) => {
	try {
		memRootElement = elem;

		ReactDOM.render(<App config={config} />, elem);

	} catch (error: unknown) {
		logger.error("Error on draw widget", error);
	}
};

Функция render отвечает за отрисовку микрофронтенда. Она принимает два параметра. Первый — это элемент, в который необходимо врендерить микрофронтенд. Второй это конфигурация с которой необходимо отрендерить микрофронтенд.

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

Пример функции clear:

export const clear = (): void => {
	ReactDOM.render([], memRootElement);
};

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

Сборка Микрофронтенда

Теперь мы можем собрать наш микрофронтенд в JS-бандл. Для этого подходит практически любой инструмент сборки: rollup, webpack, vite, swcpack. Я приведу примеры нескольких из них.

Пример сборки на Rollup:

// Используемые мною плагины
import nodeResolve from "@rollup/plugin-node-resolve";
import commonJs from "@rollup/plugin-commonjs";
import postcss from 'rollup-plugin-postcss'
import replace from "@rollup/plugin-replace";
import swc from "@rollup/plugin-swc";
import terser from '@rollup/plugin-terser';

export default {
	input: [
		"src/microfront-first-main.tsx",
		"src/microfront-second-main.tsx"
	],
	plugins: [...], // тут подключаются плагины
	output: [
		{
			dir: "dist",
			format: "esm",
			entryFileNames: "[name].esm.min.js",
		}
	]
};

Это мой любимый инструмент сборки. Rollup в связке с Swc позволяет очень быстро собирать микрофронтенды и тестировать результат. Еще одна отличительная черта Rollup — возможность делать сборки одновременно для новых и старых браузеров. Для чего может понадобиться поддержка старых браузеров, расскажу ниже.

Пример сборки на Webpack:

module.exports = {
	entry: {
		microfrontFirst: "src/microfront-first-main.tsx",
		microfrontSecond: "src/microfront-second-main.tsx"
	},
	plugins: [...],
	output: {
		filename: "[name].esm.min.js",
		path: path.join(__dirname, "dist")
	},
};

Как видите такой же простой конфиг что и у Rollup. Но настройка плагинов не такая простая как у Rollup.

Пример сборки на vite:

import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

export default defineConfig({
  plugins: [react()],
  build: {
    emptyOutDir: true,
    outDir: "dist",
    sourcemap: true,
    lib: {
      entry: {
        "first": "src/microfront-first-main.tsx",
        "second": "src/microfront-second-main.tsx"
      },
      formats: ["es"],
    },
  },
});

Vite — очень простой сборщик, в котором из коробки уже все настроено, фактически это пресет для сборщика Rollup. Но у него есть существенный недостаток. Для транспиляции typescript в javascript используется быстрый транспиллер esbuild. И проблема в том, что esbuild поддерживает не все фичи typescript. И поэтому если вам нужны продвинутые возможности typescript, такие, как декораторы, рефлексия и подобные, — esbuild вам не подходит и его необходимо заменить на swc. А так как из коробки этого сделать нельзя, то проще вернуться к варианту Rollup + Swc.

Пример конфига swc-pack:

const { config } = require("@swc/core/spack");
 
module.exports = config({
  entry: {
    first: __dirname + "/src/microfront-first-main.tsx",
    second: __dirname + "/src/microfront-second-main.tsx",
  },
  output: {
    path: __dirname + "/dist",
  },
  module: {},
});

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

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

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

Публикация микрофронтендов

Микрофронтенды публикуем как статичные файлы в отдельном контейнере. Публикуем в интернете на отдельном каталоге внутри домена.

Сборка контейнера очень проста:

FROM node:20-alpine AS build

WORKDIR /app
COPY package*.json .npmrc ./
RUN npm ci

COPY . .
RUN npm run lint
RUN npm run build


FROM nginx:1.25-alpine as production

RUN rm -rvf /etc/nginx/conf.d/default.conf
RUN rm -rvf /usr/share/nginx/html/index.html

COPY --from=build /app/dist /usr/share/nginx/html
RUN chown nginx:nginx -R /usr/share/nginx/html

Таким образом когда разработка микрофронтенда завершена, разработчик сливает код в мастер-ветку, отрабатывают CI/CD процессы и новый микрофронтенд публикуется в интернете. Клиенты при запросе микрофронтенда автоматически получат новую версию микрофронтенда без необходимости пересборки хостового приложения.

Подключение микрофронтенда к хостовому приложению

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

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

const microElement = document.querySelector("#micro");

const path = "https://tb.mts.ru/micro/header.esm.min.js";
const widget = await import(path);

widget.render(microElement, {openId: ""});

Для импорта микрофронтенда мы используем нативный динамический импорт, который поддерживают уже 95% браузеров и фактически 100% из поддерживаемых браузеров. Импортируем нашу функции render и clear. И вызываем функцию render для отрисовки микрофронтенда в нужном элементе с нужными параметрами.

Такое подключение имеет ряд преимуществ:

  • это гораздо проще, чем подключать внешний скрипт и ожидать его загрузки;

  • такая подгрузка не создает глобальных переменных, так как все переменные в модулях;

  • вам не надо «ловить» момент прогрузки и инициализации скрипта;

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

  • такое подключение нативно для браузеров и работает везде, независимо от используемых инструментов разработки и сборки;

  • таким образом можно подключать микрофронтенды к Tilda и другим платформам;

  • для обновления микрофронтенда не надо пересобирать хостовое приложение. Достаточно опубликовать новую версию микрофронтенда и он появится на всех хостовых приложениях;

  • этот вид импорта работает не только в браузере, но в nodejs. Таким образом можно переиспользовать серверную логику;

  • такой микрофронтенд совместим с SSR. Вы можете отрендерить компонент в текст на стороне сервера и гидрировать его на стороне браузера.

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

const microElement = document.querySelector("#micro");

const webpackDynamicImport = new Function(
	"return import('https://tb.mts.ru/micro/header.esm.min.js')"
);
const widget = await webpackDynamicImport();

widget.render(microElement, {openId: ""});

Дело в том, что Webpack имеет неправильное поведение и пытается динамический импорт встроить в сборку, что неправильно. Чтобы скрыть динамический импорт от сборщика необходимо спрятать динамический импорт в строке.

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

const microElement = document.querySelector("#micro");
let widget = nul;
try {
	new Function("(async(a=0)=>({...{a}},await import('')))()");

	const path = "https://tb.mts.ru/micro/header.esm.min.js";
	widget = await import(path);

} catch (err) {
	widget = require("https://tb.mts.ru/micro/header.cjs.min.js");
}

widget.render(microElement, {openId: ""});

Здесь мы сначала проверяем, поддерживает ли браузер новые возможности, в том числе динамический импорт. Если поддерживает, то подгружаем версию для новых браузеров. Если все же нет, то подгружаем CommonJS версию микрофронтенда. И как я писал выше, Rollup позволяет делать одновременно сборку для новых и старых браузеров. Но, кроме самой сборки для старых браузеров, понадобится еще и полифил require для браузеров.

Такую версию подключения микрофронтендов мы использовали несколько лет назад, когда поддержка динамического импорта была только у 85% браузеров, но теперь мы полностью отказались от старых браузеров.

Что не так с Webpack Module Federation?

Распиаренная и долгожданная технология которая по факту оказалась устаревшей и ненужной. Ключевая проблема Module Federation заключается в том, что это не инструмент разработки микрофронтендов. Это инструмент сборки распределенного монолита.

В итоге Webpack Module Federation приносит следующие проблемы:

  • Vendor Lock. Вы замыкаете свою разработку на этот проприетарный инструмент. С большой долей вероятности вам понадобится встроить ваш микрофронтенд в продукт, где нет MF и тогда вы столкнетесь с серьезными проблемами;

  • вы не можете встроить такие микрофронтенды в клиентские приложения, где нет системы сборки MF. Попробуйте, например, встроить MF в Tilda или проект на jQuery.

  • При обновлении микрофронтенда в MF необходимо пересобирать хостовое приложение, что осложняет раскатывание новой версии микрофронтенда на множество хостовых приложений.

  • самое страшное что есть в MF — это общие зависимости. Проблема настолько серьезная, что способна убить всю вашу разработку. Для примера возьмем такую общую зависимость, как React. Разработчики React периодически выпускают новые версии, в которых есть ломающие изменения. И проблема MF в том, что он заставляет всех разработчиков микрофронтендов и хостовых приложений работать в единой версии реакта. Пока проект небольшой, вы можете договориться со всеми разработчиками на обновление реакта. А как только ваш проект разросся до десятка микрофронтендов и хостовых приложений — вы уже никогда не сможете договориться о единовременном обновлении версии реакта. Таким образом вы попадаете в дурацкую ситуацию, когда реакт настолько устарел, что работать уже нельзя, а обновить его вы не можете, потому что у всех все сломается.

Получается, что MF подходит только для случаев, когда вы производите сборку распределенного монолита.

И совершенно не подходит для случаев когда ваши микрофронтенды встраиваются во множество хостовых приложений.

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

Частые ошибки в разработке микрофронтендов

Также я встречал много микрофронтендов от коллег и собрал популярные ошибки которые встретил у них:

  • импорт микрфоронтенда через script в head. Самая частая ошибка — это когда микрофронтенд подключается как внешний скрипт, который самостоятельно подгружается, инициализируется, создает глобальные переменные для вызова функционала. Дело в том, что функционал из данного скрипта может понадобиться еще до того, как скрипт прогрузился и инициализировался. Тогда вы словите ошибку. А отлавливание момента инициализации заставит вас написать несколько строчек лишнего кода. Динамический импорт — это одна простая строчка, которая вернет готовый скрипт. К тому же такие скрипты, как правило, собраны в монолитный бандл и не используют чанки, что раздувает размер скрипта;

  • скрипт сам начинает работать. Часто бывает что скрипт сам загрузился и начал что-то мониторить на странице. Такая тактика, как правило, не эффективна и потребляет клиентские ресурсы. Гораздо эффективнее будет подгрузить микрофронтенд в момент, когда он понадобился и запустить его исполнение. Например, форму оплаты не надо подгружать, когда клиент зашел на вашу страницу. Форму оплаты можно подгрузить динамическим импортом, когда пользователь нажал кнопку Купить;

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

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

Возвращаемся к первоначальным задачам и целям:

  1. Микрофронтенды встроены в наши микросервисы и обновляются без необходимости пересборки хостовых приложений.

  2. Микрофронтенды встраиваются в кабинеты партнеров, написанные на самых разных технологиях, и обновляются без необходимости пересборки партнерских кабинетов.

  3. Микрофронтенды встраиваются в Тильду и обновляются без правки в Тильде.

  4. Общая логика микросервисов вынесена в микрофронтенды и обновляется без необходимости пересборки хостовых приложений.

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

Как ведется разработка микрофронтендов?

И вот, мы сделали микрофронтенды, настроили их сборку, публикацию, подключение. Теперь вопрос — а как же удобно разрабатывать микрофронтенды? Чтобы вести разработку и сразу же видеть результат, не дожидаясь сборки и обновления микрофронтенда на сервере.

Для этого мы сделали проект, содержащий Workspace, в котором располагается еще два проекта Components и Docs. В первом ведется непосредственно разработка микрофронтендов, из которых потом собирается статика для публикации. Во втором находится проект на NextJS, который одновременно выполняет функцию документации и тестовой площадки.

Таким образом разработчик в абстрактном окружении разрабатывает микрофронтенд, а сборка в реалтайме попадает в документацию и NextJS через HotReload и сразу отображается изменения. В результате разработчик одновременно делает документацию к компоненту и проверяет, как микрофронтенд работает. Этой же документацией пользуются дизайнеры для встраивания микрофронтендов в Тильду. А тестировщики проверяют функционал микрофронтендов перед их релизом.

Микрофронтенд как инструмент миграции с legacy

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

В качестве легаси выступает фронт, написанный на C# и Razor шаблонизаторе. В качестве целевого решения был выбран NextJS. А в задаче — требования совершить беспростойную миграцию с легаси на новый стек.

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

Но вот вопрос — страница в старом проекте уже не работает, страница в новом проекте еще не работает. То есть сама страница работает, но окружение страницы еще не мигрировало, поэтому в новом пустом окружение страница работать не будет. Как минимум, сначала надо решить вопросы авторизации, роутинга и тому подобные проблемы. И тут на спасение приходят микрофронтенды.

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

В итоге Razor страница примет следующий вид:

@using WebApp.Helpers;

@{
    Layout = "~/Views/Shared/_Grid_12.cshtml";
}

@section PageHead{
}

<div id="naming-template-page"></div>
<script type="text/javascript">
    (async () => {
        const { injectInRazor } = await import("/app-build/first-page.min.js");
        injectInRazor("naming-template-page");
    })()
</script>

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

Спасибо за уделенное статье время!

Понравилась статья? Нажмите нравится и порекомендуй коллегам!

Остались вопросы или пожелания? С удовольствием пообщаюсь в комментариях к статье!

Нашли очепятку? Сообщите о ней в личку!

Комментарии (17)


  1. kaichou
    25.08.2023 18:33
    +11

    Вы начинаете статью с тезиса, что не используете библиотеки, фреймворки и прочие jquery. Мол, достаточно чистого js из коробки.

    И тут же подцепляете тонну всего.

    Ну, или я неправильно понял.


    1. saga111a
      25.08.2023 18:33
      +9

      Ведь все необходимое для разработки и работы Микрофронтендов уже встроено во все современные браузеры.

      import ReactDOM from "react-dom";

      И вот тоже как-то не понял...


    1. olku
      25.08.2023 18:33

      Тоже этот момент смутил. Полагаю, в той части речь идёт о реализации интерфейса микрофронта (два метода), а нативный код встраивания описан ниже в

      const microElement = document.querySelector

      Интересно попробовать собрать таким образом три-четыре Vaadin проекта.

      Автор, не делали ли вы автодискавери микрофронтов? Нативно это была бы бомба.


      1. LabEG Автор
        25.08.2023 18:33
        -1

        А что вы имеете ввиду под автодискавери микрофронтов?


        1. olku
          25.08.2023 18:33

          Динамику вместо статики https://tb.mts.ru/micro/header.esm.min.js


          1. LabEG Автор
            25.08.2023 18:33

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


            1. olku
              25.08.2023 18:33

              То есть, пока нет. Например, требование не привязываться к определенному домену, иметь разный набор микрофронтов в разных средах, не хардкодить зависимости.


    1. LabEG Автор
      25.08.2023 18:33
      -4

      Имелось ввиду без фреймворком разработки микрофронтендов, типа Webpack Module Federation, Single-SPA, SystemJS и т.п..

      Но на самом деле данный подход можно использовать и без реакта, и вообще каких либо библиотек, и даже инструментов сборки. Браузер нативными средствами подтянет все импорты доступные по http/s.

      Но все же лучше использовать микробиблиотеки и делать оптимизирующую сборку для клиентов.


  1. petrov_engineer
    25.08.2023 18:33
    +2

    Для webpack и vite достаточно использовать магические комментарии, чтобы запретить парсинг и разрешение зависимостей:

    import(
      /* webpackIgnore */
      url
    )
    import(
      // @vite-ignore
      url
    );

    При этом мы не прибегаем к eval/new Function, не нарушаем CSP и тп.

    Наверное, с вендор локом на технологиях MF, SSPA и тп можно согласиться, но аргументы против ИМХО несостоятельные, например, в официальной документации MF есть пример с указанием версий пакетов по semver, откуда появилась проблема в "новых версиях, в которых есть ломающие изменения" не понятно.

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


    1. LabEG Автор
      25.08.2023 18:33
      -1

      Например ваш микрофронтенд может быть реализован на react 18 с новыми хуками, а основное приложение на react 15 где новых хуков нет. И таким образом вы не сможете пошарить единый реакт между микрофронтендом и хостовым приложением.

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

      Вопрос коммуникации микрофронтендов тут не затрагивался. Но легко реализуется либо через пропсы микрофронтенда, как с обычными компонентами, либо через общий Event Bus.


  1. J_ss
    25.08.2023 18:33

    Можете приложить ссылку github на данную реализацию?


    1. LabEG Автор
      25.08.2023 18:33
      -2

      К сожалению нет. Данная реализация является частью продукта и доступна только сотрудникам МТС.


  1. gmtd
    25.08.2023 18:33

    МТС пишет на Тильде?
    И говорит что-то о минимализме и эффективности в выборе технологий для фронта?


    1. LabEG Автор
      25.08.2023 18:33

      МТС огромная компания с большим набором технологий. Распределение примерно такое же как и по индустрии. Большинство проектов это реакт, так же распространены вуе и ангуляр. Тильда это самое не популярное решение, но и к нему иногда прибегают.


  1. LabEG Автор
    25.08.2023 18:33

    Промазал. Del.


  1. profyan
    25.08.2023 18:33

    Т.е. правильно я понимаю, если все ваши МФ будут использовать React одной версии, то на странице сайта будет N бандлов React'a зашитых в МФ? Это же влияет на скорость загрузки и прочие метрики. А Module Federation как раз позволяет это оптимизировать, шаря одну и ту же версию.

    Да, если у вас микрофронты используют все разные версии, то Module Federation тут не поможет. Но это частный случай. И лучше иметь возможность шэрить общие либы, чем не иметь, нет?


    1. LabEG Автор
      25.08.2023 18:33
      -1

      И да и нет. Нет - в том плане что мы не используем реакт для микрофронтенда. Вместо него мы используем его легковесную альтернативу Preact. React + React Dom весит 128 kb, Preact весит 3.5 kb. Т.е. в 36 легче. Есть где разгуляться. Да - в том плане что в каждой группе микрофронтендов свой экземпляр Preact. Получается что на странице 2-4 экземпляра Preact + Preact на хостовом приложении. Это все еще в 6 раз легче 1 пошаренного Реакта.

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

      В моем случае было 15 внешних партнерских ресурсов + тильда. Заставить кого либо использовать нужную версию Реакта - нереально. Заставить апгрейдить версии Реакта одновременно - нереально. Заставить кого либо использовать реакт вместо вуе - нереально. Заставить шарить реакт на вуе проекте - нереально. Заставить настраивать кого либо MF там где его нет - нереально. Затащить MF в тильду - нереально.

      А такое решение на базе микробиблиотек + динамический импорт отлично справляется со всеми перечисленными проблемами.