Stories

Detail Return Return

vue2 devtools導致頁面卡頓,解決方案 - Stories Detail

背景

  • 項目升級為vue@2.7.16
  • vue@2老項目很難升級為vue@3
  • vue.js devtools@5.3.4不再維護
  • vue.js devtools@5.3.4不支持新的setup state等常用功能
  • vue.js devtools@6.6.3vue@2一進入頁面卡死
  • 項目由於歷史以及業務原因頁面性能很差,導致vue.js devtools@5.3.4會在一些場景卡死
  • chrome強制要求extension升級為manifest@v3

解決方法:從5.3.4fork一個新的devtools,針對巨石複雜歷史頁面進行適配

功能

  • 支持setup數據展示

image

  • 支持pinia數據

image

  • 升級為manifest v3
  • devtools項目升級為webpack@5
  • 使用vue@2.7.16進行開發
  • 支持response的通信機制

問題:進入頁面卡頓

定位原因

進入頁面後產生了數千個vuex:mutation事件,每一個vuex事件都會將store進行序列化並傳遞給backend.html

image

解決

由於vuex我們基本只會查看最新狀態,不太會使用其時間旅行功能,因此對vuex:mutation進行截流處理如下

// devtools/packages/app-backend/src/vuex.js

+   const onMutation = debounce((...args) => this.onMutation(...args), 500) // onMutation比較耗時,不需要時間旅行,截流
    hook.on('vuex:mutation', onMutation)

副作用:短時間內大量的vuex改動,只會記錄其中的1-2次store快照

問題:點擊一些選項頁面卡頓

定位原因

  • 點擊選項導致router修改了query,發生了replace。
  • 觸發了router:changed事件
  • 事件會對afterEach中的to進行完整序列化
  • to數據中包含了大量的頁面數據
  • 以上邏輯,router功能開關不生效

image

解決

router這個功能很少用到,平常開關是關的,使這個開關生效

// packages/app-frontend/src/index.js

  bridge.once('ready', version => {
    store.commit('SHOW_MESSAGE', 'Ready. Detected Vue ' + version + '.')
    bridge.send('events:toggle-recording', store.state.events.enabled)
+   bridge.send('router:toggle-recording', store.state.router.enabled) // 初始化時需要正確初始化router開關
    ...

問題:頻繁操作卡頓

  • 鼠標來回滑動時,頁面卡頓
  • 頁面中組件成千上萬個

定位原因

大量事件觸發導致component模塊兒短時間觸發了大量flush更新

解決

使用截流減少flush次數

// kxxxlfe-libs/devtools/packages/app-backend/src/hook.js
    hook.on('flush', () => {
      if (hook.currentTab === 'components') {
-        flush()
+        debounceFlush()
      }
    })

副作用:交互後,300ms後Componentdatapropssetup;等子模塊展示才會發生變化

問題:選中簡單組件卡頓

一些很簡單的組件選中後頁面卡頓,devtools卡死。

定位原因

$refs中的組件實例跑到了computed中;導致獲取了其他組件的實例數據

image

由於levelList裏面有一個巨大的computed,導致devtools卡死

因為class中使用了@Ref語法,如下

@Ref('level-list') levelList!: LevelList

@Ref實現如下

/**
 * decorator of a ref prop
 * @param refKey the ref key defined in template
 */
export function Ref(refKey) {
    return createDecorator(function (options, key) {
        options.computed = options.computed || {};
        options.computed[key] = {
            cache: false,
            get: function () {
                return this.$refs[refKey || key];
            },
        };
    });
}

解決

devtools收集數據時,移除computed中與$refs同名的屬性

// kxxxlfe-libs/devtools/packages/app-backend/src/index.js

+ if (def.cache === false && !Reflect.hasOwnProperty(def, 'set')) {
+   if (Object.values(instance.$refs).find(comp => comp === instance[key])) {
+     continue
+   }
+ }

問題:一段時間後devtools點擊沒反應

  • 一段時間後devtools的Component標籤大概率失效
  • 關閉devtools重新打開可以解決

定位原因

由於extension有多個環境,各個環境之間通信機制有所不同,針對vue devtools其通信主要圍繞backend.jsdevtool.js

  • backend.js: 宿主頁面(即前台https://localhost頁面)執行
  • devtool.js: devtool下inspector頁面執行

通信過程如下圖
image

連接方式特性如下

  • 發送1次消息需要經過4次消息轉發
  • devtoolservice-worker建立了1個長連接
  • content-scriptservice-worker建立了1個長連接
  • 建立的port使用中經常斷開,且沒有任何報錯信息以供參考

解法

由於port斷開,導致了開發工具點擊沒有效果。針對以上問題,提出以下解法

  • 發送消息路徑改為:web <=> content-script <=> devtools.html 3步
  • 不再使用長連接,改為每次轉發消息直接sendMessage。這裏實際上是tcp思路改為了udp思路

項目地址

https://github.com/kxxxlfe/devtools

user avatar kalii Avatar honwhy Avatar aqiongbei Avatar wx709294 Avatar
Favorites 4 users favorite the story!
Favorites

Add a new Comments

Some HTML is okay.