【D1N910】2020年qiankun根據(jù)官方文檔的使用&&學(xué)習(xí)記錄-指南篇
正常操作,正常分析,大家好,我是D1N910。
以下內(nèi)容主要學(xué)習(xí)自 qiankun v2.0.25?bf6f0df 和對(duì)應(yīng)的文檔https://qiankun.umijs.org/zh/guide

* 因?yàn)橐韵碌膬?nèi)容是純手打,所以可能會(huì)有錯(cuò)別字,如果不是純手打的內(nèi)容會(huì)直接用截圖。

微前端有很多方案,選擇 `qiankun` 的原因是因?yàn)榘⒗飯F(tuán)隊(duì)出的內(nèi)容。從技術(shù)上是比較信任的(大哥大姐過年好,抱大腿來了)。
說下我個(gè)人的考慮。
做微前端無非就是因?yàn)楫?dāng)網(wǎng)站越做越大,頁面上有各種各樣的 `服務(wù)`。
以下的會(huì)產(chǎn)生的困擾不分先后。
項(xiàng)目工程會(huì)很大;
構(gòu)件速度會(huì)很慢;
不同核心業(yè)務(wù)功能放在一起;
不同業(yè)務(wù)團(tuán)隊(duì)會(huì)在一個(gè)大工程里進(jìn)行開發(fā)工作。
傳統(tǒng)用的比較多的方案其實(shí)就是——原生的iframe。
為什么不用 `iframe` 呢?
這里手打 `qiankun` 團(tuán)隊(duì) `kuitos` 的 《Why Not Iframe》來作為解釋。
https://www.yuque.com/kuitos/gky7yw/gesexv
Why Not Iframe
為什么不用 iframe,這幾乎是所有微前端第一個(gè)被 challenge 的問題。但是大部分微前端方案又不約而同放棄了 iframe 方案 ,自然是有原因的,斌不是為了“炫技”或者刻意追求“特例獨(dú)行”。
如果不考慮體驗(yàn)問題,iframe 幾乎是最完美的微前端解決方案了。
iframe 最大的特性就是提供了瀏覽器原生的硬隔離方案,不論是樣式隔離、js隔離這類問題統(tǒng)統(tǒng)都能被完美解決。但他的最大問題也在于他的隔離性無法被突破,導(dǎo)致應(yīng)用間上下文無法被共享,隨之帶來的開發(fā)體驗(yàn)、產(chǎn)品體驗(yàn)的問題。
1、url 不同步。瀏覽器刷新 iframe url 狀態(tài)丟失、后退前進(jìn)按鈕誤無法使用。
2、UI 不同步,DOM 結(jié)構(gòu)不同享。想象一下屏幕右下角 1/4 的 iframe 里來一個(gè)帶遮罩層的彈框,同時(shí)我們要求這個(gè)彈框要瀏覽器居中顯示,還要瀏覽器 resize 時(shí)自動(dòng)居中。
3、全局上下完全隔離,內(nèi)存變量不同享。iframe 內(nèi)外系統(tǒng)的通信、數(shù)據(jù)同步等需求,主應(yīng)用的 cookie 要透傳到根域名都不同的子應(yīng)用中實(shí)現(xiàn)免登效果。
4、慢。每次子應(yīng)用進(jìn)入都是一次瀏覽器上下文重建、資源重新加載的過程。
其中有的問題比較好解決(問題1),有的問題我們可以睜一只眼閉一只眼(問題4),但有的問題我們則很難解決(問題3)甚至無法解決(問題2),而這些無法解決的問題恰恰又會(huì)給產(chǎn)品帶來非常嚴(yán)重的體驗(yàn)問題,最終導(dǎo)致我們舍棄了 iframe 方案。
提出了對(duì)于 iframe 難以解決的問題以后,實(shí)際上也就是說出了 qiankun 能夠?qū)崿F(xiàn)的事情。
那么繼續(xù)往下看。
介紹
點(diǎn)擊 qiankun 網(wǎng)站右上角的 `指南`,繼續(xù)看介紹。
qiankun 是一個(gè)基于?single-spa?的微前端實(shí)現(xiàn)庫,旨在幫助大家能更簡單、無痛的構(gòu)建一個(gè)生產(chǎn)可用微前端架構(gòu)系統(tǒng)。- qiankun 介紹
`single-spa` 超鏈接?https://github.com/CanopyTax/single-spa,這是一個(gè)前端微服務(wù)的javascript框架,qiankun基于此。
`微前端` 有一個(gè)超鏈接指向了?https://micro-frontends.org/?,這里系統(tǒng)闡述了將微服務(wù)理念拓展到前端開發(fā)而形成的微前端的概念。
【flag】要對(duì) Micro Frontends 進(jìn)行翻譯
qiankun 孵化自螞蟻金融科技基于微前端架構(gòu)的云產(chǎn)品統(tǒng)一接入平臺(tái),在經(jīng)過一批線上應(yīng)用的充分檢驗(yàn)及打磨后,我們將其微前端內(nèi)核抽取出來并開源,希望能同時(shí)幫助社區(qū)有類似需求的系統(tǒng)更方便的構(gòu)建自己的微前端系統(tǒng),同時(shí)也希望通過社區(qū)的幫助將 qiankun 打磨的更加成熟完善。- qiankun 介紹
`微前端架構(gòu)的云產(chǎn)品統(tǒng)一接入平臺(tái)`,其實(shí)類似這樣的微前端產(chǎn)品,我也有看過飛冰,也是阿里的(??ω??)
目前 qiankun 已在螞蟻內(nèi)部服務(wù)了超過 200+ 線上應(yīng)用,在易用性及完備性上,絕對(duì)是指的信賴的。
意思是 `qiankun` 已經(jīng)是螞蟻內(nèi)部落地使用很多的產(chǎn)品了,上過生產(chǎn)線。
什么是微前端
Techniques,strategies and recipes for building a modern web app with multiple teams that can ship features independently -- Mico Frontends?https://micro-frontends.org/
微前端是一種多個(gè)團(tuán)隊(duì)通過獨(dú)立發(fā)布功能的方式來共同構(gòu)建現(xiàn)代化 web 應(yīng)用的技術(shù)手段及方法策略。- qiankun 介紹 - 什么是微前端
這個(gè)也是我想的做微前端的目的,比如在一個(gè)移動(dòng)app上的首頁,不同模塊劃分出來屬于不同的業(yè)務(wù)團(tuán)隊(duì)去維護(hù),而這些業(yè)務(wù)可以放在同一個(gè)容器里,同一個(gè)域名下,不同通過域名切換就可以用到不同的前端服務(wù)。
微前端架構(gòu)具備以下幾個(gè)核心價(jià)值:
技術(shù)棧無關(guān)
主框架不限制接入應(yīng)用的技術(shù)棧,微應(yīng)用具備完全自主權(quán)
獨(dú)立開發(fā)、獨(dú)立部署
微應(yīng)用倉庫獨(dú)立,前后端可獨(dú)立開發(fā),部署完成后主框架自動(dòng)完成同步更新
增量升級(jí)
在面對(duì)各種復(fù)雜場景時(shí),我們通常很難對(duì)一個(gè)已經(jīng)存在的系統(tǒng)做全量的技術(shù)棧升級(jí)或重構(gòu),而微前端是一種非常好的實(shí)施漸進(jìn)式重構(gòu)的手段和策略
獨(dú)立運(yùn)行時(shí)
每個(gè)微應(yīng)用之間狀態(tài)隔離,運(yùn)行時(shí)狀態(tài)不共享
微前端架構(gòu)旨在解決單體應(yīng)用子啊相對(duì)長的時(shí)間跨度下,由于參與的人員、團(tuán)隊(duì)的增多、變遷,從一個(gè)普通應(yīng)用變成一個(gè)巨石應(yīng)用(Frontend Monolith https://www.youtube.com/watch?v=pU1gXA0rfwc)后,隨之而來的應(yīng)用不可維護(hù)的問題。這類問題在企業(yè)級(jí) Web 應(yīng)用中尤其常見。
更多關(guān)于微前端的相關(guān)介紹,推薦大家可以去看這這幾篇文章:
Micro Frontends https://micro-frontends.org/
Micro Frontends from martinfowler.com?https://martinfowler.com/articles/micro-frontends.html
可能是你見過最完善的微前端解決方案?https://zhuanlan.zhihu.com/p/78362028
微前端的核心價(jià)值?https://zhuanlan.zhihu.com/p/95085796
- qiankun 介紹 - 什么是微前端
上面的微前端的核心價(jià)值,其實(shí)也就是咱們之前說的,仔細(xì)一看,原生的? `iframe`?就非常好實(shí)現(xiàn)。
qiankun 的核心設(shè)計(jì)理念
簡單
由于主應(yīng)用微應(yīng)用都能做到技術(shù)棧無關(guān),qiankun 對(duì)于用戶而言只是一個(gè)類似 jQuery 的庫,你需要調(diào)用幾個(gè) qiankun 的 API 即可完成應(yīng)用的微前端改造。同時(shí)由于 qiankun 的 HTML entry 及 沙箱的設(shè)計(jì),使得微應(yīng)用的接入像使用 iframe 一樣簡單。
解耦/技術(shù)棧無關(guān)
微前端的核心目標(biāo)是將巨石應(yīng)用拆解成若干可以自治的松耦合微應(yīng)用,而 qiankun 的諸多設(shè)計(jì)均是秉持這一原則,如 HTML entry、沙箱、應(yīng)用間通信等。這樣才能確保微應(yīng)用真正具備 獨(dú)立開發(fā)、獨(dú)立運(yùn)行 的能力。
- qiankun 介紹 - qiankun 的核心設(shè)計(jì)理念
看完以后連連點(diǎn)頭,有一種 `俺也一樣` 的感覺。
它是如何工作的
TODO?- qiankun 介紹 - 它是如何工作的
回頭我看源代碼解析一下吧,其實(shí)應(yīng)該是對(duì) `iframe` 這個(gè)原生標(biāo)簽做了一層非常豐富的封裝。
打臉:學(xué)了一段時(shí)間,發(fā)現(xiàn)其實(shí)是用? fetch 下載微服務(wù)的應(yīng)用,然后插入到html元素中!
【flag】要看 qiankun 源代碼
特性
???基于 single-spa 封裝,提供了更加開箱即用的 API。
???技術(shù)棧無關(guān),任意技術(shù)棧的應(yīng)用均可 使用/接入,不論是 React/Vue/Angular/JQuery 還是其他等框架。
???HTML Entry 接入方式,讓你接入微應(yīng)用像使用 iframe 一樣簡單。
?? 樣式隔離,確保微應(yīng)用之間樣式互相不干擾。
?? JS沙箱,確保微應(yīng)用之間 全局變量/事件 不沖突。
?? 資源預(yù)加載,在瀏覽器空閑時(shí)間預(yù)加載為打開的微應(yīng)用資源,加速微應(yīng)用打開速度。
?? umi插件,提供 @umijs/plugin-qiankun 供 umi 應(yīng)用一鍵切換成微前端架構(gòu)系統(tǒng)。
- qiankun 介紹?- 特性
最后一個(gè) `umi` 感覺比較好奧,挺想搞 umi 的了。
Last Update:2020/9/21 下午6:13:24

看完以上偏理論的內(nèi)容以后,我對(duì)微前端以及qiankun概念已經(jīng)明白了。自己總結(jié)的話,從遞進(jìn)式理解就是:
1、微前端就是把不同網(wǎng)站合在一起用,這些網(wǎng)站本身就是互不干擾的,用原生的iframe就很好實(shí)現(xiàn);
2、其中single-spa對(duì) iframe 做了一層封裝,使得能夠更好地實(shí)現(xiàn)一些通用的功能;
打臉:學(xué)了一段時(shí)間,發(fā)現(xiàn)是通過fetch來下載微應(yīng)用的內(nèi)容,然后實(shí)現(xiàn)了ifram擁有的內(nèi)容!
3、qiankun是對(duì)single-spa做了又一層封裝,提供了能多企業(yè)級(jí)(即生產(chǎn)常用的)開箱即用的API。
快速上手
主應(yīng)用
1、安裝 qiankun
$ yarn add qiankun # 或者 npm i qiankun -S
2、在主應(yīng)用中注冊(cè)微應(yīng)用
import { registerMicroApps, start?} from 'qiankun'
registerMicroApps([
????{
????????name: 'my-first-micro-app', // 自定義的name名
????????entry: '//loaclhost:7100', // 啟動(dòng)的服務(wù)的地址
????????container: '#yourContainer', //?
????????activeRule: '/yourActiveRule' //?
????}
])
start() // 啟動(dòng)微應(yīng)用
當(dāng)微應(yīng)用信息注冊(cè)完之后,一旦瀏覽器的url發(fā)生變化,便會(huì)觸發(fā) qiankun 的匹配邏輯,所有 activeRule 規(guī)則匹配上的微應(yīng)用就會(huì)被插入到指定的 container 中,同時(shí)依次調(diào)用微應(yīng)用暴露出的生命周期鉤子。
如果微應(yīng)用不是跟路由關(guān) 聯(lián)的時(shí)候,比如就是想直接渲染展示的一些UI模塊,可以使用手動(dòng)加載微應(yīng)用的方式。
// 官方示例
import { loadMicroApp } from 'qiankun';
loadMicroApp(
? {?
? ? name: 'app',?
? ? entry: '//localhost:7100',
? ? container: '#yourContainer',?
? }
);
微應(yīng)用
微應(yīng)用安裝的時(shí)候不需要任何依賴
1、導(dǎo)出相應(yīng)的生命周期鉤子
微應(yīng)用通常要在自己的入口js導(dǎo)出 bootstrap、mount、unmount 三個(gè)生命周期鉤子,以供主應(yīng)用在適當(dāng)?shù)臅r(shí)機(jī)調(diào)用。
這個(gè)入口通常就是你配置的webpack的entry.js,比如在 vue 里的是 main.js,官方的實(shí)例是 React 應(yīng)用。
這三個(gè)生命周期鉤子都是必須要導(dǎo)出的!
Bootstrap?鉤子
bootstrap 只會(huì)在微應(yīng)用初始化的時(shí)候調(diào)用一次,下次微應(yīng)用重新進(jìn)入會(huì)直接調(diào)用 mount 鉤子,不會(huì)再重復(fù)觸發(fā) bootstrap。
通常我們可以在這里做一些全局變量的初始化,比如不會(huì)在 unmount 階段被銷毀的應(yīng)用級(jí)別的緩存等
export async function bootstrap() {
????console.log('bootstrap run')
}
Mount?鉤子
應(yīng)用每次進(jìn)入都會(huì)調(diào)用 mount 方法,通常我們?cè)谶@里觸發(fā)應(yīng)用的渲染方法
export async function mount(props) {
????console.log(props);
????ReactDOM.render(<APP />, document.getElementById('react15Root'));
}
* 這里的渲染方法是對(duì)應(yīng) React 的render方法,在 Vue 里一般會(huì)自定義一個(gè) render 方法來渲染。
下面是參考自?https://github.com/gongshun/qiankun-vue-demo 的寫法
/**
* 渲染函數(shù)
* 兩種情況:主應(yīng)用生命周期鉤子中運(yùn)行 / 微應(yīng)用單獨(dú)啟動(dòng)時(shí)運(yùn)行
*/
function render ({ container } = {}) {
?// 在 render 中創(chuàng)建 VueRouter,可以保證在卸載微應(yīng)用時(shí),移除 location 事件監(jiān)聽,防止事件污染
?router = new Router({
? ?...routes,
? ?// 運(yùn)行在主應(yīng)用中時(shí),添加路由命名空間 /chaiQiankun1/ffff,這和主應(yīng)用中注冊(cè)微應(yīng)用時(shí)的activeRule相互對(duì)應(yīng)
? ?base: window.__POWERED_BY_QIANKUN__ ? '/app-vue-history' : '/',
? ?mode: 'history'
?})
?global.router = router
?// 掛載應(yīng)用
?instance = new Vue({
? ?router,
? ?render: h => { return h(App) }
?}).$mount(container ? container.querySelector('#appVueHistory') : '#appVueHistory')
}
// 獨(dú)立運(yùn)行時(shí),直接掛載應(yīng)用
if (!window.__POWERED_BY_QIANKUN__) {
?render()
}
/**
* 應(yīng)用每次進(jìn)入都會(huì)調(diào)用 mount 方法,通常在這里我們會(huì)卸載微應(yīng)用的應(yīng)用實(shí)例
*/
export async function mount(props) {
?console.log('mscrtApp mount', props)
?render(props)
}
Unmount?鉤子
/**
* 應(yīng)用每次 切出/卸載 會(huì)調(diào)用的方法,通常在這里我們會(huì)卸載微應(yīng)用的應(yīng)用實(shí)例
*/
export async function unmount() {
?ReactDOM.unmountComponentAtNode(document.getElementById('react15Root'));
}
在 vue 里,之前存儲(chǔ)元素的變量賦值為 null 即可。
export async function unmount() {
???? ?console.log('mscrtApp unmount')
???? ?instance.$destroy()
???? ?instance.$el.innerHTML = ''
???? ?instance = null
???? ?router = null
}
Update 鉤子 * 可選
這是可選的生命周期鉤子,僅使用 loadMicroApp 方式加載微應(yīng)用時(shí)生效
export async function update(props) {
????console.log('update props', props);
}
*qiankun 基于 single-spa,想要看更多關(guān)于微應(yīng)用生命周期相關(guān)的文檔說明看這里
??
https://single-spa.js.org/docs/building-applications.html#registered-application-lifecycle
沒有webpack 等構(gòu)建工具的應(yīng)用接入方式 ??
https://qiankun.umijs.org/zh/faq#%E9%9D%9E-webpack-%E6%9E%84%E5%BB%BA%E7%9A%84%E5%BE%AE%E5%BA%94%E7%94%A8%E6%94%AF%E6%8C%81%E6%8E%A5%E5%85%A5-qiankun-%E4%B9%88%EF%BC%9F
2. 配置微應(yīng)用的打包工具
除了代碼中暴露出相應(yīng)的生命周期鉤子之外,為了讓主應(yīng)用能正確識(shí)別微應(yīng)用暴露出來的一些信息,微應(yīng)用的打包工具需要增加如下配置:
webpack:
const packageName = require('./package.json').name;
// 這里是為了拿應(yīng)用的名稱,微應(yīng)用和主應(yīng)用里引用的name名稱要對(duì)應(yīng)上,這里也不一定要package.json,可以是任意的js文件,也可以是直接寫的name~
module.exports = {
????output: {
????????library: `${packageName}-[name]`,
????????libraryTarge: 'umd',
????????jsonpFunction: `wbepackJsonp_${packageName}`,
????}
}
在 vue.config.js 中放在 `configureWebpack` 中。
相關(guān)配置介紹可以查看 webpack 相關(guān)文檔 ???https://webpack.js.org/configuration/output/#outputlibrary

本期 End
以上內(nèi)容大部分來自?https://qiankun.umijs.org/zh
真的非常簡單易用,很快就能夠跑起來了,簡歷上可以打上微應(yīng)用三個(gè)字了。
我已經(jīng)把`尊重`達(dá)到屏幕上了。
——就是各種遇到的?"BUG" 太多了。
這里再感謝一下龔順同學(xué),真的,太帥了, 真漂亮!在qiankun群里回答了N個(gè)人的問題,而且他的項(xiàng)目也幫了我很大的忙,我愛他。