成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

效率前端微應用推進之微前端研發提效

開發 前端
微前端中,基座應用(父應用)、子應用是常見概念,本文描述中,“基座應用”又名“父應用”,為簡化文案,“基座應用與子應用”也被稱為“父子應用”。

一、背景

業務背景

得物效率前端所在的效率工程為提升企業協作效率而生,面臨大量的 PC 側的中后臺應用場景。

在之前的微信公眾號《得物效率前端微應用推進過程與思考》中詳細介紹了效率前端推進微應用落地的思路和部分效果。

這篇文章將著重介紹得物效率前端微應用推進中,微前端的研發效率遇到的挑戰和解決方案。

名詞解釋

微應用

「微應用」是得物效率前端內部稱謂,是一個基于“monorepo & 微前端 & 基座與業務分離”的、包括“文檔 & 工具”的一套體系化降低研發成本和提升用戶體驗的技術產品。

微前端

「微前端」是得物效率前端微應用推進的重要一環,尤其是父子應用技術棧不同時,利用 iframe / qiankun / wujie / micro-app 等工具進行微前端化改造,能顯著增強業務擴展性。

圖片圖片

基座應用/父應用

微前端中,基座應用(父應用)、子應用是常見概念,本文描述中,“基座應用”又名“父應用”,為簡化文案,“基座應用與子應用”也被稱為“父子應用”。

瀏覽器插件/擴展

chrome://extensions/ 頁面中對第三方工具稱為“擴展”,在本文語境下,又稱為“插件”。

二、研發費力度痛點

就研發效率而言,微前端在團隊多個業務落地后,面臨研發過程費力度高的問題。

費力點1

本地開發時,從啟動 1 個本地服務,變為需啟動 2 個本地服務:

大大多數情況下,項目需要啟動  2 個本地服務(基座應用和子應用)才能進行日常開發,因為子應用通常依賴基座應用透傳一些依賴數據。

而非微前端場景下,啟動 1 個應用就可以了,這反而引入了降低了研發效率。雖然微前端方案更注重業務效率,但研發效率也是必須要考慮的。

如果電腦性能一般的話,卡頓問題就隨之而來了。

費力點2

基座應用本地代碼需要做適配性改造:

如父應用需要區分本地環境和生產環境類似這樣的代碼,雖然代碼量不大,但還是需要關注的:

// 基座代碼
if (isLocal) {
    return <microapppage src="localhost://8000/a/b/c" />
} else if (isProd) {
    return <microapppage src="https://www.abc.com/a/b/c">
}

費力點3

頻繁無規律刷新:

在 Qiankun 微前端框架且本地開發環境下,基座應用與子應用頁面均需要 WebSocket 與其自身本地服務進行通信。

在同時啟動基座與子應用的本地服務后,修改子應用代碼以及偶發的,頁面會觸發 Reload,而不是局部更新,開發體驗很差。針對這個問題我們做了一些分析。

HMR 的熱更新邏輯

本地開發過程會啟動 Webpack-Dev-Server 服務,其會監聽業務文件變化,瀏覽器通過 WebSocket 與 Webpack-Dev-Server 進行通信。

當發現文件內容改變時 Webpack-Dev-Server 會根據更新的文件內容生成 Hash 信息傳遞給瀏覽器,如圖:

圖片圖片

當瀏覽器收到信息時,會根據收到的信息和配置進行判斷是刷新操作還是熱更新操作。熱更新時,Webpack-Dev-Serer 通過 Jsonp 拉取最新的 JS 模塊代碼,并進行模塊替換,如圖:

圖片圖片

若此過程異常,則會降級為頁面刷新。

無規律刷新原因分析

基座應用(端口 8010)熱更新時返回的文件 Json 和 JS 文件(分別是 **:8010/update.json 和 **:8010/update.js)內容如下:

圖片圖片

圖片圖片

但在嵌套在基座應用中的本地子應用(端口 8020)熱更新時,兩個同類文件并沒有返回內容(**:8020/update.json 和 **:8020/update.js)

圖片圖片

圖片圖片

若瀏覽器單獨打開兩個文件的地址(**:8020/update.json 和 **:8020/update.js),有內容返回。

圖片圖片

但是在基座與子應用嵌套的情況下,子應用的任何請求(包括 update.json / update.js )都會被基座應用代理,開發環境下很容易出現子應用的更新探針請求被基座代理后,出現內容丟失的情況。

子應用 HMR 邏輯檢測到更新探針請求內容異常,局部更新失效,降級為頁面刷新。

即使該問題解決,微前端應用開發者依然面臨同時啟動 2 個應用才能啟動開發的問題,所以我們不過度投入精力關注這個問題。

三、技術調研

解決「默認情況下,父子應用需要分別獨立啟動,并指定關聯關系」的問題,最好的方式是回歸到非微前端場景下的常規開發方式,即只啟動 1 個應用進行本地開發。

通常情況下,我們開發的是子應用(也就是業務頁面),那先實現子應用單獨啟動即可開啟項目開發吧,以下是面向該需求的技術調研。

Shared 通信

Shared 通信方案的原理是,主應用維護一個狀態池,通過 Shared 實例暴露一些方法給子應用使用。

同時,子應用需要單獨維護一份 Shared 實例,在獨立運行時使用自身的 Shared 實例,在嵌入主應用時使用主應用的 Shared 實例,這樣就可以保證在使用和表現上的一致性。

Shared 通信方案要求父子應用都各自維護一份屬于自己的 Shared 實例,同樣會增加項目的復雜度。同時,在子應用獨立運行時,Shared 只能獲取本地緩存數據,無法真正做到完全獨立于子應用運行。

圖片圖片

Mock 父應用環境

也就是在子應用中模擬父應用嵌套環境,提供一個獨立的模擬父應用的組件,封裝了 Layout 布局、權限、用戶信息等,并且具備必要的父子通信能力,子應用調用該 Mock 組件,獨立啟動以后進行日常開發。

這個方案和 Shared 通信有類似之處。

用戶體驗

// 這是子應用代碼


import { MicroLayout } from '@abc/components';


//  組件內使用
<MicroLayout title="Layout 內容">
    {children}
</MicroLayout>

圖片圖片

流程設計

圖片圖片

其他

對業務開發者而言,基座應用 Layout 的改動均需要使用者進行 Mock Component 的升級,比較麻煩。

對 Mock Component 開發者而言,需要額外開發父子通信方案 Microservice,用于 Mock Component 與子應用的通信。

這套方案在應對比較簡單的甚至沒有數據傳輸的微應用上是可以的,但是對于自定義化程度較高,復雜程度較高的微應用項目來說就不是很方便了。

四、Chrome 代理插件

也就是通過 Chrome 插件,將線上子應用 URL 代理到本地代碼。

利用瀏覽器提供的插件特性,劫持 HTTP 請求,將已經部署在測試/預發/線上環境的項目的微應用部分代理到開發者本地啟動的項目,這樣可以不用啟動基座應用,直接打開目標環境的主應用,卻可以訪問本地子應用項目進行開發工作。

用戶體驗

圖片圖片

其他

子應用需要的數據通過目標環境的父應用獲得,和第一套方案相比,他既可以滿足復雜場景下的子應用獨立啟動,也不需要關注每個接入的子應用他的數據依賴關系,研發成本也較低。

圖片圖片

四、Chrome 代理插件

產品設計

“Chrome 插件代理子應用到本地代碼”以提升微前端研發效率,該瀏覽器插件需要具備以下核心能力:

圖片圖片

規則靈活配置。插件實現了 from 和 to 的地址映射規則配置表單。

如下圖,所有含 https://t1-xxxxxxxx.net/microapp/ 路徑的請求都將被代理到 localhost:8020/microapp/。

圖片圖片

  1. 緩存能力。用戶關閉瀏覽器/電腦后再次打開,仍然能夠使用之前保存的代理規則。
  2. 快捷操作。為常用產品配置內置規則,一鍵即可啟動,非常方便。
  3. 實時顯示。需要實時顯示代理規則的生效情況,方便用戶確認哪些規則正在生效。

技術設計

Proxy 和 Popup

Chrome 插件分為 2 個模塊:Proxy 代理劫持模塊和 Popup 用戶交互模塊。

圖片圖片

功能流轉

圖片圖片

無感更新(Seamless Update)

圖片圖片

popup.html 作為用戶界面入口,動態引入 popup.js 處理用戶交互,popup.js 動態引入 proxy.js 執行 url 攔截規則。

這么做需要在 chrome 插件的 csp 安全策略配置中加入 cdn 域名白名單,允許插件訪問外部 cdn 資源。

manifest.json 配置如下:

值得注意的是,無感更新方案只在 Chrome V2 中實現了,V3 版本的 Chrome 插件執行了更為保守的安全策略,限制第三方資源的加載。

{
...
"permissions": [
  "webRequest", // 允許瀏覽器開放http請求劫持的功能
  "storage", // 允許使用瀏覽器緩存
  "activeTab", 
  "background", 
  "webRequestBlocking",
  "<all_urls>"
],
// 允許特定域名可以訪問的安全策略
"content_security_policy":"script-src 'self' https://cdn.xxxxx.com 'sha256-G7YAg/PQDo8GYc/fSYvWtXP98kXS7iqT7K4QZgyhUIE='; object-src 'self'",
"content_scripts": [
  {
    "matches": ["*://*.xxxxxxx.net/*"],
    "js": ["contentScript.bundle.js"]
  }
]
}
// ==========attentinotallow===========
//v2配置,v2版本中可以配置script等通過外部引入,這個content_security_policy配置參數不加或者加上之后相應的值填none
"content_security_policy": "script-src 'none'; object-src 'none'",


//v3配置,v3版本中安全政策配置script引入等信息,都必須填寫self,即只允許script標簽引用當前插件內部文件,不允許引用外部鏈接,如果不填寫self的話,插件添加到擴展程序時會報錯
"content_security_policy": {
//原文:此政策涵蓋您的擴展程序中的頁面,包括 html 文件和服務人員;
"extension_pages": "script-src 'self'; object-src 'self'",


//原文:此政策涵蓋您的擴展程序使用的任何[沙盒擴展程序頁面](https://developer.chrome.com/docs/extensions/mv3/manifest/sandbox/)。;
"sandbox": "sandbox allow-scripts; script-src 'self'; object-src 'self'"
},

在 popup.html 中動態引入 popup.js 示例:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Popup</title>
    <script>
      var scriptEl = document.createElement('script');
      scriptEl.defer = "defer";
      scriptEl.src = "https://cdn.xxxxxxxxxxx/popup.js?timestamp=" + Date.now();
      document.getElementsByTagName('head')[0].appendChild(scriptEl);
</script>  
  </head>


  <body>
    <div id="app-container"></div>
  </body>
</html>

各模塊 JS 在構建后上傳至 CDN,再在 popup.html / background.js / ... 中動態引入以實現無感更新。

圖片圖片

Proxy

  1. 攔截頁面請求。
  2. 提供緩存配置的功能,用戶在關閉瀏覽器后,配置的映射關系不會自動消失,以便用戶下次打開的時候正常提供服務。
  3. 通信功能,需要將用戶在 Popup 頁面交互時提交的數據地址數據提供給攔截方法,從而實現對應的攔截效果。
  4. 提供配置信息狀態的緩存數據,方便觀測攔截效果。

以下是攔截邏輯的相關代碼:

chrome.webRequest.onBeforeRequest.addListener(
  worker.getRequest.bind(worker),
  {urls: worker.getFilterUrls(worker.replaceRules)},
  ['blocking']
);
// Class background 
class Background {
    constructor() {
    this.replaceRules = []
    }
    getRequest(details) {
      if (!details) {
        // chrome未返回任何request
        return false
      }
      const {url} = details
      const returnObj = {}
      if (this.replaceRules.length) {
        // 存在替換規則
        this.replaceRules.map((item) => {
          if (url.includes(item.from)) {
            // 更新 icon 狀態
            this.setBadgeInfo(true)
            // 代理替換
            returnObj.redirectUrl = url.replace(item.from, item.to)
            // 緩存更新當前代理域名
            chrome.storage.sync.get(null, function (data) {
              if (data.messageProxyingData) {
                // 存在被代理的數據,合并數據
                const isExistMessageProxyingData = data.messageProxyingData
                chrome.storage.sync.set({messageProxyingData: Object.assign(isExistMessageProxyingData, {[item.key]: true})})
              } else {
                // 未存在緩存,使用新數據
                chrome.storage.sync.set({messageProxyingData: {[item.key]: true}})
              }
            })
          }
        })
      }
      return returnObj
    }
}

可以看到,chrome.webRequest.onBeforeRequest/ getRequest 配合攔截獲取請求地址,然后攔截替換目標路徑,當然這是比較簡單的邏輯,復雜的可以參考 glob 寫法代理鏈接。

Popup

Popup 用戶交互模塊,支持一鍵開啟和一鍵關閉、支持自定義配置映射地址。

圖片圖片

const sendMessage = (data: DataType[]) => {
  // 保留數據中已開啟的數據,進行數據傳輸
  const finalData = data.filter.((item) => item.is_open);
  chrome.runtime.sendMessage({ data: finalData, type: 'rule' });
};
const handleSaveData = (
  data: DataType[],
  isNeedSendMsg: boolean,
  key?: number[]
) => {
  setDataSource([...data]);
  // 緩存配置
  chrome.storage.sync.set({ popupData: data });
  if (isNeedSendMsg) {
    sendMessage(data);
    if (key?.length) {
      chrome.storage.sync.get(null, function (data) {
        const messageProxyingData = data.messageProxyingData || {};
        if (messageProxyingData) {
          key.forEach.((item) => {
            delete messageProxyingData[item];
          });
        }
        chrome.storage.sync.set({ messageProxyingData });
      });
    }
  }
};

ContentScript

原本無需在 ContentScript 中植入代理相關的任何邏輯,但在 Qiankun 微前端場景下有一個問題,子應用的熱更新會失效(可能導致 HMR 無效進而只能 Reload 頁面查看最新頁面效果),為此我們正好可以借助 Chrome 插件可注入 ContentScript 的能力,為用戶自動規避一些問題。

下面這段注入頁面的 ContentScript 可以輔助解決 Qiankun 子應用代碼更新后 HMR 失效的問題(方案來自社區)。

const scrpit = document.createElement('script')
scrpit.textContent = `
window.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__ =
        window.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__ || {
            iframeReady: function () {
                var overlay = document.querySelector(
                    'iframe[style*="z-index: 2147483647;"]',
                );
                if (overlay) {
                    overlay.style.display = 'none';
                }
            },
        };
`
document.body.appendChild(scrpit)

五、推進情況

項目覆蓋率

目前該插件在效率前端的微應用項目覆蓋率達到了 100%,在推進過程中,只需要用戶「安裝 1 次插件」,即可使用,后續更新無需關心(減少「插件需要更新」的心理負擔)。

研發效率

  1. 避免了父子應用均啟動時,子應用代碼更新后,父應用被動觸發 Reload 的問題。
  2. 子應用 HMR 熱更新延時與非微前端項目沒有差距。

用戶反饋

從研發側的反饋來看,確實有效地提高了微應用場景下的研發效率,告別啟動多個本地服務的煩惱。

同時,Chrome 插件方案實現簡單、使用方便,是此類場景下,在研發成本和用戶體驗上的表現比較均衡的解決方案。

六、思考

這個產品是效率前端業務小組發起,從 0 到 1 進行產品設計、技術方案調研、開發、完成落地的,既讓參與的同學經歷了完整的技術產品研發過程,也解決了實際業務中遇到的問題,并得到了正反饋。

對于此產品,還有可以持續完善的地方,比如:可以增加本地服務的保活探針,替代手動開啟代理規則,更智能化;或者利用其動態更新能力擴充功能,從很具體的小事情入手,不斷解決更多問題。

對于團隊,發現工作中的痛點,用工具化的方式沉淀解決方案,解決實際問題,也是前端同學提升自身價值的一個可行路徑。


責任編輯:武曉燕 來源: 得物技術
相關推薦

2023-08-02 18:56:29

效率前端微應用

2021-04-21 19:20:53

前端 容器應用

2022-10-17 15:21:18

2023-03-07 10:44:05

前端JS 調試

2020-07-22 13:50:39

shell命令前端

2022-04-02 17:20:00

微前端應用技術

2020-05-06 09:25:10

微前端qiankun架構

2022-05-23 08:34:08

微前端微服務開發

2023-12-27 18:15:42

組裝式生態提效開發中心

2020-07-27 15:50:28

微前端組件前端

2023-11-20 08:12:15

2018-11-01 14:12:03

前端架構Javascript

2020-04-22 15:20:39

前端框架代碼

2022-07-08 11:18:33

前端實踐自動化

2024-09-02 08:03:23

2023-12-29 13:45:57

2021-04-30 23:26:28

微前端開發工具

2020-10-18 12:00:27

前端開發架構

2021-05-18 09:48:58

前端開發架構

2022-09-07 21:31:19

微前端架構iframe
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美xxxx性xxxxx高清 | 81精品国产乱码久久久久久 | 亚洲欧美日韩国产综合 | 91精品国产91久久久 | 国产99精品 | 国产麻豆一区二区三区 | www97影院 | 亚洲先锋影音 | 亚洲午夜在线 | 黄a网| 91久久精品一区二区二区 | 自拍视频一区二区三区 | 国产午夜精品久久久久免费视高清 | 国产福利91精品 | 日本一区二区三区免费观看 | 91视频免费在观看 | av片免费观看 | 亚洲高清在线 | 国产一区二区三区久久久久久久久 | 91成人免费看片 | 天天射夜夜操 | 精品日韩电影 | 国产在线精品一区二区 | 国产日韩一区二区三区 | 精品国产aⅴ | a级黄色毛片免费播放视频 国产精品视频在线观看 | 精品久久一区 | 国产精品日韩一区 | 91一区二区三区 | 欧美一区二区在线观看 | 亚洲欧美综合精品久久成人 | 日韩av网址在线观看 | 午夜精品一区二区三区在线 | 欧美激情一区 | 在线播放国产一区二区三区 | 国产精品区二区三区日本 | a级在线免费观看 | 精品久久国产 | 欧美一区二区在线看 | 久久精品小短片 | 国产欧美精品一区二区 |