背景
- 項目升級為
vue@2.7.16 vue@2老項目很難升級為vue@3vue.js devtools@5.3.4不再維護vue.js devtools@5.3.4不支持新的setup state等常用功能vue.js devtools@6.6.3對vue@2一進入頁面卡死- 項目由於歷史以及業務原因頁面性能很差,導致
vue.js devtools@5.3.4會在一些場景卡死 chrome強制要求extension升級為manifest@v3
解決方法:從5.3.4fork一個新的devtools,針對巨石複雜歷史頁面進行適配
功能
- 支持
setup數據展示
- 支持
pinia數據
- 升級為
manifest v3 - devtools項目升級為
webpack@5 - 使用
vue@2.7.16進行開發 - 支持response的通信機制
問題:進入頁面卡頓
定位原因
進入頁面後產生了數千個vuex:mutation事件,每一個vuex事件都會將store進行序列化並傳遞給backend.html
解決
由於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功能開關不生效
解決
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後Component下data;props;setup;等子模塊展示才會發生變化
問題:選中簡單組件卡頓
一些很簡單的組件選中後頁面卡頓,devtools卡死。
定位原因
$refs中的組件實例跑到了computed中;導致獲取了其他組件的實例數據
由於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.js和devtool.js。
- backend.js: 宿主頁面(即前台https://localhost頁面)執行
- devtool.js: devtool下inspector頁面執行
通信過程如下圖
連接方式特性如下
- 發送1次消息需要經過4次消息轉發
devtool和service-worker建立了1個長連接content-script和service-worker建立了1個長連接- 建立的port使用中經常斷開,且沒有任何報錯信息以供參考
解法
由於port斷開,導致了開發工具點擊沒有效果。針對以上問題,提出以下解法
- 發送消息路徑改為:web <=>
content-script<=>devtools.html3步 - 不再使用長連接,改為每次轉發消息直接
sendMessage。這裏實際上是tcp思路改為了udp思路
項目地址
https://github.com/kxxxlfe/devtools
完