Что такое микрофронтенд?
Давайте сначала рассмотрим два практических сценария:
1. Повторно используйте другие страницы проекта
Обычно наши фоновые проекты выглядят так:
Если нашему проекту необходимо разработать новую функцию, а эта функция была разработана в другом проекте, мы хотим использовать ее напрямую. PS: Все, что нам нужно, это эта функция страницы чужих проектовРаздел контента, который не требует верхней навигации и меню для чужих проектов.
Относительно глупый способ - напрямую копировать код этой страницы чужих проектов, но на случай, если другие неvue
развитый, илиvue
Версия,UI
Библиотеки бывают разные, как и чужие операции перед загрузкой страницы (перехват роутинга, аутентификация и т.д.) нам нужно ее копировать.Более важный вопрос, как мы синхронизируем обновления при обновлении чужого кода.
В долгосрочной перспективе копирование кода невозможно, корень проблемы в том, что нам нужно заставить их код работать в их собственной среде, а мы всего лишь «ссылки» на их страницы. Эта среда включает в себя различные плагины (vue
,vuex
,vue-router
д.), но и логику предварительной загрузки (читайcookie
, аутентификация, перехват маршрутизации и т.д.). частныйnpm
Компоненты могут быть общими, но все еще есть проблемы, такие как разные технологические стеки / разные библиотеки пользовательского интерфейса.
2. Бесплатное разделение и объединение проектов Big Mac
- Кодов становится все больше и больше, упаковка становится все медленнее и медленнее, развертывание и обновление вызывают затруднения, а обновление некоторых плагинов и модификацию общих компонентов нужно учитывать больше, и это легко повлиять на все. тело.
- Чем больше проект, тем больше людей задействовано, тем сложнее управлять спецификациями кода и тем чаще возникают конфликты кода.
- Продукт полностью функционален, но клиентам часто нужна только его часть. После зачистки лишнего кода приходится самостоятельно формулировать версию и самостоятельно ее поддерживать, что увеличивает трудозатраты.
Например, ваш продукт имеет сотни страниц с полными функциями и мощными функциями.Покупателям нужны только некоторые страницы, и им нужно, чтобы вы предоставили исходный код.В настоящее время точно невозможно дать все коды, и вы можно только выбрать их.Потребителям нужно, эту часть кода нужно разрабатывать отдельно для поддержки версий, что очень расточительно.
Общие решения для микроинтерфейса
Рождение микрофронтенда также должно решить две вышеупомянутые проблемы:
- Повторное использование (встраивание) страниц проектов других людей, но проекты других людей выполняются поверх его собственной среды.
- Приложение Big Mac разделено на небольшие проекты, эти небольшие проекты разрабатываются и развертываются независимо друг от друга и могут свободно объединяться для продажи.
Преимущества использования микрофронтендов:
- Независимо от стека технологий каждый подпроект может свободно выбирать фреймворк и разрабатывать собственные спецификации разработки.
- Быстрая упаковка, независимое развертывание, независимо друг от друга, простота обновления.
- Существующие функциональные модули можно легко использовать повторно, чтобы избежать повторной разработки.
На данный момент существует два основных решения для микрофронтендов:iframe
программа иsingle-spa
план
iframe
план
iframe
С ним знаком каждый, он прост и удобен в использовании, обеспечивает естественнуюjs/css
Изоляция также создает неудобства при передаче данных.Некоторые данные не могут использоваться совместно (в основном локальное хранилище, глобальные переменные и общедоступные плагины).Когда два проекта имеют разные источники (междоменные), передача данных должна опираться наpostMessage
.
iframe
Есть много ям, но у большинства из них есть решения:
- проблема с загрузкой страницы
iframe
Пул соединений общий с главной страницей, а в браузере есть ограничения на подключение одного и того же домена, поэтому это повлияет на параллельную загрузку страницы, блокируяonload
событие. Каждый щелчок требует перезагрузки, хотя можно использоватьdisplay:none
Сделать кеш, но слишком большой кеш страниц приведет к зависанию компьютера.(не может быть решен)
- проблема макета
iframe
Должна быть указана заданная высота, иначе он рухнет.
Решение: Подпроект вычисляет высоту в режиме реального времени и передаетpostMessage
Отправить на главную страницу, главная страница устанавливается динамическиiframe
высокий. В некоторых случаях появляется несколько полос прокрутки, что не очень удобно для пользователя.
- Проблема со всплывающим окном и маскирующим слоем
Всплывающие окна могут быть толькоiframe
Диапазон центрируется по вертикали и горизонтали, но не может быть центрирован по вертикали и горизонтали на всей странице.
- Решение 1: При синхронизации с сообщением страницы фрейма сообщение всплывающего окна отправляется на главную страницу, а на главной странице всплывает окно, что сильно меняет исходный проект и влияет на использование исходного проекта.
- Решение 2. Измените стиль всплывающего окна: скройте слой маски и измените положение всплывающего окна.
-
iframe
внутриdiv
Не могу перейти в полноэкранный режим
Полный экран всплывающего окна относится к полному экрану в видимой области браузера. Этот полный экран относится к занятию экрана пользователя.
Полноэкранная схема, нативный метод используетElement.requestFullscreen()
, плагин:vue-fullscreen. когда страницаiframe
Когда внутри, на весь экран сообщит об ошибке, иdom
Неорганизованная структура.
решение:iframe
Настройки ярлыкаallow="fullscreen"
характеристики
- Проблема с браузером вперед/назад
iframe
Делитесь историей посещений с главной страницей,iframe
Это повлияет на перемотку вперед и назад страницы. нормальный в большинстве случаев,iframe
Множественные перенаправления приведут к тому, что функции браузера вперед и назад не будут работать должным образом. иiframe
Обновление страницы будет сброшено (например, перейти со страницы списка на страницу сведений, а затем обновить, он вернется на страницу списка), потому что адресная строка браузера не изменилась,iframe
изsrc
Изменений тоже нет.
-
iframe
Сбой нагрузки непрост в обращении
негомологичныйiframe
в фаерфоксе иchorme
не поддерживаютonerror
событие.
- Решение 1:
onload
О названии страницы судят в том случае, если оно404
или500
- Решение 2. Используйте
try catch
Чтобы исправить это, попробуйте получитьcontentDocument
вызовет исключение.
Ссылка на решение:Вопрос о stackoverflow: поймать ошибку, если iframe src не загружается
single-spa
Микро интерфейсное решение
spa
В эпоху одностраничных приложений наши страницы имеют толькоindex.html
Вот этотhtml
файл, и в этом файле есть только один тег содержимого<div id="app"></div>
, который выступает в качестве контейнера для другого контента,js
Сгенерировано. Другими словами, нам нужно только получить контейнер подпроекта<div id="app"></div>
и сгенерированный контентjs
, вставленный в основной проект, может быть представлен контент подпроекта.
<link href=/css/app.c8c4d97c.css rel=stylesheet>
<div id=app></div>
<script src=/js/chunk-vendors.164d8230.js> </script>
<script src=/js/app.6a6f1dda.js> </script>
Нам нужно только получить четыре верхних тега подпроекта и вставить их в основной проект.HTML
, вы можете отображать дочерние проекты в родительском проекте.
Здесь есть проблема, так как теги контента подпроектов генерируются динамически, гдеimg/video/audio
И т. д. файлы ресурсов и загрузка страниц маршрутизации по запросуjs/css
являются относительными путями в подпроектеindex.html
внутри можно запросить корректно, в то время как в основном проектеindex.html
Внутри нельзя.
В качестве примера предположим, что URL-адрес нашего основного проектаwww.baidu.com
, URL-адрес подпроектаwww.taobao.com
, в подпроектеindex.html
В нем есть картинка<img src="./logo.jpg">
, то полный адрес этого образаwww.taobao.com/logo.jpg
, теперь преобразуйте это изображение вimg
Теги генерируются для родительского проектаindex.html
, то адрес запроса изображенияwww.baidu.com/logo.jpg
, очевидно, на сервере родительского проекта такой картинки нет.
Решения:
- здесь
js/css/img/video
и т. д. - все относительные пути, можете ли вы пройтиwebpack
Упаковать, упаковать все эти пути в абсолютные пути? Это решает проблему сбоев файловых запросов. - Можно ли это сделать вручную (или с помощью
node
), чтобы скопировать все файлы подпроекта на главный сервер проекта,node
Когда файл подпроекта мониторинга будет обновлен, он будет скопирован автоматически, и нажмитеjs/css/img
слияние папок - Может ли это быть похоже
CDN
Точно так же, если сервер зависнет, он перейдет к другим серверам для запроса соответствующих файлов. Другими словами, для обмена файлами между серверами, если запрос файла в основном проекте не удался, он будет автоматически найден на подсервере и возвращен.
Обычной практикой является динамическое изменениеwebpack
в упаковкеpublicPath
, а затем вы можете автоматически внедрять префиксы в эти ресурсы.
single-spa
Это микроинтерфейсный фреймворк.Основной принцип такой же, как и выше.На основе вышеуказанных подпроектов новыйbootstrap
,mount
,unmount
и другой жизненный цикл.
относительноiframe
,single-spa
Сделать родительский и дочерний проекты одним и тем жеdocument
, что имеет как преимущества, так и недостатки. Преимущество в том, что данные/файлы могут быть общими, общедоступные плагины являются общими, а подпроекты загружаются быстрее.js/css
Загрязнение.
single-spa
Начать работу непросто, и его нельзя использовать сразу, а разработка и развертывание требуют множества модификаций.webpack
Конфигурация, трансформация подпроектов тоже очень много.
qiankun
план
qiankun
Это фреймворк Ant Financial с открытым исходным кодом, основанный наsingle-spa
из. онsingle-spa
На основе реализовано готовое использование.За исключением некоторых необходимых модификаций, в подпроекты нужно внести лишь несколько изменений, чтобы их можно было легко подключить. если мы предположимsingle-spa
Если это велосипед,qiankun
Просто машина.
Существует два распространенных способа входа в файл входа подпроекта в микро-интерфейсе:JS entry
иHTML entry
чистыйsingle-spa
используетсяJS entry
,иqiankun
оба поддерживаютJS entry
и поддерживаетHTML entry
.
JS entry
Требования более жесткие:
(1) будетcss
упакован вjs
в
(2) удалитьchunk-vendors.js
,
(3) Удалить имя файлаhash
ценность
(4) будетsingle-spa
Входной файл для схемы (app.js
) помещается вindex.html
Директория, остальные файлы остаются без изменений, причина в перехватеapp.js
путь какpublicPath
APP entry | преимущество | недостаток |
---|---|---|
JS entry |
может сотрудничатьsystemJs , который загружает общедоступные зависимости по запросу (vue , vuex , vue-router Ждать) |
Требуются различные конфигурации упаковки, и предварительная загрузка не может быть достигнута |
HTML entry |
Конфигурация упаковки не требует особых изменений и может быть предварительно загружена | Еще один уровень запроса, вам нужно запроситьHTML файл, а затем использовать обычное сопоставление с нимjs иcss
|
фактическиqiankun
также поддерживаетconfig entry
:
{
entry: {
scripts: [
"app.3249afbe.js"
"chunk-vendors.75fba470.js",
],
styles: [
"app.3249afbe.css"
"chunk.75fba470.css",
],
html: `<!doctype html>
<html>
...
`
}
}
Рекомендуется использоватьHTML entry
, который используется иiframe
Так же просто, как пользовательский интерфейсiframe
Гораздо сильнее.qiankun
запрос на подпроектindex.html
После этого он сначала будет соответствоватьjs/css
связанные теги, а затем заменить его, он должен загрузить себяjs
и запустить, затем удалитьhtml/head/body
и другие теги, остальной контент вставляется как есть в контейнер подэлемента:
использоватьqiankun
преимущества:
-
qiankun
Принести свой собственныйjs/css
функция песочницы,singles-spa
Может быть решенcss
Загрязнение, но требует сотрудничества подпроектов -
single-spa
Программа поддерживает толькоJS entry
функции, которые ограничивают его только поддержкойvue
,react
,angular
и другие проекты технического развития, для некоторыхjQuery
Старые проекты бессильны.qiankun
нет предела -
qiankun
Поддержка функции предварительного запроса подпроекта.
js
песочница
js/css
Загрязнение неизбежно и является проблемой, которая может быть большой или маленькой. Подобно бомбе замедленного действия, вы не знаете, когда что-то пойдет не так, а устранение неполадок сопряжено с трудностями. В качестве базовой структуры очень важно разрешить эти два загрязнения, и ее нельзя разработать только на основе «спецификации».
js
Принцип песочницы заключается в том, что перед загрузкой подпроектаwindow
Объект делает снимок, и снимок восстанавливается при удалении подпроекта, как показано на рисунке:
Итак, как контролироватьwindow
Как насчет смены объекта, непосредственноwindow
Очевидно, что невозможно выполнить глубокое копирование объекта, а затем детально сравнить каждый атрибут.qiankun
Фреймворк используетES6
новые возможности,proxy
метод прокси. Как работать, написано в предыдущей статье (ссылка в конце статьи), поэтому повторяться не буду.
ноproxy
несовместимоIE11
Да, для совместимости более низкая версияIE
Усыновленныйdiff
Метод: поверхностное копированиеwindow
объект, а затем сравните каждое свойство.
css-песочница
qiankun
изcss
Принцип песочницы заключается в переписыванииHTMLHeadElement.prototype.appendChild
События, которые добавляются при запуске подпроектаstyle/link
теги, которые удаляются при выгрузке подпроектов.
single-spa
В схеме я использовал идею скиннинга для решенияcss
Загрязнение: первоеcss-scoped
Решите большую часть загрязнения, для некоторых глобальных стилей отдайте в подпроектыbody/html
добавить уникальныйid/class
(для обычной разработки и развертывания), затем добавьте это перед глобальным стилемid/class
,иsingle-spa
режимmount
цикл, чтобы датьbody/html
плюс это толькоid/class
,существуетunmount
Цикл удаляется, так что этот глобальныйcss
Действует только для этого проекта.
Фатальная точка этих двух решений заключается в том, что они не могут решить проблему одновременного выполнения нескольких подпроектов.css
загрязнение и влияние подпроектов на основной проектcss
Загрязнение.
Хотя не принято говорить, что два проекта выполняются одновременно, если вы хотите достичьkeep-alive
, вам нужно использоватьdisplay: none
Скройте подпроект, и подпроект не нужно удалять.В это время одновременно будут работать два подпроекта, но один из них не виден пользователю.
css
Другая идея песочницы заключается в том, чтобы ограничить стили подпроектов, чтобы они вступали в силу в рамках контейнера подпроекта, так что вам нужно только предоставить разным подпроектам разные контейнеры. Но это также будет иметь новые проблемы, в подпроектеappend
прибытьbody
, стиль не вступит в силу. Поэтому необходимо сформулировать спецификации для стилевого загрязнения.class
Назовите префикс.
Практика микро-интерфейсных решений
В моих предыдущих статьях (ссылка в конце статьи),single-spa
иqiankun
изdemo
Она реализована, и процессы разработки и развертывания также доступны.Следующим шагом является практика и использование ее в реальных проектах, чтобы знать эти ямы.
Модернизация существующего проекта дляqiankun
подпроект
Так как мыvue
стек технологий, поэтому я преобразовываюvue
Проект используется в качестве примера, чтобы проиллюстрировать, что принципы других технологических стеков одинаковы.
- существует
src
Добавить файлы в каталогpublic-path.js
:
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
-
Исправлять
index.html
В контейнере, инициализированном проектом, не используйте#app
, во избежание конфликтов с другими проектами рекомендуется заменить проектname
CamelCase -
Изменить файл записи
main.js
:
import './public-path';
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router'
import store from './store';
Vue.use(VueRouter)
Vue.config.productionTip = false
let router = null;
let instance = null;
function render(parent = {}) {
const router = new VueRouter({
// histroy模式的路由需要设置base,app-history-vue根据项目名称来定
base: window.__POWERED_BY_QIANKUN__ ? '/app-history-vue' : '/',
mode: 'history',
// hash模式不需要上面两行
routes: []
})
instance = new Vue({
router,
store,
render: h => h(App),
data(){
return {
parentRouter: parent.router,
parentVuex: parent.store,
}
},
}).$mount('#appVueHistory');
}
//全局变量来判断环境,独立运行时
if (!window.__POWERED_BY_QIANKUN__) {
render();
}
export async function bootstrap() {
console.log('vue app bootstraped');
}
export async function mount(props) {
console.log('props from main framework', props);
render(props.data);
}
export async function unmount() {
instance.$destroy();
instance.$el.innerHTML = '';
instance = null;
router = null;
}
Основные изменения: Внести измененияpublicPath
файлы иexport
Три жизненных цикла.
Уведомление:
-
webpack
изpublicPath
Значение может быть изменено только в файле ввода, причина, по которой оно записывается в отдельный файл и импортируется в начало файла ввода, заключается в том, что это позволяет всему приведенному ниже коду использовать это. - требуется файл маршрута
export
Данные маршрутизации, а не экземпляры объектов маршрутизации, функции маршрутизации также необходимо переместить в файл записи. - существует
mount
Жизненный цикл, вы можете получить данные, переданные родительским проектом,router
Маршруты для перехода к основному проекту/другим подпроектам,store
является экземпляром родительского проектаVuex
(Другие данные также могут быть переданы).
- Изменить конфигурацию упаковки
vue.config.js
:
const { name } = require('./package');
module.exports = {
devServer: {
headers: {
'Access-Control-Allow-Origin': '*',
},
},
// 自定义webpack配置
configureWebpack: {
output: {
library: `${name}-[name]`,
libraryTarget: 'umd',// 把子应用打包成 umd 库格式
jsonpFunction: `webpackJsonp_${name}`,
},
},
};
Примечание: этоname
По умолчанию отpackage.json
Получить, можно настроить, если он зарегистрирован в родительском проекте.name
Просто будьте последовательны.
В этой конфигурации в основном есть две конфигурации, одна из которых позволяет междоменное использование, а другая должна быть упакована вumd
Формат. Зачем собиратьсяumd
Что насчет формата? это позволитьqiankun
получить егоexport
функция жизненного цикла. Можем посмотреть в упаковкеapp.js
Просто знаю:
root
В среде браузера этоwindow
, qiankun
Возьмите эти три жизненных цикла, которые основаны на том, что вы указали при регистрации приложения.name
ценность,name
Несоответствие приведет к невозможности получить функцию жизненного цикла.
Некоторые соображения по разработке подпроектов
- Все ресурсы (картинки/аудио/видео и т.д.) должны быть размещены в
src
каталог, не ставитьpublic
илиstatic
Релиз ресурсаsrc
каталог, будет проходитьwebpack
обработка, может быть введена равномерноpublicPath
. В противном случае это будет 404 в основном проекте.
Ссылаться на:Официальная документация vue-cli3 вводит: когда использовать -public-folder
Файлы конфигурации, открытые для операторовconfig.js
, можно разместить вpublic
каталог, потому что вindex.html
серединаurl
для относительных ссылокjs/css
ресурс,qiankun
В него будет введен префикс.
- Пожалуйста, дайте
axios
Экземпляр вместо этого добавить перехватчикaxios
объект
В будущем предполагается, что подпроекты будут использовать общие плагины.В настоящее время необходимо избегать загрязнения общедоступными плагинами.
// 正确做法:给 axios 实例添加拦截器
const instance = axios.create();
instance.interceptors.request.use(function () {/*...*/});
// 错误用法:直接给 axios 对象添加拦截器
axios.interceptors.request.use(function () {/*...*/});
- избегать
css
Загрязнение
стилизован внутри компонентаcss-scoped
Это необходимо.
Для некоторых вставок вbody
всплывающее окно, недоступноscoped
, пожалуйста, не используйте оригиналclass
Измените стиль, добавьте свой собственныйclass
, чтобы изменить стиль.
.el-dialog{
/* 不推荐使用组件原有的class */
}
.my-el-dialog{
/* 推荐使用自定义组件的class */
}
- Используйте с осторожностью
position:fixed
В родительском проекте это позиционирование может быть неточным и его следует по возможности избегать.Там действительно есть необходимость в позиционировании относительно окна браузера.Вы можете использоватьposition: sticky
, но будут проблемы с совместимостью (не поддерживается IE). Если таргетинг используетbottom
иright
, то проблем нет.
Есть и другой способ, локацию можно записать как динамическую привязкуstyle
форма:
<div :style="{ top: isQiankun ? '10px' : '0'}">
- давать
body
,document
и другие связанные события, пожалуйстаunmount
Очистить период
js
Песочница только угналиwindow.addEventListener
,использоватьdocument.body.addEventListener
илиdocument.body.onClick
Добавленное событие не будет удалено песочницей и повлияет на другие страницы.unmount
Очистить период
qiankun
Общие проблемы и решения
qiankun
Распространенная ошибка
- Подпроект не
export
Необходимые функции жизненного цикла
Сначала проверьте, есть ли входной файл подпроекта.export
Функция жизненного цикла, затем проверьте упаковку подпроекта и, наконец, проверьте правильность запрошенного файла подпроекта.
- Контейнеры плохо отображаются при загрузке подэлементов
Проверьте контейнерdiv
То ли в маршруте написано, то ли маршрут не совпадает со всеми выгруженными. Если вы загружаете подэлементы только на определенной странице маршрутизации, вы можетеmounted
Зарегистрируйте подпроект в цикле и запустите его.
Маршрут основного элемента можно использовать толькоhistory
Режим?
так какqiankun
черезlocation.pathname
значение, чтобы определить, какой подпроект должен быть загружен в данный момент, поэтому вам нужно ввести разные маршруты в каждый подпроект.path
,иhash
Скачок маршрутизации подпункта режима не меняетсяpath
, так что это не имеет никакого эффекта,history
Настройки маршрутизации подпроекта режимаbase
характеристики.
Если основной проект используетhash
режим, затем используйтеlocation.hash
значение, чтобы определить, какой подпроект должен быть загружен в данный момент, и все подпроекты должны бытьhash
режиме, вам также необходимо добавить префикс ко всем маршрутам подпроекта.Если переход маршрута подпроекта используется доpath
также необходимо изменить, сname
Прыгать не обязательно.
Если основной элементhash
Подпункт режимаhistory
режим, после перехода к подпункту нельзя перейти к другомуhistory
Подпроекты модального окна не могут вернуться на главную страницу проекта.
vue
проектhash
Изменение режимаhistory
Схема тоже проста:
-
new Router
настройки времениmode
заhistory
:
-
webpack
запакованный конфиг(vue.config.js
) :
- Некоторые ресурсы будут сообщать об ошибке 404, а относительный путь будет изменен на абсолютный:
<img src="./img/logo.jpg">
изменить на<img src="/img/logo.jpg">
Просто
css
Проблемы загрязнения и загрузкиbug
-
qiankun
Он может решить только взаимное загрязнение стилей между подпроектами, но не может решить загрязнение стилей подпроектов, которые загрязняют стили основного проекта.
Если основной проект не должен быть загрязнен стилем подпроекта, подпроектvue
технология, стиль может быть написанcss-scoped
, если подпроектjQuery
Как насчет технологий? Итак, сам основной проектid/class
Он должен быть особенным, он не может быть слишком простым, он соответствует подпунктам.
- При переходе со страницы подпроекта на собственную страницу основного проекта главная страница проекта
css
не загруженbug
Причина этой проблемы: при переходе дочернего проекта к родительскому выгрузка дочернего проекта занимает немного времени, за это время происходит загрузка и вставка родительского проекта.css
, но элемент одеялаcss
Песочница была записана, а затем удалена. Мониторинг событий родительского проекта такой же, поэтому переходить нужно после выгрузки дочернего проекта. Я изначально хотел судить в функции хука маршрутизации, удален ли подпроект, а затем перейти к маршруту после завершения удаления.Однако, если маршрут не перескакивает, подпроект вообще не будет удален.
Временное решение: сначала сделайте копиюHTMLHeadElement.prototype.appendChild
иwindow.addEventListener
, функция маршрутизацииbeforeEach
Если текущий маршрут является дочерним проектом, а маршрут, к которому он ведет, является родительским проектом, восстановите эти два объекта.
const childRoute = ['/app-vue-hash','/app-vue-history'];
const isChildRoute = path => childRoute.some(item => path.startsWith(item))
const rawAppendChild = HTMLHeadElement.prototype.appendChild;
const rawAddEventListener = window.addEventListener;
router.beforeEach((to, from, next) => {
// 从子项目跳转到主项目
if(isChildRoute(from.path) && !isChildRoute(to.path)){
HTMLHeadElement.prototype.appendChild = rawAppendChild;
window.addEventListener = rawAddEventListener;
}
next();
});
Проблема перехода маршрута
Как перейти к другому подпроекту/основной странице проекта в подпроекте, написать напрямую<router-link>
или использоватьrouter.push/router.replace
Нет, причина в этомrouter
Это маршрут подпроекта, все прыжки будут основаны на подпроекте.base
. Писать<a>
Ссылка может перейти в прошлое, но страница будет обновлена, а взаимодействие с пользователем не очень хорошее.
Решение также относительно простое: при регистрации подпроекта объект экземпляра маршрутизации основного проекта передается, а подпроект монтируется в глобальный, используя этот объект родительского проекта.router
Просто прыгай.
Но есть немного несовершенства, так что это может только пройтиjs
Для перехода ссылка перехода не может использовать контекстное меню, которое поставляется вместе с браузером (как показано на рисунке:Chrome
Встроенное контекстное меню ссылок)
Проблемы коммуникации проекта
Не допускайте слишком большого количества зависимостей данных между проектами, ведь проекты по-прежнему должны выполняться независимо. Коммуникационные операции должны определить,qiankun
режим, сделайте совместимую обработку.
пройти черезprops
Передать родительский проектVuex
, если подпроектvue
Стек технологий будет работать хорошо. Если подпроектjQuery/react/angular
, он не может хорошо отслеживать изменения данных.
qiakun
обеспечивает глобальноеGlobalState
для обмена данными. После инициализации основного проекта подпроекты могут отслеживать изменения этих данных, а также могут отправлять эти данные.
// 主项目初始化
import { initGlobalState } from 'qiankun';
const actions = initGlobalState(state);
// 主项目项目监听和修改
actions.onGlobalStateChange((state, prev) => {
// state: 变更后的状态; prev 变更前的状态
console.log(state, prev);
});
actions.setGlobalState(state);
// 子项目监听和修改
export function mount(props) {
props.onGlobalStateChange((state, prev) => {
// state: 变更后的状态; prev 变更前的状态
console.log(state, prev);
});
props.setGlobalState(state);
}
vue
При передаче данных между проектами по-прежнему используются общие родительские компоненты.Vuex
Удобнее общаться с другими проектами стека технологийqiankun
который предоставилGlobalState
.
Как общие плагины распределяются между подпроектами
Если и основной проект, и подпроекты используют одну и ту же версиюVue/Vuex/Vue-Router
Подождите, после того, как основной проект загружен один раз, подпроекты загружаются снова, что очень расточительно.
Для повторного использования общих зависимостей предварительным условием является то, что подпроекты должны быть настроеныexternals
, чтобы зависимости не были упакованы вchunk-vendors.js
, чтобы повторно использовать существующие общедоступные зависимости.
Внедрение публичных зависимостей по требованию имеет два уровня:
- Неиспользуемые зависимости не загружаются
- Большие плагины загружают только те части, которые им нужны, например.
UI
Загрузка библиотек компонентов по требованию,echarts/lodash
загрузка по запросу.
webpack
изexternals
Введено по запросу для поддержки больших плагинов:
subtract : {
root: ['math', 'subtract']
}
subtract
через глобальныйmath
свойства под объектомsubtract
доступ (например,window['math']['subtract']
).
single-spa
Общие зависимости подпроектов могут быть импортированы по запросу
single-spa
это использоватьsystemJs
Загружайте подпроекты и общедоступные зависимости, настраивайте общедоступные зависимости и подпроекты вместе, чтобыsystemJs
файл конфигурацииimportmap.json
, вы можете добиться загрузки общедоступных зависимостей по требованию:
{
"imports": {
"appVueHash": "http://localhost:7778/app.js",
"appVueHistory": "http://localhost:7779/app.js",
"single-spa": "https://cdnjs.cloudflare.com/ajax/libs/single-spa/4.3.7/system/single-spa.min.js",
"vue": "https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js",
"vue-router": "https://cdn.jsdelivr.net/npm/vue-router@3.0.7/dist/vue-router.min.js",
"echarts": "https://cdn.bootcss.com/echarts/4.2.1-rc1/echarts.min.js"
}
}
qiankun
Как ввести общие зависимости по требованию
Публичные зависимости и публичные функции приложения Big Mac используются слишком большим количеством страниц, что затрудняет обновление и изменение.Использование микрофронтенда позволяет каждому подпроекту независимо иметь свои зависимости, не мешая друг другу. И мы хотим повторно использовать публичные зависимости, что противоречит концепции микрофронтендов.
Итак, моя идея такова: родительский проект предоставляет общедоступные зависимости, а дочерний проект может свободно выбирать, использовать его или нет.
Это также очень легко реализовать: родительский проект сначала загружает зависимости, а затем при регистрации дочернего проектаVue/Vuex/Vue-Router
переждатьprops
В прошлом подпроекты могли выбирать, использовать их или нет.
Основной проект:
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import { registerMicroApps, start } from 'qiankun';
import Vuex from 'vuex';
import VueRouter from 'vue-router';
new Vue({
router,
store,
render: h => h(App)
}).$mount("#app");
registerMicroApps([
{
name: 'app-vue-hash',
entry: 'http://localhost:1111',
container: '#appContainer',
activeRule: '/app-vue-hash',
props: { data : { store, router, Vue, Vuex, VueRouter } }
},
]);
start();
Подпроект:
import Vue from 'vue'
export async function bootstrap() {
console.log('vue app bootstraped');
}
export async function mount(props) {
console.log('props from main framework', props);
const { VueRouter, Vuex } = props.data;
Vue.use(VueRouter);
Vue.use(Vuex);
render(props.data);
}
export async function unmount() {
instance.$destroy();
instance = null;
router = null;
}
Это невозможно по двум причинам:
- Когда подпроекты выполняются независимо,
Vue-Router/Vuex
Откуда берутся эти зависимости? Подпроекты развертываются только один раз, и их можно запускать независимо илиqiankun
интегрированный. - Родительский проект может передавать только те зависимости, которые у него уже есть. Как определить, какие зависимости нужны дочернему проекту? Не отвечает потребностям внедрения по требованию
настроитьwebpack
изexternals
После этого при независимом запуске подпроекта источник этих зависимостейесть и только index.html
внешние ссылки вscript
Этикетка.
В соответствии с этой предпосылкой подпроект и основной проектvue
Если версии одинаковые, используйте один и тот же файл сервера. Даже если вы не можете поделиться, вы можетеhttp
кэшировано.
Такqiankun
Можно ли сделать так, чтобы после загрузки определенной зависимости она не загружалась и не использовалась напрямую? Скажем, подпроект A запрашивает версию 2.6 на сервере.vue
, переключитесь на подпроект B, который также использует этотvue
Можно ли повторно использовать файл напрямую, не загружая его снова?
На самом деле, это возможно, вы можете видетьqiankun
Внешняя ссылка подпроектаscript
После того, как содержимое будет запрошено, оно будет записано в глобальную переменную, и при следующем повторном использовании оно будет сначала взято из этой глобальной переменной. Это позволит реализовать повторное использование контента, если гарантированы две ссылки.url
Вы можете согласиться.
const fetchScript = scriptUrl => scriptCache[scriptUrl] ||
(scriptCache[scriptUrl] = fetch(scriptUrl).then(response => response.text()));
Итак, пока подпроект настроенwebpack
изexternals
, И вindex.html
Используйте внешние ссылки вscript
Когда эти общедоступные зависимости вводятся, пока эти общедоступные зависимости находятся на одном сервере, общедоступные зависимости подпроектов могут быть импортированы по запросу.После использования одного проекта другой проект не будет загружать его повторно, и файл могут быть повторно использованы напрямую.
qiankun
Более совершенное введение по запросу
Несмотря на то чтоqiankun
не будет повторять тот же запросurl
общедоступные зависимости, но это также толькоhttp
Кэш немного мощнее.
Недостатки:
- Общие зависимости в основном проекте не записываются в этот кеш и не будут повторно использоваться другими проектами.
- Просто повторного запроса нет, и его все равно нужно повторить один раз. Можно ли его использовать повторно без исполнения? .
js
Песочница удаляется при удалении подпроектаwindow
новые переменные наwebpack
изexternals
Именно для монтирования этих публичных зависимостей вwindow
Можете ли вы удалить эти общедоступные зависимости в зависимости от ситуации? - Зависимости одной и той же версии будут использоваться повторно. Версии разные, но использование одинаковое. Можно ли использовать повторно? (разные версии
url
Он тоже другой, переиспользоваться не будет) Но тут могут быть некоторые сомнения, раз разницы в использовании нет, то почему бы не обновить плагин?
Эти вопросы, возможно, должны быть измененыqiankun
исходный код.
jQuery
Проблема с загрузкой ресурсов для старых проектов
Тег содержимого дочернего проекта вставляется в тег содержимого родительского проекта.index.html
После этого ресурсы в нем (img/video/audio
и т. д.) все пути являются относительными, что приводит к неправильному отображению ресурсов. Выше я перечислил три решения.
Вообще говоря,jQuery
Проект не проходитwebpack
Упакован, поэтому его нельзя изменитьpublicPath
ввести префикс пути. Последние два метода более хлопотны в эксплуатации, иначе мы должныприоритет от самого фреймворкарешить эту проблему, а не наоборот. Поэтому я подумал о следующих трех вариантах:
Вариант 1: динамическая вставка<base>
Этикетка
html
имеет родной тег<base>
, эта метка может быть размещена только в<head>
внутри, егоhref
собственность - этоurl
ценность.mdn
адрес:корневой URL-элемент базового документа
уже настроен<base>
После тега все ссылки на странице иurl
на его основеhref
. Например, адрес доступа к страницеhttps://www.taobao.com
,настраивать<base href="https://www.baidu.com">
После этого исходное изображение на странице<img src="./img/jQuery1.png" alt="">
Фактический адрес запроса станетhttps://www.baidu.com/img/jQuery1.png
, на странице<a>
Ссылка на сайт:<a href="/about"></a>
, после нажатия страница перейдет на:https://www.baidu.com/about
можно увидеть,<base>
этикетки иwebpack
изpublicPath
имеют тот же эффект, то может лиjQuery
Перед загрузкой проекта поместитеjQuery
Адрес проекта закреплен за<base>
Отметьте, затем вставьте<head>
? это решитjQuery
Проблема загрузки ресурсов проекта.
Это также очень просто, т.qiankun
который предоставилbeforeLoad
Жизненный цикл, чтобы определить, является ли текущийjQuery
проект:
beforeLoad: app => {
if(app.name === 'purehtml'){
const baseTag = document.createElement('base');
baseTag.setAttribute('href',app.entry);
console.log(baseTag);
document.head.appendChild(baseTag);
}
},
beforeUnmount: app => {
if(app.name === 'purehtml'){
const baseTag = document.head.querySelector('base');
document.head.removeChild(baseTag);
}
}
При этом ресурсы подпроекта загружаются корректно, но<base>
Сила метки слишком сильна, что приведет к тому, что все маршруты не смогут нормально переходить.<a>
ссылка основана на<base>
Да, будет прыгатьjQuery
Несуществующие маршруты для подпроектов. решил одинbug
, новыйbug
, это невозможно. Поэтому целесообразность этой схемы очень мала.
Вариант 2: взломать функцию вставки этикетки
Эта схема состоит из двух шагов:
- за
HTML
существующий вimg/audio/video
этикетка и т. д.,qiankun
переписатьgetTemplate
функция, вы можете поместить файл вводаindex.html
Замените путь к статическому ресурсу в - для динамически вставленных
img/audio/video
тэги, угонappendChild
,innerHTML
,insertBefore
и другие события, замените относительный путь ресурса абсолютным путем
Как мы упоминали ранее, для подпроектовHTML entry
из,qiankun
получить входной файлindex.html
После этого он будет сопоставлен с обычным<body>
этикетки и их содержимое,<head>
серединаlink/style/script/meta
т. д. теги, затем вставляются в контейнер родительского элемента.
мы можем передатьgetTemplate
функция для преобразования относительного пути изображения в абсолютный путь, который будет использоваться при обработке шаблонов:
start({
getTemplate(tpl,...rest) {
// 为了直接看到效果,所以写死了,实际中需要用正则匹配
return tpl.replace('<img src="./img/jQuery1.png">', '<img src="http://localhost:3333/img/jQuery1.png">');
}
});
Для динамически вставляемых тегов перехватите их вставкуDOM
функция, введите префикс.
Если подпроект динамически вставляет картинку:
const render = $ => {
$('#purehtml-container').html('<p>Hello, render with jQuery</p><img src="./img/jQuery2.png">');
return Promise.resolve();
};
Угон основного предметаjQuery
изhtml
метод:
beforeMount: app => {
if(app.name === 'purehtml'){
// jQuery 的 html 方法是一个挺复杂的函数,这里只是为了看效果,简写了
$.prototype.html = function(value){
const str = value.replace('<img src="/img/jQuery2.png">', '<img src="http://localhost:3333/img/jQuery2.png">')
this[0].innerHTML = str;
}
}
}
Конечно, есть и простой и грубый способ письма, дающийjQuery
Путь к образу проекта записывается как абсолютный путь, но это не рекомендуется, и это не сработает, если вы измените развертывание сервера.
Вариант третий: датьjQuery
пункт плюсwebpack
Бэйл
Реализуемость этого плана не высока.Это старый-престарый проект, так что не стоит делать такой жеребьевки.
Сводка загрузки ресурсов старых проектов
qiankun
получить доступ к себеjQuery
Многостраничные приложения относительно слабы, общий сценарий использования — большой проект обращается только к одной/нескольким страницам, в этом случае более разумен второй вариант.
qiankun
Использовать сводку
-
Чтобы включить предварительную загрузку, когда есть только один подпроект, вы должны использовать
start({ prefetch: 'all' })
-
js
Песочница не решает всегоjs
загрязнение, например, я используюonclick
илиaddEventListener
давать<body>
Добавлено событие клика,js
Песочница не исключает его влияния, поэтому приходится полагаться на спецификацию кода и самосознание -
qiankun
Фреймворк не очень прост в реализацииkeep-alive
потребности, потому что решениеcss/js
Способ загрязнения - удалить вставленный подпроектcss
Тегирование и угонwindow
объекта, при выгрузке он восстанавливается до того, каким он был до загрузки подпроекта, что аналогичноkeep-alive
Противоречие:keep-alive
Просьба сохранить их — это просто стилистическое сокрытие. -
qiankun
Не могу хорошо встроить некоторые старые проекты
Несмотря на то чтоqiankun
служба поддержкиjQuery
Старый проект, но вроде правильныймногостраничное приложениеНет хорошего решения. Модифицировать каждую страницу очень дорого и хлопотно, но с помощьюiframe
Эти старые проекты удобнее встраивать.
- проблемы с безопасностью и производительностью
qiankun
каждого подпроектаjs/css
Содержимое файла записывается в глобальную переменную.Если подпроектов слишком много или размер файла большой, это может привести к чрезмерному использованию памяти и зависанию страницы.
Кроме того,qiankun
запустить подпроектjs
, не черезscript
теги вставляются, но черезeval
функция реализована,eval
Безопасность и выполнение функций несколько спорны:Предварительное введение MDN
- При отладке микрофронтенда вам нужно вводить подпроект и основной проект для запуска и упаковки каждый раз отдельно, что очень хлопотно и может быть использовано
npm-run-all
Плагины для достижения: одна команда для запуска всех проектов.
{
"scripts": {
"install:hash": "cd app-vue-hash && npm install",
"install:history": "cd app-vue-history && npm install",
"install:main": "cd main && npm install",
"install:purehtml": "cd purehtml && npm install",
"install-all": "npm-run-all install:*",
"start:hash": "cd app-vue-hash && npm run serve ",
"start:history": "cd app-vue-history && npm run serve",
"start:main": "cd main && npm run serve",
"start:purehtml": "cd purehtml && npm run serve",
"start-all": "npm-run-all --parallel start:*",
"serve-all": "npm-run-all --parallel start:*",
"build:hash": "cd app-vue-hash && npm run build",
"build:history": "cd app-vue-history && npm run build",
"build:main": "cd main && npm run build",
"build-all": "npm-run-all --parallel build:*"
}
}
в--parallel
Параметр указывает на параллелизм, без этого параметра следующая команда будет выполняться после выполнения предыдущей команды.
конец
неiframe
Предубеждение, это тоже реализация микро-фронтенда, если нет всплывающего окна, нет полноэкранного режима и прочих операций на странице,iframe
Это также очень полезно. настроить кеш иcdn
Ускорение, если это интранет-доступ, будет не очень медленным.
iframe
иqiankun
могут сосуществовать,jQuery
Использование многостраничного приложенияiframe
Доступ очень хороший.Когда и какой сценарий следует использовать, какое решение следует использовать, и конкретная ситуация будет подробно проанализирована.
Наконец, если есть какие-либо проблемы или ошибки в статье, пожалуйста, укажите, спасибо!
В содержании статьи есть некоторые дополнения, но эта статья не может быть записана, см.:Краткое изложение практики qiankun micro front-end (2)
приложение
single-spa
иqiankun
изdemo
Как реализовать и некоторые принципы, вы можете увидеть в этих трех моих статьях:
- Внедрение внешнего микросервиса с 0 (на)
- Внедрение внешнего микросервиса single-spa с 0 (средний уровень)
- Внедрение внешнего микросервиса single-spa с 0 (ниже)
PS: Третья статья была написана в марте этого года, в ней участвовалиqiankun
Исходный код версии 1.0,qiankun
Версия 2.0 была выпущена в апреле, но ее основные принципы практически не изменились.
Взгляды и практика других фронтенд-команд в отрасли на микрофронтенды:
- Преобразование микроинтерфейса команды фронтенда ежедневной цепочки поставок превосходных свежих продуктов
- Практика микро-интерфейса на вынос Meituan
- Полировка и применение интерфейсных микросервисов в ByteDance
- Практика микроинтерфейса в CRM-системе Xiaomi
- Реализация стандартной архитектуры микроинтерфейса в Ant
qiankun
онлайн-кейсов