Итак, в Части I этой серии мы создали заголовок (источник), список товаров (источник) и корзину (источник). Теперь мы хотим собрать их вместе, чтобы создать полную страницу.

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

Как мы собираемся это реализовать? Что ж, есть несколько возможностей.

Альтернатива 1

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

mkdir homepage
cd homepage
git init .
npm init

И установите те зависимости, которые нам понадобятся:

npm install --save express ejs request

Теперь давайте создадим HTML-код в том виде, в каком мы хотим, чтобы наша конечная домашняя страница была. Для этого создайте файл внутри views/index.ejs, он должен находиться в папке представлений, потому что это значение по умолчанию для экспресс. Затем добавьте это содержимое:

Здесь мы рендерим базовый HTML, и наши приложения будут отображаться там, где находятся эти теги ejs. Итак, теперь нам нужен наш экспресс-сервер для предоставления этих переменных. Тогда давайте создадим наш сервер.

Создайте файл с именем server.js в корне вашего проекта и поместите этот код ниже:

Надеюсь, это достаточно просто для понимания, но, в итоге, он запрашивает все остальные 3 приложения параллельно, и когда все они завершают загрузку, выполняется рендеринг в HTML.

Вы можете увидеть окончательный результат с node server.js, проверьте это!

Прохладный! Эта настройка должна работать в большинстве случаев. Вы можете увидеть полный код здесь: https://github.com/microfrontends/homepage/tree/back-end

Наша архитектура сейчас такая:

Каждый из этих блоков представляет собой отдельное приложение, развернутое на отдельном сервере и работающее внутри Docker, круто!

ps: если вам нужен более надежный способ присоединения приложений к бэкэнду, nginx SSI кажется правильным инструментом для этой работы. Вот презентация об этом.

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

Проблема: некоторые приложения могут загружаться дольше

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

Итак, вместо того, чтобы ждать, пока все загрузится и затем отобразится для пользователя, вы хотите отображать их по мере загрузки, например, Facebook BigPipe (с 2009 года!).

Сначала мы смоделируем эту проблему. В нашем приложении со списком продуктов давайте заключим res.send в строку 17 с setTimeout пятью секундами:

Теперь для загрузки этого приложения требуется 5 секунд каждый раз, вы можете убедиться в этом, посетив https://microfrontends-products-list.herokuapp.com/ и обновив страницу.

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

Обновление 02 / июн / 2017

Хотя я представляю альтернативы ниже, услышав некоторые отзывы и истории, я передумал. В настоящее время я бы старался как можно больше придерживаться первого подхода (объединение всего в бэкэнде), поскольку это гораздо более простое решение.

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

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

Но как насчет вещей, которые могут быть медленными по своей природе? Что ж, приложение не должно полностью отображать менее чем за 300 мс, оно должно отображать хотя бы что-то, по крайней мере, простой текст «Загрузка…», чтобы пользователь не оставался ждать на пустом месте. экран. Команда, разрабатывающая приложение, несет ответственность за асинхронную загрузку, если это необходимо.

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

Я считаю, что основными преимуществами такой политики производительности - вместо попытки решить проблему с помощью кода - являются:

  • Намного более простой подход
  • Распределяет обязанности по производительности между командами
  • Гораздо меньше связи, поскольку у вас нет конкретных API-интерфейсов для адаптации, вам просто нужно отобразить свой HTML
  • Это быстрее, так как нам не нужно загружать что-либо дополнительно во фронтенде, чтобы выполнить эту работу.

Хорошо, теперь вернемся к старому мне ...

Альтернатива 2: iFrames

Я знаю, о чем вы думаете, о чем? iFrames? Неужели ?, тогда я вас спрашиваю: а почему бы и нет?

Давайте изменим наш index.ejs, чтобы использовать их:

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

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

Хорошо, если честно, обычно iFrames - не лучшая идея, вы, вероятно, столкнетесь с проблемами по мере продвижения.

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

Но это самая простая вещь в мире в использовании. Не бойтесь, если вам просто нужна полная инкапсуляция (например, что-то встроить), iFrame может быть решением.

Вот исходный код:
https://github.com/microfrontends/homepage/tree/iframes

Альтернатива 3: клиентский JavaScript

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

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

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

Да, из CORS (ba-dum-tss) мы не можем делать запросы ajax к другим доменам, но мы можем их проксировать! Для этого воспользуемся http-proxy-middleware:

npm install --save http-proxy-middleware

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

Теперь мы можем загрузить эти приложения из /header, /productsList и /cart.

Woohoo снова работает! Теперь он также загружается, как только приложения готовы, проверьте это:

Исходный код:
https://github.com/microfrontends/homepage/tree/client-side

ps: чтобы избежать проблем с порядком загрузки Javascript и CSS, я предлагаю вам развить это до решения, подобного facebook's bigpipe, возвращая JSON, например
{ html: ..., css: [...], js: [...] }, чтобы вы могли полностью контролировать его.

Альтернатива 4: прогрессивная загрузка из серверной части

Я считаю, что вышеприведенная альтернатива очень проста и отлично работает! Но если для вас очень-очень важно, чтобы HTML-код отображался с сервера, возможно, для SEO (может быть, нет, потому что Google, по крайней мере, уже очень хорошо обрабатывает javascript), вы можете использовать эту альтернативу.

Идея заключается в отправке фрагментов данных с сервера по мере их загрузки, мы можем сделать это, изменив наш index.ejs файл на это:

И чтобы server.js делал то, что мы ожидаем, мы можем использовать это:

Ух ты! Это много кода только для этого, если вы знаете лучший и простой способ добиться этого, скажите!

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

Вот как выглядит окончательный результат:

Исходный код:
https://github.com/microfrontends/homepage/tree/progressive-back-end

Альтернатива 5: Веб-компоненты

Если вы слышали о веб-компонентах раньше, вы могли подумать, что они идеально подходят для этого.

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

Внимание!

Эти альтернативы, указанные выше, могут сделать вещи очень сложными. ИМХО, я бы придерживался Альтернативы 1 (простая загрузка с сервера), если у вас нет этой проблемы, когда некоторые приложения загружаются дольше, чем другие. Если вы это сделаете, сначала постарайтесь свести к минимуму время, затрачиваемое на бэкэнд этих приложений, вместо того, чтобы пытаться исправить это спереди, это упростит все.

Вам не нужна отдельная страница

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

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

Подводя итог: не создавайте сложности, пока она вам не понадобится.

Следующие шаги

Хорошо! Итак, теперь, когда наши приложения разделены и мы знаем, как объединить их на странице, мы можем создавать другие страницы, например, повторно используя один и тот же заголовок, круто, правда? Не так быстро, сначала нам нужно исправить проблемы, которые мы сами себе создали, используя этот подход.

Какие проблемы вы говорите? Перейдите к Части III и узнайте.