Предварительное знакомство с MicroApp, чрезвычайно лаконичной микроинтерфейсной структурой.

внешний интерфейс JavaScript
Предварительное знакомство с MicroApp, чрезвычайно лаконичной микроинтерфейсной структурой.

предисловие

Всем привет, я морское чудовище.

В области микроинтерфейса, я думаю, все слышали об Али.qiankun. Я использовал его сам в течение последних нескольких месяцев для некоторой практики:

За время использования я обнаружил, что 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 года сценариев использования микроинтерфейса и накопления опыта, что делает его более стабильным в решении проблем.