時間回到一週前,當時剛開發完公司A項目的一個新的版本,等待着測試完成就進行發佈。此時的我也準備從連續多日的緊張開發狀態中走出來,覺得能夠稍稍放鬆一下。而那時的我還不知道,我即將面臨一個強大的Bug選手,更不知道我要跟這個Bug來來回回進行屢次的搏鬥。固然,咱們能看到這篇文章也就說明了我最終解決了這個Bug,並且這個過程也是至關的精彩的。什麼?你不相信,那就讓我來帶你進入這個「跌宕起伏」的經歷中吧。前端
友情提示:接下來的文章也許有一點長,可是但願你可以堅持讀下去。我相信我在解決這個Bug的過程當中的一些思路會給你帶來一些思考。固然也但願你在這個過程當中可以像我同樣學習到一些新的知識,爲之後排查相似的Bug積累一些經驗。好啦,話很少說,讓咱們開始吧。vue
先來簡單介紹一下A項目,這是一個基於Vue
框架的項目,項目使用的也是Vue CLI
這個開發工具。這個項目是須要集成在別的APP中的,也就是頁面須要在APP中進瀏覽和操做。這個項目在我接手以前已經開發過一段時間了。因此項目中的一些依賴庫和工具庫版本相對比較低,這也給我後續的調試以及解決Bug的過程增長了一些困難。node
當時開發完成以後,就交給咱們這邊的測試和另外一個城市的相關同窗去驗收此次開發的功能。在咱們這邊一切都很正常,測試這邊也沒有反饋有什麼問題。可是在另外一個城市的同窗小C的iPhone手機上卻發現了白屏,打開頁面以後什麼內容也沒有。webpack
發現了這個問題以後,我再次跟咱們這邊的測試同窗確認了一下,看看咱們這邊測試的iOS系統的iPhone手機有沒有這個問題。通過測試的測試,發現咱們這邊的幾臺iPhone手機都沒有問題。而後就問了小C他使用的測試手機的系統版本是多少,當時感受應該跟iOS
的系統版本有關係。git
小C反饋說他的iPhone是6S Plus
,而後系統的版本是11.1.2
。我問了咱們這邊測試使用的iPhone版本都是多少,測試反饋說系統的版本都是12
以上的。因此到這裏,我肯定了這個白屏Bug的出現確定跟iPhone手機的系統有關係。github
雖然肯定了問題出現的環境,可是由於我身邊沒有系統是11
的iPhone手機,因此想讓這個問題重現就變成了一個難題。詢問了身邊的同事,你們的系統版本也都廣泛高於12
,因此借用別人的手機進行調試這個方法暫時也不可行。web
在平時的開發中,若是網頁在iOS
系統的APP中有一些問題的話,咱們通常都會經過Safari
瀏覽器進行調試。可是由於此次出現問題的iPhone手機不在我這裏,而且我這邊也沒有相同系統的手機。因此想經過真機進行調試就不太可能了。那怎麼辦呢?這個問題確定是要解決的,我也相信辦法總比困難多。npm
想要進行調試,最簡單的辦法就是讓我有一個系統是11
的iPhone手機。因此我就搜索看看有沒有什麼辦法能夠給iPhone手機安裝11
的系統。一搜索還真的有,過程也不算是很複雜。可是其中有一個步驟是須要到一些論壇或者第三方的助手網站下載跟本身手機型號相匹配的iOS
系統,這個步驟讓我有點感受不安全。畢竟不是官方的,不可以保證安全性。並且也未必有版本是11
的系統。因此這個方案就暫時做罷。json
在我搜索的過程當中,我發現有網友說可使用Xcode
安裝相應系統版本的iPhone模擬器
來進行調試。哎,你說我怎麼沒有想到這個辦法呢?這確實是一個不錯的辦法。由於以前跟公司的同事學習過Swift
,也瞭解過Xcode
的一些操做。忽然感慨,真是技多不壓身,你不知道你何時就會用上你學過的知識。因此有條件的話,仍是多學習一些知識。額,有點跑題了。瀏覽器
我打開公司的電腦,開始安裝Xcode
,可是發現公司的電腦系統版本過低,安裝Xcode
須要升級系統,因此沒辦法,先升級系統吧。由於升級的時間比較長,我想到本身家中的Mac電腦上是有安裝過Xcode
,因此決定先回家。留下公司的電腦慢慢升級。
回到家,二話不說就開始準備調試,可是發現個人Xcode
上面的iPhone模擬器的系統版本也都是12
以上的,查了一下資料,Xcode
是能夠安裝不一樣系統版本的模擬器的,因而我就安裝了系統版本是11
的模擬器。這個過程須要咱們打開Xcode
的偏好設置,而後在Components
選項中,選擇下載你要安裝的對應系統版本的模擬器。
安裝成功以後,運行iPhone 6S Plus
模擬器,使用模擬器的Safari
打開h5的頁面地址,果真是白屏。
小樣,終於把這個問題給復現了,這樣就距離解決這個Bug不遠了。我打開Mac
的Safari
瀏覽器,進入開發者模式,發現了以下所示的報錯
我搜索了一下這個錯誤,發現是由於項目中使用了...
ES6擴展運算符,而後iOS 11
系統不支持這個這個運算符。這麼容易就找到問題了,開心。想到這個問題仍是比較好解決的,能夠經過使用Babel
的一些插件,很容易就能夠將這個問題解決掉。而後我就開心的睡覺去了,心想這個問題也不是什麼大問題,明天處理一下就行了。
次日到公司,我就在項目中的babel
的配置文件中添加了相應的插件
{
... // 省略原來的配置內容
"plugins": ["@babel/plugin-proposal-object-rest-spread"]
}
複製代碼
而後發佈到測試環境中。告訴了小C同窗再次測試一下,我也在等着解決這個Bug的好消息。可是,出現的卻不是好消息,小C給我回復說仍是不能夠。什麼,不可能呀,我就立刻用公司的電腦再次進行測試。當我用公司電腦的Safari
調試系統是iOS 11
的iPhone 6S PLus
模擬器的時候,卻發現出現了下面這個狀況:審覈警告:「data-custom」太新,沒法在此檢查的頁面上運行
我就又搜索了一下爲何會出現這個問題,終於讓我找到了答案,Safari
瀏覽器的Web Inspector
工程師也說這是一個Bug,不過他們已經修復了,在下個發佈的版本中就能夠正常使用新的Safari
瀏覽器去調試比較老的iOS
系統的模擬器了。知道如今這個版本的Safari
調試不了模擬的iOS 11
系統的頁面。我有點沮喪,總不能我如今回家把個人電腦拿過來吧😂?當我想着該如何解決的時候,我發現了上面那個回答中提到了Safari Technology Preview
,Safari
技術預覽。
我看這個名字感受有點但願,而後就搜索了一下Safari Technology Preview
是什麼。而後就發現它相對於Safari
就跟Chromium
相對於Chrome
是同樣,都至關因而開發版本的瀏覽器。
這時,我以爲可使用Safari Technology Preview
進行調試。因此就下載了Safari Technology Preview
,當我打開Safari Technology Preview
而後進入開發者模式後,發現確實能夠調試iOS 11
系統的頁面。而後我就看了一下爲何仍是白屏的問題。發現出現的錯誤仍是上次的問題:
也就是說這個問題尚未解決掉,由於打包後的代碼是沒有SourceMap
的,因此要想看更詳細的報錯信息,須要在本地進行調試。本地的環境中是有SourceMap
的,能夠定位到更詳細的錯誤信息,我在本地運行了項目,而後我打開了控制檯的錯誤詳情,發現是使用的一個第三方的庫出現了問題。
那麼到這裏爲止,能夠說明上面咱們使用的Babel
插件沒有處理這個第三方的庫,因此如今咱們的問題就變成了:如何解決第三方庫中出現的...
擴展運算符沒有被編譯爲ES5語法的問題。
這時我又仔細的看了一下Vue CLI
的相關文檔,發現確實在瀏覽器的兼容性這個章節中,提到了一些處理的方法。原來咱們在項目中寫的代碼默認會幫咱們轉換爲ES5的語法的,可是若是項目中依賴的第三方庫須要polyfill
的話,那須要咱們手動進行配置。一看到這裏,我感受黎明就要來了。
我就開始嘗試這三種方法。我發現第一種方法是比較簡單的,也很好配置。因而我就嘗試了第一種方法。在項目的vue.config.js
中添加以下的配置:
... // 省略的配置
transpileDependencies: [
'module-name/library-name' // 出現問題的那個庫
],
... // 省略的配置
複製代碼
從新運行項目,當我將要爲即將到來的成功歡呼鼓掌時,控制檯忽然報告了以下的錯誤: Uncaught TypeError: Cannot assign to read only property 'exports' of object '#<Object>'
這個報錯是在Chrome
瀏覽器的控制檯出現的,由於項目在本地從新運行以後會首先打開Chrome
瀏覽器。真是的,一個問題尚未解決,又出來了一個新的問題。而後再次查詢資料後發現,原來是由於這個第三方的庫是一個CommonJS
類型的庫,而Babel
默認處理的是ES6
的module
類型的庫,因此這裏就又出現了新的問題。
第一種方法遇到了阻礙,先暫停一下。我準備繼續嘗試下面兩種方法。可是由於後面兩種方法對原來的項目改動有點大,因此我直接經過Vue CLI
建立了一個新的項目,在package.json
中加入項目中使用的那個第三方包的依賴,使用公司的包管理工具安裝了依賴。而後運行項目,打開控制檯確實發現了相同的錯誤。可是打開詳情之後,發現出錯的路徑跟我原來項目不一致。而後我此次抱着試一試的心態,繼續使用了第一種方法嘗試看看可不能夠。而後複製了出錯路徑的包名稱,在vue.config.js
文件中的對應位置添加了以下的配置代碼:
... // 省略的配置
transpileDependencies: [
'module-name-new/library-name-new' // 出現問題的那個庫
],
... // 省略的配置
複製代碼
而後從新運行項目,發現竟然能夠了。啊,竟然能夠了。爲何我在原來的項目中這樣卻不能夠呢?我看了一下原來項目的依賴以及如今新的測試項目的依賴,發現它們的vue
, babel
版本差了好多。我猜想多是由於這個緣由。可是如今確定不能夠貿然升級這些依賴的版本,由於爲了解決這個問題再次帶來新的問題就得不償失了。
還有一個問題就是爲何一樣的第三方庫,在原來的項目中和如今的項目中報錯的路徑不同。並且看着像是使用了兩個不同的第三方庫。這裏先留個懸念,我會在後面的文章中進行解釋。
接下來,我開始在測試項目中繼續嘗試剩下的兩種方法,對於第二種方法,由於老項目中使用的presets
是沒有polyfills
這個配置選項的,到如今爲止出問題的這個第三方庫我不知道除了這個...
對象擴展操做符以外還有沒有別的依賴。因此這個方法我暫時也放棄了。
對於第三個方法,我以爲能夠嘗試,首先我將測試項目中的一些關鍵依賴進行了手動降級,而後按照上面的第三個方法的步驟在測試項目中使用。可是發現測試項目運行以後,提示須要安裝core-js
,安裝core-js
以後還報錯,再次提示須要安裝es.module.regex.match
等等不少依賴,繼續查資料,發現須要把配置中的 useBuiltIns
修改,可是由於我接手的這個項目是老項目,依賴比較多,不肯定修改useBuiltIns
這個配置選項後會不會出現新的問題。因此也不敢貿然修改這個配置選項,因此也暫時放棄了這個方法。
我後來想了一下,對於...
擴展運算符來講,這是一個新的語法。是不可以經過一些polyfills
去解決的。須要Babel
對這個語法進行編譯,而後才能夠在低版本的系統中使用,因此解決的辦法仍是要讓Babel
對這個庫再次進行編譯。
當進行到了這裏的時候,彷佛沒有了出路。一時間我感受我要被這個Bug戰勝了,我彷佛聽到了它無情的嘲笑,「小夥子,是否是被我折磨的沒有脾氣啦;放棄吧,你是沒辦法打倒個人。哈哈哈。。。」
可是,它看錯我了,Bug越是難解決,我對它就越有興趣。因此我決定好好理一下思路,準備再次揚帆起航。
我發現第一種辦法實際上是起做用的,只不過是由於一個是CommonJS
類型的,一個須要是ES6 module
類型的。因此我決定從這個地方入手,因而我決定查查相關的資料,看看Babel
有沒有辦法能夠即可以處理CommonJS
模塊,又可以處理ES6 module
模塊呢?終於,功夫不負有心人,我發現了Babel
裏面有這麼一個配置sourceType
,若是把sourceType
設置爲unambiguous
就能夠解決這個問題。
這樣Babel
就會根據模塊文件中有沒有import/export
來決定使用哪一種解析模塊的方式。因而我再次使用了第一種方法,在vue.config.js
中添加了transpileDependencies
選項的配置,而後在項目中的Babel
配置文件中添加了以下的配置:
module.exports = {
... // 省略的配置
sourceType: 'unambiguous',
... // 省略的配置
};
複製代碼
發現的確能夠,這一刻成功的喜悅再次降臨。而後我再次打包,再次把代碼部署到測試環境,趕緊讓小C同窗再次測試一下,發現的確能夠。歐耶,終於解決這個問題了。我終於能夠鬆一口氣了,哈哈哈。。。小樣,這怎麼會可貴到我呢?
可是,當我仔細閱讀將這個選項設置爲unambiguous
時,我發現了一些問題。由於這樣的話會有一些風險,由於就算不使用import/export
語句的這些模塊也多是徹底有效的ES6 module
,因此這樣的話就有可能會出現一些意外的狀況。怎麼辦,我彷佛在一不留神的時候又被Bug卡住了脖子。
我以爲老天老是給我開玩笑,當我從一個坑裏跳出來,覺得沒有危險的時候。前面忽然又多出來一個坑,我一不留心就又掉了進去。我感受既然都走到了這裏,確定要繼續走下去,必定有辦法能夠優化我如今遇到的問題。我就很仔細的再次看了一下Babel
的配置說明文檔,這個時候就心想若是我對Babel
再熟悉一些就行了。不要緊,繼續努力。終於,我彷佛看到了什麼了不起的配置選項。
我在Config Merging options
裏發現了overrides
選項,這個配置選項不正是我須要的嗎?我能夠利用這個配置選項將我須要的第三方包使用unambiguous
的處理方式,而後其餘的第三方庫都按照以前的方式處理不就能夠了。哈哈哈,我真是個天才,我內心這樣對本身說😂。
因此只須要在項目的babel.config.js
中寫下以下的配置就能夠了:
module.exports = {
... // 省略的配置
overrides: [
{
include: './node_modules/module-name/library-name/name.common.js', // 使用的第三方庫
sourceType: 'unambiguous'
}
],
... // 省略的配置
};
複製代碼
對了,還有一件事情尚未說,那就是上文提到的關於爲何使用公司本身的包管理工具下載下來的node_modules
包的名稱跟使用官方的npm
包管理工具下載的包的名稱不一致的問題。緣由是公司使用的包管理工具是cnpm
的一個修改版本。又由於cnpm
爲了提升下載的速度,使用了cnpm/npminstall
,因此纔會出現下載的包名比較混亂的狀況,詳情能夠看這裏。
到此完結撒花,總結一下:出現白屏的緣由是由於使用的第三方庫的包中使用了...
擴展運算符,而後由於第三方的包默認是沒有被Babel
處理過的,因此在不支持...
的iOS 11
系統上就出現了白屏。解決的方式就是經過給vue.config.js
的配置文件中transpileDependencies
配置選項中添加上出問題的包的名稱就能夠了。固然若是項目比較老,可能還須要像文章上面寫的那樣的處理方式。
解決這個Bug過程就像是升級打怪同樣,不斷失敗,不斷嘗試,只要不放棄,終有成功的那一天。若是你堅持看到了這裏,那說明你也很棒呀。在當今這個信息爆炸的時代裏,可以堅持看完一篇很長的文章已經很不錯了。
一點反思與思考:這個過程當中我也發現了本身對Babel
和Vue CLI
其實沒有那麼熟練,若是我對它們比較熟練的話,那我解決這個Bug應該會花費更少的時間。固然,如今把它們學習好也不算晚。要抱着學習的態度,此次解決這個Bug的過程,就是我之後解決其它相似Bug的經驗。還有在解決Bug的這個過程當中要有耐心,固然在嘗試以後也要學會放棄錯誤的方向。
寫這篇文章也花費了我很多的時間,若是你有所收穫或者感悟,不妨點贊,轉發,收藏走一波,這個要求應該不算過度吧😂?
若是你對本篇文章有什麼意見和建議,均可以直接在文章下面留言,也能夠在這裏提出來。也歡迎你們關注個人公衆號關山不難越,學習更多實用的前端知識,讓咱們一塊兒努力進步吧。