一、微前端解決什麼問題
為了解決龐大的一整塊前端帶來的變更與擴充方面的限制,出現了微前端
二、什麼是微前端
微前端:即,一種由獨立傳遞的多個前端應用組成整體的架構風格。具體的,将前端應用分解成一些更小、更簡單的能夠獨立開發、測試、部署的小塊,而在使用者看來仍然是内聚的單個産品
三、微前端的特點
-
技術棧無關
主架構不限制接入應用的技術棧,微應用具備完全自主權
-
獨立開發、獨立部署
微應用倉庫獨立,前後端可獨立開發,部署完成後主架構自動完成同步更新
-
增量更新
在面對各種複雜場景時,我們通常很難對一個已經存在的系統做全量的技術棧更新或重構,而微前端是一種非常好的實施漸進式重構的手段和政策
-
獨立運作時
每個微應用之間狀态隔離,運作時狀态不共享
四、qiankun
qiankun 是一個基于 single-spa 的微前端實作庫,旨在幫助大家能更簡單、無痛的建構一個生産可用微前端架構系統
- qiankun核心設計理念
簡單
由于主應用微應用都能做到技術棧無關,qiankun 對于使用者而言隻是一個類似 jQuery 的庫,你需要調用幾個 qiankun 的 API 即可完成應用的微前端改造。同時由于 qiankun 的 HTML entry 及沙箱的設計,使得微應用的接入像使用 iframe 一樣簡單。
解耦/技術棧無關
微前端的核心目标是将巨石應用拆解成若幹可以自治的松耦合微應用,而 qiankun 的諸多設計均是秉持這一原則,如 HTML entry、沙箱、應用間通信等。這樣才能確定微應用真正具備 獨立開發、獨立運作 的能力。
- 為什麼不是iframe
為什麼不用 iframe,這幾乎是所有微前端方案第一個會被 challenge 的問題。但是大部分微前端方案又不約而同放棄了 iframe 方案,自然是有原因的,并不是為了 “炫技” 或者刻意追求 “特立獨行”。
如果不考慮體驗問題,iframe 幾乎是最完美的微前端解決方案了。
iframe 最大的特性就是提供了浏覽器原生的硬隔離方案,不論是樣式隔離、js 隔離這類問題統統都能被完美解決。但他的最大問題也在于他的隔離性無法被突破,導緻應用間上下文無法被共享,随之帶來的開發體驗、産品體驗的問題。
- url 不同步。浏覽器重新整理 iframe url 狀态丢失、後退前進按鈕無法使用。
- UI 不同步,DOM 結構不共享。想象一下螢幕右下角 1/4 的 iframe 裡來一個帶遮罩層的彈框,同時我們要求這個彈框要浏覽器居中顯示,還要浏覽器 resize 時自動居中…
- 全局上下文完全隔離,記憶體變量不共享。iframe 内外系統的通信、資料同步等需求,主應用的 cookie 要透傳到根域名都不同的子應用中實作免登效果。
- 慢。每次子應用進入都是一次浏覽器上下文重建、資源重新加載的過程。
3.使用
主應用
- 安裝qiankun
yarn add qiankun # 或者 npm install qiankun -S
- 在主應用中注冊微應用
import { registerMicroApps, start } from 'qiankun'; registerMicroApps([ { name: 'react app', // app name registered entry: '//localhost:7100', container: '#yourContainer', activeRule: '/yourActiveRule', }, { name: 'vue app', entry: { scripts: ['//localhost:7100/main.js'] }, container: '#yourContainer2', activeRule: '/yourActiveRule2', }, ]); start();
當微應用資訊注冊完之後,一旦浏覽器的 url 發生變化,便會自動觸發 qiankun 的比對邏輯,所有 activeRule
規則比對上的微應用就會被插入到指定的 container 中,同時依次調用微應用暴露出的生命周期鈎子。
import { loadMicroApp } from 'qiankun'; loadMicroApp({ name: 'app', entry: '//localhost:7100', container: '#yourContainer', });
微應用
微應用不需要額外安裝任何其他依賴即可接入 qiankun 主應用。
-
導出相應的生命周期鈎子
微應用需要在自己的入口 js (通常就是你配置的 webpack 的 entry js) 導出 bootstrap、mount、unmount 三個生命周期鈎子,以供主應用在适當的時機調用。
/** * bootstrap 隻會在微應用初始化的時候調用一次,下次微應用重新進入時會直接調用 mount 鈎子,不會再重複觸發 bootstrap。 * 通常我們可以在這裡做一些全局變量的初始化,比如不會在 unmount 階段被銷毀的應用級别的緩存等。 */ export async function bootstrap() { console.log('react app bootstraped'); } /** * 應用每次進入都會調用 mount 方法,通常我們在這裡觸發應用的渲染方法 */ export async function mount(props) { ReactDOM.render(<App />, props.container ? props.container.querySelector('#root') : document.getElementById('root')); } /** * 應用每次 切出/解除安裝 會調用的方法,通常在這裡我們會解除安裝微應用的應用執行個體 */ export async function unmount(props) { ReactDOM.unmountComponentAtNode( props.container ? props.container.querySelector('#root') : document.getElementById('root'), ); } /** * 可選生命周期鈎子,僅使用 loadMicroApp 方式加載微應用時生效 */ export async function update(props) { console.log('update props', props); }```
-
配置微應用到的打包工具
除了代碼中暴露出相應的生命周期鈎子之外,為了讓主應用能正确識别微應用暴露出來的一些資訊,微應用的打包工具需要增加如下配置:
webpack:
const packageName = require('./package.json').name; module.exports = { output: { library: `${packageName}-[name]`, libraryTarget: 'umd', jsonpFunction: `webpackJsonp_${packageName}`, }, };```