我是怎么調試 Element UI 源碼的
??上篇文章??寫了怎么調試 antd 的源碼,反響很不錯:
但很多小伙伴是寫 Vue 的,可能平時用的是 Element UI 的組件庫,所以這篇文章就來講下怎么調試 Element UI 的源碼。
首先,我們用 Vue CLI 創建一個 vue2 的項目:
創建成功后,進入到項目目錄
安裝 element ui 的庫,并在入口引入:
然后在 App.vue 里用一下 button 組件
之后 yarn run serve 把開發服務跑起來,就可以看到這樣的頁面:
Element UI 的組件正確的顯示了。
接下來調試 button 組件的源碼,那問題來了,我怎么知道在哪里打斷點呢?
我們可以知道的是,這個 button 會處理點擊事件,但是卻不知道事件處理函數的代碼在什么地方。
這種情況可以加一個事件斷點:
在 sources 面板的 Event Listener Breakponts 里勾選 Mouse 的 click 事件,也就是在所有 click 事件的處理函數處斷住。
然后你再點下那個按鈕試試看:
你會發現它在事件處理函數處斷住了。
當你知道這個組件處理了什么事件,但卻不知道事件處理函數在哪的時候就可以用事件斷點。
當然,這個事件處理函數并不是組件里的,因為 Vue 內部會先做一些處理,然后再交給組件處理。
所以,我們要先走到組件的事件處理函數:
單步執行、再進入函數內部,再單步執行、再進入函數內部,代碼就會走到組件的事件處理函數:
methods、computed、props,這明顯是源碼里的了。但你再往上走兩步,會發現又不是最初的源碼:
template 變成了 render 函數,而且還有其他組件的代碼,這明顯是被編譯打包之后的代碼。
從文件名也可以看出來:
這是一個把所有組件代碼編譯后打包到一起的文件。
這樣雖然也能調試,但肯定是不爽的,能不能直接調試組件最初的源碼呢?就是帶 template 的單文件組件那種?
是可以的,這就要用到 sourcemap 了。
sourcemap 是在編譯過程中產生的:
里面記錄了目標代碼和源代碼的映射關系,調試的時候可以通過它映射回源碼:
但是你去 node_modules 下看看,會發現沒有這個文件的 sourcemap:
那怎么生成它的 sourcemap 呢?
這就要從源碼重新編譯了。
我們從 github 把它的源碼下載下來:
--depth=1 是只下載單個 commit,--single-branch 是下載單個 branch,這樣下載速度能快幾十倍,是一個加速小技巧。
進入 element 目錄,安裝依賴,你會遇到一個前端經常頭疼的問題,node-sass 安裝報錯了:
這個問題的解決方案就是把 node 版本切換到 node-sass 版本對應的那個。
package.json 中可以看到 node-sass 是 4.11.0
打開 node-sass 的 github 首頁:
你會看到這樣一個版本對應關系表:
4.11 對應 node11,那就把 node 切換到 11 就可以了。
然后再次 yarn 安裝依賴就能成功了。
之后開始編譯,在 npm scripts 中可以找到 dist 命令,這就是構建源碼用的:
但是我們只需要 element-ui.common.js 這個文件:
其實只需要執行其中的一部分腳本,也就是這個:
所以在項目下執行 npx webpack --config build/webpack.common.js 即可:
然后在 lib 下就可以看到構建產物:
但我們的目標是生成帶有 source-map 的代碼,所以要改下配置:
修改 build/webpack.common.js,配置 devtool 為 cheap-module-source-map:
source-map 是生成 sourcemap 并關聯,也就是這樣:
module 是把中間 loader 產生的 sourcemap 也給合并到最終的 sourcemap 里,這樣才能直接映射到源碼。
cheap 是加快編譯速度用的,只保留行的映射信息。
改完配置后再次 yarn run dist,就可以看到帶有 sourcemap 的產物了:
把這倆文件復制到測試項目的 node_modules/element-ui 下覆蓋下之前的:
之后清掉 node_modules/.cache 下的緩存,重新跑 dev server:
這時會報錯提示你 node 版本太低了,你需要再把 node 版本換回來:
跑起開發服務之后,再次用之前的方式調試 button 組件的源碼:
你會發現現在的組件代碼是帶 template 語法的單文件組件的代碼了!
這就是 sourcemap 的作用。
之后你會可以在這個組件里打斷點然后調試。
有的同學可能會問,通過事件斷點進入組件內部,這樣有點麻煩,有沒有更簡單的方式?而且 button 組件有點擊事件,但有的組件沒有呀,這些組件該怎么調試呢?
確實,有了 sourcemap 之后就有更簡單的調試方式了。
你可以在 sources 左邊看到 ELEMENT 目錄下有很多 vue 文件,這其實就是 Chrome DevTools 解析 sourcemap 之后列在這里的:
你可以直接在里面打斷點調試。
比如我們加一個 tabs 組件:
把前面添加的那個事件斷點去掉,在代碼里手動打一個斷點:
然后你就會發現,這樣就可以調試 Element UI 組件源碼了!
當然,有的組件找不到的時候,還是可以通過事件斷點的方式來進入組件內部。
我們是通過 Chrome DevTools 調試的,其實用 VSCode Debugger 來調試它也是一樣的,在 Chrome DevTools 里打的斷點,在 VSCode Debugger 里同樣會斷住。
總結
今天我們調試了 Element UI 的源碼。
定位到組件的代碼,是通過事件斷點的方式,因為我們知道它觸發了什么事件,但卻不知道事件處理函數在哪。
但是組件的代碼是被編譯打包過的,不是最初的源碼。
為了調試最初的源碼,我們下載了 Element UI 的代碼,build 出了一份帶有 sourcemap 的代碼。
覆蓋項目 node_modules 下的代碼,重新跑 dev server,這時候就可以直接調試組件源碼了。
有了 sourcemap 之后,Chrome DevTools 會直接把 vue 文件列在 sources 里,我們可以找到對應的 vue 文件來打斷點,就不用通過事件斷點來找了。
能夠調試 Element UI 源碼之后,想知道組件內部都有哪些邏輯的話,就可以直接在源碼斷點調試了,就很香。