предисловие
Всем привет, я морское чудовище.
В области микроинтерфейса, я думаю, все слышали об Али.qiankun. Я использовал его сам в течение последних нескольких месяцев для некоторой практики:
- Краткое изложение практики рефакторинга Micro Front-end x
- Когда микробоковая панель предприятия встречается с микроинтерфейсом
За время использования я обнаружил, что qiankun все же имеет некоторые недостатки:
- Проекты по-прежнему очень навязчивы. Дабы раскрутить его в группе, я сделал 3 шаринга, но это иссушило мне слюну.
- qiankun все еще имеет много ям в песочнице. Просматривая журнал изменений qiankun в прошлом году, я обнаружил, что все они исправляют проблемы, связанные с песочницей.
Не только мне было неудобно использовать qiankun, но и моим друзьям из JD.com тоже было трудно его использовать, поэтому в июле прошлого года JD.com запустила собственное микроинтерфейсное решение——MicroApp. Сегодня давайте впервые взглянем на этот новый интерфейсный фреймворк Star Micro.
характерная черта
MicroApp давай, чтобы указать свою позицию:
micro-appне следилsingle-spaидея.
заимствованныйWebComponentподумал о,micro-appпройти черезCustomElementв сочетании с обычайShadowDom, который инкапсулирует микроинтерфейс в классWebComponentкомпонентов, чтобы реализовать компонентный рендеринг микроинтерфейсов.
это вДок-приложениеа такжедополнительное приложениеОн действует как клей-мост между ними.
Имеет следующие преимущества:
- Простой в использовании.Инкапсулируйте функциональность в WebComponent
- Нулевые зависимости.Нет зависимостей, более высокая масштабируемость
- Совместимость со всеми фреймворкамиНезависимость от стека технологий
Смотрим непосредственно на коробкуmicro-appКакой сюрприз вы можете нам преподнести?
Примечание: все коды размещены вГитхаб проектсередина.
Архитектура
Хотя чиновник тоже дал полныйОбразец, но кода в нем слишком много, поэтому сделаю проект попроще со следующей структурой:
Начало
основное использование приложенияcreate-react-appСоздайте проект React:
npx create-react-app bigass-micro-app
затем установитеmicro-app:
npm i @micro-zoe/micro-app --save
После создания сначала используйте React Router для построения системы маршрутизации базового приложения:
const App = () => {
return (
<BrowserRouter>
<div>
<header className={styles.header}>
<Link to="/">基座 Home</Link>
<Link to="/about">基座 About</Link>
</header>
<Routes>
<Route path="/" element={<Home/>}/>
<Route path="/about" element={<About/>}/>
</Routes>
</div>
</BrowserRouter>
);
}
Есть самый простой маршрут:
Добавьте микроприложения React
Затем мы добавляем еще одно приложение React в качестве микроприложения для этого проекта./appsтакже используется в каталогеcreate-react-appСоздайте новое приложение React иpcakge.jsonИзмените порт доступа в:
"scripts": {
"start": "BROWSER=none PORT=3001 react-scripts start",
}
Добавить кpublic-path.js:
// __MICRO_APP_ENVIRONMENT__和__MICRO_APP_PUBLIC_PATH__是由micro-app注入的全局变量
if (window.__MICRO_APP_ENVIRONMENT__) {
// eslint-disable-next-line
__webpack_public_path__ = window.__MICRO_APP_PUBLIC_PATH__
}
в микроприложенияхпервая строка входаИмпортируйте это:
import './public-path'
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(<App />, document.getElementById('root'));
Этот шаг в основном предназначен для предотвращения сбоя загрузки, когда статические ресурсы подприложения используют относительные адреса.
И настроим междоменный доступ на devServer:
headers: {
'Access-Control-Allow-Origin': '*',
}
Также добавьте простой маршрут:
function App() {
return (
<div>
<BrowserRouter basename={window.__MICRO_APP_BASE_ROUTE__ || '/'}>
<div>
<header className={styles.header}>
<Link to="/">react-app Home</Link>
<Link to="/about">react-app About</Link>
</header>
<Routes>
<Route path="/" element={<Home/>}/>
<Route path="/about" element={<About/>}/>
</Routes>
</div>
</BrowserRouter>
</div>
);
}
Сейчасnpm run startтогда ты можешьhttp://localhost:3001посетите его здесь.
Доступ к микроприложениям React
Впервые применяется на пьедесталеВходвключитьmicro-app:
// index.jsx
import microApp from '@micro-zoe/micro-app'
microApp.start()
ReactDOM.render(<App />, document.getElementById('root'));
Затем добавьте в базовое приложение компонент, в котором размещается микроприложение.ReactMicroApp:
// ReactMicroApp.jsx
const ReactMicroApp = () => {
return (
<div>
<h1>react-app</h1>
<micro-app
name='react-app'
url='http://localhost:3001/'
baseroute='/react-app'
>
</micro-app>
</div>
)
}
Наконец вAppкомпонент добавленreact-appмаршрут:
const App = () => {
return (
<BrowserRouter>
<div>
<header className={styles.header}>
<Link to="/">基座 Home</Link>
<Link to="/about">基座 About</Link>
<Link to="/react-app">React 子应用</Link>
</header>
<Routes>
<Route path="/" element={<Home/>}/>
<Route path="/about" element={<About/>}/>
<Route path='/react-app' element={<ReactMicroApp/>}/>
</Routes>
</div>
</BrowserRouter>
);
}
Теперь у нас есть идеально подключенное приложение React:
Весь процесс доступа очень прост, а инвазивные операции резюмируются следующим образом:
- основное приложение
microApp.start()- Добавьте компоненты контейнера для микроприложений
- Добавьте маршрут, чтобы указать на этот компонент контейнера
- Микро приложение
- Изменить общедоступный путь
- Добавить междоменный доступ
- автоматическая маршрутизация
basename
Контрастный цянькунь
После завершения Hello World давайте сравнимqiankunстартер.
основное приложение
| micro-app | qiankun |
|---|---|
| указать элемент контейнера | Добавить элемент пользовательской метки |
registerMicroApps |
общий коммутатор маршрутизации |
start() |
microApp.start() |
Микроприложения:
| micro-app | qiankun |
|---|---|
| изменить общий путь | изменить общий путь |
| Указывает базовое имя маршрута | Указывает базовое имя маршрута |
| - | жизненный цикл экспорта |
| Настроить междоменный доступ | Настроить междоменный доступ |
| - | Настроить вывод Webpack |
должен сказать,micro-appОн действительно более удобен для новичков, более лаконичен и понятен в использовании.
Доступ к микроприложениям Vue
С учетом вышеизложенного быстрее получить доступ к микроприложениям Vue.
Микро приложение
использовать напрямуюvue-cliСоздайте проект Vue, здесь я выбираю Vue3.
Первый шаг — добавитьpublic-path.js:
// public-path.js
if (window.__MICRO_APP_ENVIRONMENT__) {
// eslint-disable-next-line
__webpack_public_path__ = window.__MICRO_APP_PUBLIC_PATH__
}
И вВход main.jsПредставлять:
// main.js
import './public-path'
import {createApp} from 'vue'
...
Второй шаг — изменить Vue Routerbasename:
// main.js
const router = createRouter({
history: createWebHistory(window.__MICRO_APP_BASE_ROUTE__ || process.env.BASE_URL),
routes: [
{ path: '/', component: Home },
{ path: '/about', component: About }
],
})
const app = createApp(App).use(router)
app.mount('#app')
// 监听卸载操作
window.addEventListener('unmount', function () {
app.unmount()
})
Третий шаг — изменить междоменный доступ Webpack DevServer:
// vue.config.js
module.exports = {
devServer: {
headers: {
'Access-Control-Allow-Origin': '*',
}
}
}
основное приложение
Добавить кVue3MicroAppконтейнер:
const Vue3MicroApp = () => {
return (
<div>
<h1>vue3-app</h1>
<button onClick={sendVue3AppData}>基座 => vue3-app</button>
<p>子应用消息 {microAppState ? microAppState.msg : '无'}</p>
<micro-app
name='vue3-app'
url='http://localhost:3002/'
baseroute='/vue3-app'
>
</micro-app>
</div>
)
}
Затем добавьте маршрут:
const App = () => {
return (
<BrowserRouter>
<div>
<header className={styles.header}>
<Link to="/">基座 Home</Link>
<Link to="/about">基座 About</Link>
<Link to="/react-app">React 子应用</Link>
<Link to="/vue3-app">Vue3 子应用</Link>
</header>
<Routes>
<Route path="/" element={<Home/>}/>
<Route path="/about" element={<About/>}/>
<Route path='/react-app' element={<ReactMicroApp/>}/>
<Route path='/vue3-app' element={<Vue3MicroApp/>}/>
</Routes>
</div>
</BrowserRouter>
);
}
Вскоре (Ma Baoguo.jpg) будет подключено новое микроприложение:
передача данных
Передача данных такжеmicro-appИзюминкой использования уровня, чемqiankunEventBus проще в использовании, чеммало по малу. Ах да, именно так, потому что способ его использования все еще относительно хаки.
Отец
Добавьте компонент-контейнер в док-приложениеmicroApp.setDataДостаточно:
// ReactMicroApp
const ReactMicroApp = () => {
const [microAppState, setMicroAppState] = useState(microApp.getData('react-app'));
// 发送数据给 react-app
const sendReactAppData = () => {
microApp.setData('react-app', {
name: `react-app 随机数: ${Math.random()}`
})
}
return (
<div>
<h1>react-app</h1>
<button onClick={sendReactAppData}>基座 => react-app</button>
<p>子应用消息 {microAppState ? microAppState.msg : '无'}</p>
<micro-app
name='react-app'
url='http://localhost:3001/'
baseroute='/react-app'
>
</micro-app>
</div>
)
}
должен быть в курсеsetDataЗначение должно быть объектом!
Когда микроприложение получает данные, оно также получает их через мониторинг событий:
// react-app App.js
function App() {
const [mainAppData, setMainAppData] = useState( window.microApp.getData());
// 监听基座数据
useEffect(() => {
if (window.microApp) {
const dataListener = (data) => {
console.log('主应用传的数据', data);
setMainAppData(data);
}
window.microApp.addDataListener(dataListener)
return () => {
window.microApp.clearDataListener()
}
}
})
return (
<div>
<p>主应用的数据:{mainAppData ? mainAppData.name : '无'}</p>
<BrowserRouter basename={window.__MICRO_APP_BASE_ROUTE__ || '/'}>
<div>
<header className={styles.header}>
<Link to="/">react-app Home</Link>
<Link to="/about">react-app About</Link>
</header>
<Routes>
<Route path="/" element={<Home/>}/>
<Route path="/about" element={<About/>}/>
</Routes>
</div>
</BrowserRouter>
</div>
);
}
сын к отцу
При этом данные, отправляемые микроприложением, также являются строкойwindow.microApp.dispatchВсе в порядке, и входные параметры тоже должны быть объектами:
// react-app App.js
function App() {
const [mainAppData, setMainAppData] = useState( window.microApp.getData());
useEffect(() => {
if (window.microApp) {
const dataListener = (data) => {
console.log('主应用传的数据', data);
setMainAppData(data);
}
window.microApp.addDataListener(dataListener)
return () => {
window.microApp.clearDataListener()
}
}
})
// 发送数据给基座
const sendToMain = () => {
window.microApp.dispatch({msg: `我是 react-app 随机数 ${Math.random()}`})
}
return (
<div>
<p>主应用的数据:{mainAppData ? mainAppData.name : '无'}</p>
<button onClick={sendToMain}>给基座应用发送</button>
<BrowserRouter basename={window.__MICRO_APP_BASE_ROUTE__ || '/'}>
<div>
<header className={styles.header}>
<Link to="/">react-app Home</Link>
<Link to="/about">react-app About</Link>
</header>
<Routes>
<Route path="/" element={<Home/>}/>
<Route path="/about" element={<About/>}/>
</Routes>
</div>
</BrowserRouter>
</div>
);
}
Монитор пьедестала немного хакерский:
// ReactMicroApp.js
import microApp from '@micro-zoe/micro-app'
import {useState} from "react";
/** @jsxRuntime classic */
/** @jsx jsxCustomEvent */
import jsxCustomEvent from '@micro-zoe/micro-app/polyfill/jsx-custom-event'
const ReactMicroApp = () => {
const [microAppState, setMicroAppState] = useState(microApp.getData('react-app'));
const sendReactAppData = () => {
microApp.setData('react-app', {
name: `react-app 随机数: ${Math.random()}`
})
}
const onDataChange = (e) => {
console.log('react-app onDataChange', e);
console.log('react-app 数据', e.detail.data);
setMicroAppState(e.detail.data);
}
return (
<div>
<h1>react-app</h1>
<button onClick={sendReactAppData}>基座 => react-app</button>
<p>子应用消息 {microAppState ? microAppState.msg : '无'}</p>
<micro-app
name='react-app'
url='http://localhost:3001/'
baseroute='/react-app'
onDataChange={onDataChange}
>
</micro-app>
</div>
)
}
Хотя не используетсяjsxCustomEvent, но его тоже надо импортировать, а комментарии удалять нельзя!
Затем мы можем увидеть эффект передачи данных:
Расширенные возможности
все вышеперечисленноеmicro-appПриступая к работе с некоторыми основными операциями, он также предоставляет некоторые дополнительные функции.
KeeyAlive
Поддерживать состояние микроприложенияKeep-Alive:
<micro-app name='xx' url='xx' keep-alive></micro-app>
Жизненный цикл
/** @jsxRuntime classic */
/** @jsx jsxCustomEvent */
import jsxCustomEvent from '@micro-zoe/micro-app/polyfill/jsx-custom-event'
const App = () => {
return (
<micro-app
name='xx'
url='xx'
onCreated={() => console.log('micro-app元素被创建')}
onBeforemount={() => console.log('即将被渲染,只在初始化时执行一次')}
onMounted={() => console.log('已经渲染完成,只在初始化时执行一次')}
onAfterhidden={() => console.log('已卸载')}
onBeforeshow={() => console.log('即将重新渲染,初始化时不执行')}
onAftershow={() => console.log('已经重新渲染,初始化时不执行')}
onError={() => console.log('渲染出错')}
/>
)
}
Переход между приложениями
- window.history
- Управление прыжком через передачу данных
- Передать метод экземпляра маршрута
изолировать
использование JSProxyПоведение глобальной операции пользователя перехватывается, предотвращаяwindowдоступ и модификация, чтобы избежать загрязнения глобальной переменной.
На стороне CSS существует два вида изоляции:
- Добавить префикс селектора CSS по умолчанию
- ShadowDOM
Аспекты изоляции элементов,micro-appСимуляция достигает чего-то вродеShadowDomфункция, элемент не исчезает<micro-app>Границы элементов, подприложения могут только добавлять, удалять, изменять и проверять свои собственные элементы.
Статическая обработка ресурсов
использоватьglobalAssetsПоделиться ресурсом:
// index.js
import microApp from '@micro-zoe/micro-app'
microApp.start({
globalAssets: {
js: ['js地址1', 'js地址2', ...], // js地址
css: ['css地址1', 'css地址2', ...], // css地址
}
})
или использоватьglobalАтрибуты:
<link rel="stylesheet" href="xx.css" global>
<script src="xx.js" global></script>
и фильтрация ресурсов:
<link rel="stylesheet" href="xx.css" exclude>
<script src="xx.js" exclude></script>
<style exclude></style>
Рендеринг в режиме микро-фронтенда
- режим по умолчанию: выполнять JS последовательно каждый раз, что является идемпотентным
- умд режим: Выполняет все JS только при первом рендеринге, что может повысить производительность для проектов, требующих частого переключения микроприложений.
Система плагинов
Основная функция системы плагинов - модифицировать js.Каждый файл js будет проходить через систему плагинов, и мы можем перехватывать и обрабатывать эти js.Обычно используется для исправления ошибок в js или внедрения каких-то глобальных переменных в подприложения.
Эта подключаемая система может в основном обрабатывать JS на среднем уровне, чтобы избежать некоторых ошибок JS, которые невозможно обработать из-за фиксированных шаблонов. В общем, эта система еще новорожденная и ее нужно строить вместе с другими разработчиками.
Суммировать
В основном,micro-appЭто фреймворк микроинтерфейса nova, запущенный JD.
Конечно, поскольку этот проект также был запущен 21 июля, текущая версия (28 января 2022 г.)0.8.4,еще нет1.0, поэтому, если вы хотите использовать его в производственной среде, рекомендуется соблюдать осторожность.
qiankunХотя он более навязчив, он имеет 3 года сценариев использования микроинтерфейса и накопления опыта, что делает его более стабильным в решении проблем.