【微前端】微前端最終章-qiankun指南以及微前端整體探索

  • 2021 年 2 月 22 日
  • 筆記

 這才2月中旬,廣州就已經漸漸地進入了夏季,——夏天總是讓人焦慮的。過年閑暇時間寫下了微前端這系列的終章,歡迎拍磚。如果你習慣直接上手代碼,不妨跳到實踐一節,直接上代碼教程玩一玩。

如果你還沒有看過前面幾章 這裡是鏈接:

微前端大賞

微前端大賞二-singlespa實踐

qiankun原理和API介紹

qiankun是基於singlespa框架的一個上層應用,它提供了完整的生命周期,和一些鉤子函數,通過路由匹配來動態加載註冊微應用,同時提供了一系列api對微應用做管理和預加載等,它相對singlespa來說進步是比較大的。

所以—qiankun實質上是singlespa的一個封裝,基於我們在上一節看到的,singlespa是通過輸出一個manifest.json 通過標識入口信息動態構造script渲染實現的微前端應用,類似下面的圖:
avatar

回顧一下singlespa在渲染過程中的核心邏輯
1、 首先我們有 main(主app) child(子app),主app只有一個,子app可以有多個
2、 其次,主app上一般我們可以在index.html裏面,寫多幾個空間,也就是多幾個div
例如:

 

<div id=」react-app」></div>
<div id=」vue-app」></div>

3、然後,在我們的child上,我們要用webpack插件,生成一個帶有所有需要加載的依賴文件的manifest.json

4、主應用去加載這個manifest.json,獲取到具體的js,使用script標籤把它放到主應用上,進行渲染

在qiankun中對這套邏輯做了基本的封裝, 讓我們只需要經過簡單的幾個api就可以控制singlespa中比較複雜的配置和概念。

 

註冊

import { registerMicroApps, start } from 'qiankun';
registerMicroApps([
  {
    name: 'react app', // 應用名稱
    entry: '//localhost:7100', // 應用入口,應用需要增加cors選項
    container: '#yourContainer', // 應用單獨的appid的div
    activeRule: '/yourActiveRule', // 匹配路由
  },
  {
    name: 'vue app',
    entry: { scripts: ['//localhost:7100/main.js'] },
    container: '#yourContainer2',
    activeRule: '/yourActiveRule2',
  },
]);
start();

 

main

main是一個qiankun的主體部分,它也是不限制框架種類的,可以用react也可以用vue和angular,只需要在entry.js裏面註冊它就可以了。

一般情況下main的作用是存放公共代碼,例如:
1、消息觸發器
2、公共路由
3、權限觸發器
4、存放例如全局管理、皮膚、用戶管理等公共頁面

你也可以把站點的首頁寫在這裡,可以加快主體加載速度

 

生命周期

 

bootstrap

boostrap相當於init,子應用在第一次加載的時候會調用這個方法, 一般可以在裏面做一些項目的初始化操作,例如

 

mount

每次在加載到子應用的時候都會調用它,就像是componentDidMount,一般情況下我們要把ReactDOM.render這樣的初始化函數寫在裏面,每次mount時調用render

 

unmount

這個跟mount正好相反,每一次註銷/切換子應用的時候會調用它,一般我們在這裡 ReactDOM.unmountComponentAtNode 註銷這個應用,然後把整個項目的容器讓出來

 

update

這是個可選的生命周期,子應用發生變化的時候會調用。

 

路由匹配

路由規則有兩種,需要手動調用對應的子應用渲染就行了,通過一個叫loadMicroApp的方法掛載一個子應用組件,這樣就可以在main中像配置一個正常的應用那樣配置子應用的view了。

 

import { loadMicroApp } from 'qiankun';
import React from 'react';
class App extends React.Component {
  containerRef = React.createRef();
  microApp = null;
  componentDidMount() {
    this.microApp = loadMicroApp(
      { name: 'app1', entry: '//localhost:1234', container: this.containerRef.current, props: { name: 'qiankun' } },
    );
  }
  componentWillUnmount() {
    this.microApp.unmount();
  }
  componentDidUpdate() {
    this.microApp.update({ name: 'kuitos' });
  }
  render() {
    return <div ref={this.containerRef}></div>;
  }
}

 

處理樣式

 

沙箱

qiankun的沙箱模式是在start的api配置項裏面開啟的

sandbox 選項可選

 

start({
  sandbox: true // true | false | { strictStyleIsolation?: boolean, experimentalStyleIsolation?: boolean }
})

默認情況下沙箱可以確保單實例場景子應用之間的樣式隔離,但是無法確保主應用跟子應用、或者多實例場景的子應用樣式隔離。當配置為 { strictStyleIsolation: true } 時表示開啟嚴格的樣式隔離模式。這種模式下 qiankun 會為每個微應用的容器包裹上一個 shadow dom 節點,從而確保微應用的樣式不會對全局造成影響。
shadow dom coco大神寫過一篇文章介紹這個,我就不班門弄斧了
//www.cnblogs.com/coco1s/p/5711795.html

 

樣式衝突解決方案

qiankun 會自動隔離微應用之間的樣式(開啟沙箱的情況下),你可以通過手動的方式確保主應用與微應用之間的樣式隔離。比如給主應用的所有樣式添加一個前綴,或者假如你使用了 ant-design 這樣的組件庫,你可以通過這篇文檔中的配置方式給主應用樣式自動添加指定的前綴。

以 antd 為例:

配置 webpack 修改 less 變量

 

{
  loader: 'less-loader',
+ options: {
+   modifyVars: {
+     '@ant-prefix': 'yourPrefix',
+   },
+   javascriptEnabled: true,
+ },
}

配置 antd ConfigProvider

 

import { ConfigProvider } from 'antd';
export const MyApp = () => (
  <ConfigProvider prefixCls="yourPrefix">
    <App />
  </ConfigProvider>
);

 

webpack配置的問題

微應用的打包工具還需要增加如下配置:

 

  const packageName = require('./package.json').name;
  module.exports = {
    output: {
      library: `${packageName}-[name]`,
      libraryTarget: 'umd',
      jsonpFunction: `webpackJsonp_${packageName}`,
    },
  };

 

qiankun實踐-react微前端應用

 

起始,準備2個react應用

直接用create-react-app創建兩個app應用

 

npx create-react-app main-app
npx create-react-app micro-app

可以得到一個文件夾里有兩個項目

我們用main做主應用,micro做子應用,按照我們的api,子應用只需要配置一個register就可以引入子應用了
其中子應用需要調出webpack配置,create-react-app默認是不允許手動配置的,使用命令就可以了
進入micro-app的文件夾目錄運行(create-react-app也有overload的辦法更改配置,這裡為了方便直接用命令調出來):

npm run eject

這樣項目的準備工作就做好了。

 

子應用配置

配置子應用兩個步驟,一個是生命周期的配置。 我們把生命周期函數寫好放到main.js中:

然後我們把reactDom.render放到mount生命周期里調用,讓qiankun在準備好加載mount的時候再去初始化應用:

unmount的註銷操作也不能忘記:

我們更改一下子應用的根節點id,在父應用中再去引用它(不要忘了html里也需要更改):

最後再把webpack中的配置修改一下:
1、修改devserver支持cors 修改端口
headers: { 'Access-Control-Allow-Origin': '*', }

 

 

 


2、修改增加bundle的導出,在webpack.config.js增加配置:

 

 

 

 

父應用配置

然後我們就可以去在main應用中,註冊了首先要

npm install qiankun --save

然後在main文件index.js中註冊子應用:

 

 

 

別忘了我們還需要在public/index.html中寫一個div容器,id是我們子應用的那個id,用來承載子應用的渲染:

 

 

 

然後我們就可以開始運行看一看了:

 

 

 

運行成功,隨便改一下micro的樣式看看效果:

 

 

 

接下來我們需要處理一下路由跳轉的問題。

 

路由的處理實踐

前文有提到,在react中使用qiankun可以使用apiloadMicroApp,這裡我們也用它來處理路由的跳轉。
我們主要是在main-app中操作:
首先新建micro-app的view文件(每多一個子應用就新建一個):

 

 

 

然後使用react-router直接配置:
由於create-react-app默認沒有直接提供react-router,我們手動下一個

 

npm install react-router react-router-dom --save

改完index.js長這樣:

 

 

再試一下:

 

 

大功告成! 

 

結論和源碼

相比較上一次我們看見的 singlespa的配置要簡單了很多,而且更加直白,新增子應用更加無縫。
需要demo源碼的同學私信我哦

 

應用場景和坑

 

坑-靜態資源問題解決

微應用打包之後 css 中的字體文件和圖片加載如果使用的加載路徑是相對路徑,會導致css 中的字體文件和圖片加載 404。

而 css 文件一旦打包完成,就無法通過動態修改 publicPath 來修正其中的字體文件和背景圖片的路徑。

主要有三個解決方案:

  • 所有圖片等靜態資源上傳至 cdn,css 中直接引用 cdn 地址(推薦)
  • 藉助 webpack 的 url-loader 將字體文件和圖片打包成 base64(適用於字體文件和圖片體積小的項目)(推薦)
  • 使用絕對地址,nginx中設置靜態目錄

  

結束語

qiankun整體的思路是比較ok的,它大大簡化了singlespa的使用邏輯,讓微前端的門檻變得更低,但它仍然有一些缺點,例如部分api總是會有莫名其妙的問題,例如api文檔不是特別的直觀等,這些都是待改進的地方。而對於微前端來說,做到能夠技術棧無關、漸進升級舊項目、分離不同業務等功能就已經能發揮它的最大價值了。