1. Происхождение микроинтерфейса
С развитием историзации внешнего интерфейса появились два режима разработки внешнего интерфейса: режим многостраничного приложения MPA и режим одностраничного приложения SPA, каждый из которых имеет свою уникальность и недостатки.
(1) режим МРА
Например, средняя фоновая система охватывает несколько бизнес-модулей, за которые отвечают разные команды, и каждый бизнес-модуль имеет независимые доменные имена.Доступ к различным бизнес-модулям приведет к повторному обновлению браузера или недавно открытой страницы ярлыков для внедрения системы. . Преимущество режима MPA заключается в том, что развертывание простое, а различные бизнес-модули изолированы, естественный стек технологий является независимым, независимо разработанным, независимо развернутым; его недостатки также очевидны, переключение между различными модулями вызовет просмотр, другой продукт доменные имена В процессе работы будут очевидные точки останова.
(2) СПА-режим
Я считаю, что интерфейсные приложения сейчас почти созданы и разрабатываются тремя основными вагонами SPA: Vue, React и Angular.Переходы страниц между приложениями выгружаются/монтируются путем прослушивания URL-адреса браузера, поэтому преимущество в том, что это имеет неотъемлемые преимущества в опыте. Нет необходимости обновлять браузер для переключения между несколькими продуктами, что может в значительной степени обеспечить поток операций процесса между несколькими продуктами. Микроинтерфейс — это архитектура, аналогичная микросервисам, которая применяет концепцию микросервисов к стороне браузера, то есть одностраничное интерфейсное приложение преобразуется из единого монолитного приложения в приложение, объединяющее несколько небольшие интерфейсные приложения в одно. Он сочетает в себе преимущества режима MPA и режима SPA, а обычная архитектура микро-фронтенда имеет следующие преимущества:
-
Независимость от стека технологий: используйте несколько интерфейсных фреймворков на одной странице без обновления страницы (Vue, React, Angular и т. д.);
-
Сильная независимость: независимая разработка, независимое развертывание и постепенное обновление различных бизнес-приложений;
-
Изоляция и совместное использование во время выполнения: данные могут совместно использоваться и передаваться между различными бизнес-подприложениями, но js и css не могут влиять друг на друга;
-
Преимущество опыта: он обеспечивает непрерывность работы одностраничного приложения, и переключение страниц не требует обновления;
2. Проблемы с фреймами
在早期,微前端概念出现之前,我们整合多个团队多个应用,我们不约而同的选择即为 iframe。 Самая большая особенность iframe заключается в том, чтобы обеспечить собственное решение жесткой изоляции браузера, будь то изоляция стиля, изоляция js и другие проблемы, которые могут быть идеально решены.但它的最大问题也在于它的隔离性无法被突破,导致应用间上下文无法被共享,随之带来的开发体验、产品体验的问题。
-
URL-адрес не синхронизирован. Состояние URL-адреса обновления браузера iframe теряется, кнопки «Назад» и «Вперед» использовать нельзя.
-
Пользовательский интерфейс не синхронизирован, и структура dom не используется совместно. Представьте всплывающее окно с маской слоя в iframe в правом нижнем углу экрана, при этом мы требуем, чтобы это всплывающее окно отображалось в центре браузера, а также автоматически центрировалось при размер браузера изменился..
-
Глобальный контекст полностью изолирован, а переменные памяти не используются совместно. Для обеспечения связи и синхронизации данных внутренней и внешней систем iframe файл cookie основного приложения должен быть прозрачно передан в подприложения с разными корневыми доменными именами для достижения эффекта отсутствия входа в систему.
-
Первая партия подприложений работает медленно. Каждая запись подприложения — это процесс перестройки контекста браузера и перезагрузки ресурсов.
Три, пример с одним спа
single-spa является краеугольным камнем многих фреймворков микро-интерфейса (сам по себе является фреймворком микро-интерфейса, но многие крупные производители и фреймворки микро-интерфейса осуществляют вторичную инкапсуляцию на его основе), поэтому глубокое понимание его принципы являются основой для исследования и практики микроинтерфейса. single-spa — это инфраструктура микроинтерфейса javascript, которая объединяет несколько одностраничных приложений в монолитное приложение. Конкретный учебник и API single-spa можно просмотретьофициальный сайт спа-салона, Также рекомендуется, чтобы при чтении следующих глав вы сначала кратко прочитали его официальный сайт, чтобы узнать, что это такое и что оно может делать. В этой главе мы напрямую используем практические примеры, представленные на официальном веб-сайте single-spa, для описания использования single-spa и переходим к принципиальному анализу следующей главы с размышлениями, лежащими в основе этого явления.
1. Клонируйте экземпляр проекта
git clone https://github.com/joeldenning/coexisting-vue-microfrontends.git
2. Запустите проект
В каталогах базового приложения и подприложения установите пакеты зависимостей соответственно, а затем запустите приложения соответственно:
// root-html-file
cd root-html-file
npm install
npm run serve
// navbar
cd navbar
npm install
npm run serve
// app1
cd app1
npm install
npm run serve
// app2
cd app2
npm install
npm run serve
3. Наблюдение за примерами и размышление
(1) Мы смотрим на пример кода базового приложения. Регистрация подприложения (registerApplication) в базовом приложении вызывает функцию registerApplication single-spa, и то, что реализовано внутри. Начал делать Что, как это работает внутренне?
(2) Мы смотрим на входной исполняемый файл main.js субприложения и обнаруживаем, что субприложение будет экспортировать три периодические функции bootstrap/mount/unmount Когда эти три периодические функции выполняются?
(3) Доступ через браузерhttp://localhost:5000/, доступны следующие страницы. Глядя на пример кода, мы можем обнаружить, что следующая страница является страницей панели навигации базового приложения, как single-spa соответствует этому маршруту, а нажатие на App1 и App2 приведет к переходу на страницы приложения app1 и app2. приложения соответственно, и страница не будет обновляться, что является ключевой функциональной точкой сопоставления маршрутов с одним спа-адресом;
(4) Мы продолжаем нажимать на App1 App2 и наблюдаем за опцией вкладки сети в окне отладки браузера.Мы обнаружим, что при переключении на другое подприложение ресурсы, необходимые для рендеринга подприложения, будут загружены только тогда, когда под- приложение рендерится в первый раз. , последующее переключение не будет загружать связанные ресурсы; наблюдая за опцией Elements окна отладки браузера, мы обнаружим, что: структура Dom различных подприложений будет монтироваться и выгружаться соответственно с переключением суб-приложений, что single-spa Как загружать, монтировать и выгружать ресурсы суб-приложений?
Если вы не знаете, зачем нужны некоторые из вышеперечисленных явлений или реализаций, и очень хотите разобраться в принципах, то вам подойдет содержание следующей главы — Анализ принципов.
4. Принцип одиночного спа
Обобщите принцип single-spa в одном предложении: **single-spa — это конечный автомат. Фреймворк отвечает только за поддержание состояния каждого подприложения. -приложения и т. д. все определяются самими подприложениями.Контроль, поэтому инфраструктура с одним спа имеет хорошую расширяемость. **У нас можно заказатьОдин-спа Официальный сайт GitHubПроверьте исходный код клона.Исходный код функции sinlge-spa в основном сосредоточен в каталоге src.Основные функции каждого файла в каталоге src резюмируются следующим образом.
После того, как мы поймем общий каталог исходного кода и функции, мы вернемся назад и рассмотрим принципы некоторых API и функций во второй части один за другим. В пояснении некоторых комментариев к коду мы опускаем некоторые проверки параметров, не влияющие на понимание принципа.
1. Что делает регистрация приложения register?
Метод регистрации приложения registerApplication определен в файле /src/applications/app.js. Код и комментарии выглядят следующим образом. В основном он делает три вещи:
-
sanitizeArguments: нормализация параметров, чтобы гарантировать, что параметры, зарегистрированные каждым подприложением, являются допустимыми;
-
apps.push: добавление зарегистрированных подприложений в массив приложений и добавление внутренних свойств для каждого подприложения, таких как статус очень важного атрибута, чтобы отметить статус подприложения;
-
REROUTE: этот метод фокусируется на следующем разделе, мы временно и знаем, что метод в методе будет определять, зарегистрирована ли загрузка ресурсов (метод LoadApps), и добавляет связанные крючки жизненного цикла в APP дочернего приложения при загрузке (TOLOADPROMIMIMIMIMIMIMIMIMIMIMI);
(1) Код метода регистрации registerApplication выглядит следующим образом:
export function registerApplication(
appNameOrConfig,
appOrLoadApp,
activeWhen,
customProps
) {
// hb: 格式化用户传入的应用配置参数,保证传入的参数是合法的
const registration = sanitizeArguments(
appNameOrConfig,
appOrLoadApp,
activeWhen,
customProps
);
// hb: 已经存在相同名称的应用报错
if (getAppNames().indexOf(registration.name) !== -1)
throw Error(
formatErrorMessage(
21,
__DEV__ &&
`There is already an app registered with name ${registration.name}`,
registration.name
)
);
// 将每个应用的配置信息都存放到 apps 数组中
apps.push(
assign(
{
loadErrorTime: null,
status: NOT_LOADED,
parcels: {},
devtools: {
overlays: {
options: {},
selectors: [],
},
},
},
registration
)
);
if (isInBrowser) {
ensureJQuerySupport();
reroute();
}
}
(2) Код метода loadApps выглядит следующим образом:
// hb: 整体返回一个立即resolved的promise,通过微任务来加载apps
function loadApps() {
return Promise.resolve().then(() => {
// hb: 返回封装后的 app,包括给其附上生命周期等
const loadPromises = appsToLoad.map(toLoadPromise);
console.log('查看 loadPromises :', loadPromises);
return (
Promise.all(loadPromises)
.then(callAllEventListeners)
// there are no mounted apps, before start() is called, so we always return []
.then(() => [])
.catch((err) => {
callAllEventListeners();
throw err;
})
);
});
}
(3) Основной код метода toLoadPromise выглядит следующим образом:
export function toLoadPromise(app) {
return Promise.resolve().then(() => {
if (app.loadPromise) {
// hb: 说明 app 已经被加载
return app.loadPromise;
}
if (app.status !== NOT_LOADED && app.status !== LOAD_ERROR) {
return app;
}
app.status = LOADING_SOURCE_CODE;
let appOpts, isUserErr;
return (app.loadPromise = Promise.resolve()
.then(() => {
// hb: loadApp 即是用户传入的参数 () => System.import('navbar'),
// 所以加载子应用其实就是通过用户自己传入的加载方式,即使如果不用 System.import 也可以;
// 没有明白属性获取来干嘛用 getProps(app) ???
const loadPromise = app.loadApp(getProps(app));
// hb: 子应用导出的必须是个对象,且包含 3 个生命周期:bootstrap、mount、unmount
return loadPromise.then((val) => {
app.loadErrorTime = null;
appOpts = val;
app.status = NOT_BOOTSTRAPPED;
// hb: 在app对象上挂载生命周期方法,每个方法都接收一个props作为参数,方法内部执行子应用导出的生命周期函数,并确保生命周期函数返回一个promise
app.bootstrap = flattenFnArray(appOpts, "bootstrap");
app.mount = flattenFnArray(appOpts, "mount");
app.unmount = flattenFnArray(appOpts, "unmount");
app.unload = flattenFnArray(appOpts, "unload");
app.timeouts = ensureValidAppTimeouts(appOpts.timeouts);
// hb: 执行到这里说明子应用已成功加载,删除app.loadPromise属性
delete app.loadPromise;
return app;
});
})
.catch((err) => {
// hb: 加载失败,稍后重新加载
delete app.loadPromise;
let newStatus;
if (isUserErr) {
newStatus = SKIP_BECAUSE_BROKEN;
} else {
newStatus = LOAD_ERROR;
app.loadErrorTime = new Date().getTime();
}
handleAppError(err, app, newStatus);
return app;
}));
});
}
2. Что делает метод start?
Мы уже знаем из предыдущего раздела, что registerApplication загрузит зарегистрированное субприложение, и URL-адрес совпадает, то есть, если только зарегистрирован, ресурсы, соответствующие субприложению, будут загружены, но оно не будет инициализировано. или визуализируется; то функция метода запуска состоит в инициализации и отображении подприложения. Код выглядит следующим образом. Мы можем видеть, что метод перенаправления в основном вызывается в методе запуска. В методе перенаправления он будет различать, является ли он до или после старта В этом разделе говорится о загрузке ресурсов субприложения во время регистрации, если после старта, вызовите метод PerformAppChanges для выполнения соответствующих операций над субприложениями в разных состояниях
-
appsToUnload // Приложения, которые необходимо удалить, удаляются
-
Appstounmount // Приложение должно быть удалено для удаления
-
appsToLoad // Загружается приложение, которое нужно загрузить
-
appsToMount // Необходимо смонтировать приложения для монтирования
(1) код метода запуска
// hb: 调用 start 之前,应用会被加载,但不会初始化、挂载和卸载,有了 start 可以更好的控制应用的流程
export function start(opts) {
started = true;
if (opts && opts.urlRerouteOnly) {
setUrlRerouteOnly(opts.urlRerouteOnly);
}
if (isInBrowser) {
reroute();
}
}
(2) метод перенаправления
export function reroute(pendingPromises = [], eventArguments) {
const {
appsToUnload, // hb: 需要被移除的
appsToUnmount, // hb: 需要被卸载的
appsToLoad, // hb: 需要被加载的
appsToMount, // hb: 需要被挂载的
} = getAppChanges();
let appsThatChanged;
// hb: 是否 start 调用 isStarted 为 false 时表示是 start 调用
if (isStarted()) {
appChangeUnderway = true;
appsThatChanged = appsToUnload.concat(
appsToLoad,
appsToUnmount,
appsToMount
);
return performAppChanges();
} else {
appsThatChanged = appsToLoad;
return loadApps();
}
// hb: 整体返回一个立即resolved的promise,通过微任务来加载apps
function loadApps() {
return Promise.resolve().then(() => {
// hb: 返回封装后的 app,包括给其附上生命周期等
const loadPromises = appsToLoad.map(toLoadPromise);
return (
Promise.all(loadPromises)
.then(callAllEventListeners)
// there are no mounted apps, before start() is called, so we always return []
.then(() => [])
.catch((err) => {
callAllEventListeners();
throw err;
})
);
});
}
function performAppChanges() {
return Promise.resolve().then(() => {
// hb: 移除应用 => 更改应用状态,执行unload生命周期函数,执行一些清理动作
// 其实一般情况下这里没有真的移除应用
const unloadPromises = appsToUnload.map(toUnloadPromise);
// hb: 先卸载再移除
const unmountUnloadPromises = appsToUnmount
.map(toUnmountPromise)
.map((unmountPromise) => unmountPromise.then(toUnloadPromise));
const allUnmountPromises = unmountUnloadPromises.concat(unloadPromises);
const unmountAllPromise = Promise.all(allUnmountPromises);
unmountAllPromise.then(() => {
window.dispatchEvent(
new CustomEvent(
"single-spa:before-mount-routing-event",
getCustomEventDetail(true)
)
);
});
// hb: 待加载的进行加载 并且进行挂载
const loadThenMountPromises = appsToLoad.map((app) => {
return toLoadPromise(app).then((app) =>
tryToBootstrapAndMount(app, unmountAllPromise)
);
});
// hb: 待挂载的进行挂载
const mountPromises = appsToMount
.filter((appToMount) => appsToLoad.indexOf(appToMount) < 0)
.map((appToMount) => {
return tryToBootstrapAndMount(appToMount, unmountAllPromise);
});
return unmountAllPromise
.catch((err) => {
callAllEventListeners();
throw err;
})
.then(() => {});
});
}
}
3. Момент времени выполнения функции жизненного цикла, экспортируемой субприложением.
Мы проверили входной исполняемый файл main.js субприложения и обнаружили, что субприложение будет экспортировать три периодические функции bootstrap/mount/unmount Когда эти три периодические функции выполняются? Фактически, после загрузки ресурсов подприложения функция жизненного цикла подприложения будет добавлена в свойства приложения (каждое подприложение в single-spa является объектом приложения, а затем агрегировано в массив apps), и тогда single-spa будет в подприложении, при обновлении состояния app соответственно выполняется его функция жизненного цикла.
(1) Код в методе загрузки, который обрабатывает метод жизненного цикла в поддержании
export function toLoadPromise(app) {
app.status = NOT_BOOTSTRAPPED;
// hb: 在app对象上挂载生命周期方法,每个方法都接收一个props作为参数,方法内部执行子应用导出的生命周期函数,并确保生命周期函数返回一个promise
app.bootstrap = flattenFnArray(appOpts, "bootstrap");
app.mount = flattenFnArray(appOpts, "mount");
app.unmount = flattenFnArray(appOpts, "unmount");
app.unload = flattenFnArray(appOpts, "unload");
app.timeouts = ensureValidAppTimeouts(appOpts.timeouts);
});
})
(2) метод flattenFnArray
// hb: 返回一个接受 props 作为参数的函数,这个函数负责执行子应用中的生命周期函数,
// 并确保生命周期函数返回的结果为promise
export function flattenFnArray(appOrParcel, lifecycle) {
let fns = appOrParcel[lifecycle] || [];
fns = Array.isArray(fns) ? fns : [fns];
if (fns.length === 0) {
fns = [() => Promise.resolve()];
}
return function (props) {
return fns.reduce((resultPromise, fn, index) => {
return resultPromise.then(() => {
const thisPromise = fn(props);
});
}, Promise.resolve());
};
}
4. Переключение подприложений
В этом примере обнаружено, что наше базовое приложение может монтировать/выгружать наши подприложения в соответствии с разными URL-адресами без обновления страницы, так как же single-spa соответствует маршруту URL-адреса? На самом деле, если вы поняли принцип переключения маршрутизации одностраничных приложений, таких как vue-router и react-router, это не что иное, как применение события hashchange для отслеживания изменения хеш-маршрута и события popstate для отслеживания изменение маршрута истории.Принцип сопоставления маршрута url точно такой же (базовый апи только те, его еще можно изменить), а связанные операции определяются в файле /src/navigation/navigation-events.js файл.
window.addEventListener("hashchange", urlReroute);
window.addEventListener("popstate", urlReroute);
И когда мы зарегистрировали субприложение, мы передали правило сопоставления маршрутизации субприложения в качестве параметра, и single-spa использует это условие оценки соответствия входящего маршрута в /src/applications/app.helpers.js для оценки субприложения. Должен ли он быть в активном (подключенном) состоянии, соответствующий код выглядит следующим образом, где app.activeWhen — функция сопоставления входящего маршрута. На данный момент мы почти знаем, как single-spa соответствует соответствующему подприложению при переключении URL.
// hb: 是否应该活跃状态(url 匹配到路由)
export function shouldBeActive(app) {
try {
return app.activeWhen(window.location);
} catch (err) {
handleAppError(err, app, SKIP_BECAUSE_BROKEN);
return false;
}
}
5. Как монтировать/размонтировать подприложения
Мы уже знаем из вышесказанного, одной спа управления изменений состояния суб-приложений, таких как загрузка ресурсов суб-приложений во время регистрации, а также монтаж / выгрузки суб-приложений. В третьей главе, мы проходим, когда мы зарегистрировать приложение . метод загрузки из System.import используется для загрузки, и нет ресурсов загрузки метод внутри одного-шпа, насчет монтирования / деинсталляции? На самом деле, установка / разгрузка также осуществляется через соответствующие жизненный цикл функции, передаваемые в каждом субприложении сам. Давай проверит крепление / выгрузки жизненного цикл функция плагина одного сп-вю (не одного спа), используемая суб- приложения. Вы можете видеть , что соответствующие функции жизненного цикла монтирует и выгружает элементы DOM. В одном-шпа, он выполняет только функцию жизненного цикла , соответствующего субприложения в соответствующем состоянии суб-приложений. Сам сингл-шпа только играет роль контроля состояния. И так далее, это может также достичь лучшего масштабируемость, как пользователи хотят скачать, установить и деинсталлировать, они решают сами по себе, до тех пор, как вы передаете в стандартных параметрах.
(1) Методы жизненного цикла с одним спа-VEUE
// 挂载生命周期函数
function mount(opts, mountedInstances, props) {
return Promise
.resolve()
.then(() => {
const appOptions = {...opts.appOptions}
if (props.domElement && !appOptions.el) {
appOptions.el = props.domElement;
}
if (!appOptions.el) {
const htmlId = `single-spa-application:${props.name}`
appOptions.el = `#${htmlId.replace(':', '\\:')} .single-spa-container`
let domEl = document.getElementById(htmlId)
if (!domEl) {
domEl = document.createElement('div')
domEl.id = htmlId
document.body.appendChild(domEl)
}
// single-spa-vue@>=2 always REPLACES the `el` instead of appending to it.
// We want domEl to stick around and not be replaced. So we tell Vue to mount
// into a container div inside of the main domEl
if (!domEl.querySelector('.single-spa-container')) {
const singleSpaContainer = document.createElement('div')
singleSpaContainer.className = 'single-spa-container'
domEl.appendChild(singleSpaContainer)
}
mountedInstances.domEl = domEl
}
if (!appOptions.render && !appOptions.template && opts.rootComponent) {
appOptions.render = (h) => h(opts.rootComponent)
}
if (!appOptions.data) {
appOptions.data = {}
}
appOptions.data = {...appOptions.data, ...props}
mountedInstances.instance = new opts.Vue(appOptions);
if (mountedInstances.instance.bind) {
mountedInstances.instance = mountedInstances.instance.bind(mountedInstances.instance);
}
})
}
// 卸载生命周期函数
function unmount(opts, mountedInstances) {
return Promise
.resolve()
.then(() => {
mountedInstances.instance.$destroy();
mountedInstances.instance.$el.innerHTML = '';
delete mountedInstances.instance;
if (mountedInstances.domEl) {
mountedInstances.domEl.innerHTML = ''
delete mountedInstances.domEl
}
})
}
Я полагаю, что читатели, прочитавшие это, глубоко проникнутся авторским изложением принципа single-spa.**single-spa — это конечный автомат. Фреймворк отвечает только за поддержание состояния каждого подприложения. Как загружать субприложения Приложения, монтирование субприложений, выгрузка субприложений и т. д. контролируются самими субприложениями, поэтому структура single-spa обладает хорошей масштабируемостью. **После прочтения этой главы у меня появилось глубокое понимание механизма работы инфраструктуры single-spa, но single-spa, как архитектура самого низкого уровня, по-прежнему имеет некоторые проблемы в реальной сцене, как показано ниже, в В следующей главе мы сосредоточимся на том, как решить эти проблемы.
-
single-spa использует запись js как запись подприложения, а стоимость модернизации старых проектов высока;
-
Подприложения имеют стили CSS, которые взаимодействуют друг с другом;
-
Существует глобальное загрязнение js в подприложениях;
-
Платформа single-spa не обеспечивает механизма связи между подприложениями или между подприложениями и базовым приложением;
5. Принцип цянькунь
qiankun — это относительно зрелая микроинтерфейсная среда, запущенная Ant Financial, основанная на single-spa для вторичной разработки и используемая для преобразования веб-приложений из одного приложения в несколько небольших интерфейсных приложений. Если вы еще не знакомы с фреймворком, вы можете сначала проверить его.официальный сайт Цянькунь; В этой главе мы в основном сосредоточимся на вопросах, поднятых в третьем разделе, чтобы обсудить, как обращаться с цянькунь (天地).
1. Подприложения работают независимо
использование qiankunimport-html-entry
2. Изоляция стилей CSS
Поскольку в сценарии микроинтерфейса субприложения разных технологических стеков будут интегрированы в одну и ту же среду выполнения, неизбежно возникнет проблема интерференции стилей между субприложениями. Есть две идеи для изоляции стилей.Первая заключается в использовании решения, аналогичного CSS-модулю или БЭМ, что, по сути, позволяет избежать конфликтов из-за условностей.Для новых проектов это решение очень рентабельно, но если оно предполагает использование старые проекты. В совокупности стоимость преобразования будет очень высока; вторая идея — удалить таблицу стилей одновременно с удалением субприложения. Технический принцип заключается в том, что браузер рефакторит всю CSSOM для вставка и удаление всех таблиц стилей. , чтобы достичь цели вставки и выгрузки стилей, что гарантирует, что только одна примененная таблица стилей действительна в определенный момент времени. Фреймворк qiankun принимает вторую идею, используяimport-html-entry, получить информацию о стиле, проанализировав теги и в записи html, загрузить файл стиля и, наконец, вставить его в контейнер основного фрейма в виде тега и удалить его вместе при удалении подприложения, поэтому чтобы избежать конфликтов между различными субприложениями.
3. глобальная изоляция js
По сравнению с изоляцией стиля изоляция js важнее. Потому что в сценарии SPA влияние таких проблем, как утечка памяти и конфликты глобальных переменных, будет усилено, а проблемы в подприложении могут повлиять на работу других приложений. Кроме того, такого рода проблемы обычно очень трудно устранить и локализовать, а если они возникают, то стоимость их решения очень высока. Платформа qiankun обеспечивает среду песочницы для каждого подприложения на основе прокси, и доступ всех подприложений к значениям объекта прокси/окна контролируется. Установленное значение будет применяться только к коллекции updateValueMap внутри песочницы, а значение будет взято сначала из независимого пула состояний субприложений (updateValueMap).Это гарантирует, что глобальные js каждого субприложения конфликтуют друг с другом и загрязняют друг друга.
4. Связь между подприложениями
Обычно мы разделяем каждое подприложение с точки зрения бизнеса, максимально сокращаем общение между приложениями, тем самым упрощая все приложение, делая нашу архитектуру микрофронтенда более гибкой и управляемой, но в некоторых сценариях взаимодействие между под- приложения Связь все еще существует. Платформа qiankun обеспечивает взаимодействие действий (режим наблюдателя) и внутренне предоставляет метод initGlobalState для регистрации экземпляров MicroAppStateActions для связи.У этого экземпляра есть три метода, а именно:
-
setGlobalState: set globalState — при установке нового значения будет выполняться внутренняя поверхностная проверка.Если будет обнаружено, что globalState изменилось, будет запущено уведомление, чтобы уведомить все функции наблюдателя;
-
onGlobalStateChange: зарегистрировать функцию наблюдателя — в ответ на изменения в globalState запускать функцию наблюдателя при изменении globalState;
-
offGlobalStateChange: отменить функцию наблюдателя — экземпляр больше не реагирует на изменения globalState.
6. Резюме
В этой статье рассказывается о происхождении микро-интерфейсов и анализируется необходимость микро-интерфейсов, затем обобщаются некоторые проблемы, существующие в фреймах, используемых для агрегирования приложений, а затем обсуждается принцип реализации единого спа на примере феномена одиночного спа и использование API; Наконец, с помощью фреймворка микро-интерфейса qiankun мы обсудим, какие проблемы необходимо решать в режиме микро-интерфейса в реальных сценариях и как их решить. Шаг за шагом, от понимания микро-фронтенда к пониманию принципа соответствующего фреймворка, к решению проблемы на реальной сцене, чтобы «понять» микро-фронтенд во всех аспектах.
Адрес блога на github:fengshi123 , в котором собраны все блоги автора, приглашаем подписаться и отметиться ~
использованная литература
3.Вероятно, самое полное решение для микроинтерфейса, которое вы когда-либо видели.