https://goo.gl/jKvPnc
- 為了 adaptive width 的 plugin (目前只有
fb-page
),調整 directive parsing 的流程 - 支援 Embedded Video Player
想不到才隔一天馬上又 release 一個小版… 我也是千百個不願意!
話說昨天那位印度人很快的發現了新支援的 Page plugin 有 bug
我也馬上著手修正,想不到這一下去就是 5 小時…
遠古怪獸 - initial XFBML rendering
其實就是某個一直以來存在但不為我所知的問題在這個 bug 中浮現了。
Facebook JavaScript SDK 會在第一次載入之後主動去掃過整個 DOM (with document.getElementsByTagName('*')
),對出符合它支援顯示的 social plugin 之後進行一次 render。
一直以來這個初次的 render 都被我的 directive 忽視了,在我的 directive 生成的時候會透過 FB.XFBML.parse()
也來針對性的 render 一次。往往 SDK 載入的那次都會跑在我的 directive render 之後,總之如果一個 social plugin 在頁面第一次載入的時候是可見的,基本上它就是會被連 call 兩次 FB.XFBML.parse()
。
是說我在挖 SDK 裡面的程式碼的時候發現,針對正在跑 rendering 流程的 plugin,FB.XFBML.parse()
還是會無情的觸發第二次 render,明明有個參數是「強制 parse」你們永遠代 true
是哪招啊啊啊啊!(另外其實內部有個 function 叫做 parseNew
,就是「不強制 parse」正在 render 的 plugin,結果整個 code 都沒有 call 它到底是…)
Adaptive width
遠古怪獸當然是不會隨隨便便就醒過來,需要適當的媒介才能夠喚醒他(X)
還記得上版 release 有說到 adaptive width 需要取得 parent 的 width;而根據 SDK 內程式碼,其實他們使用的方法是很單純的 element.offsetWidth
。這時候遠古怪獸就登場了!
Facebook 的 social plugin 一旦進入 parse -> rendered
的過程之後就會主動的被新增一個相當關鍵的 class 叫做 fb_iframe_widget
(乍看好像只有 iframe widget 才會套用的 class,但現在每個 plugin 都是 iframe 就是了),來看看它的 CSS style:
.fb_iframe_widget {
display: inline-block;
position: relative;
}
發現問題出在哪兒了嗎? 我們先列出一次簡單的 parse 流程:
- 找到有
fb-page
class 的元素 - 透過 element.offsetWidth 取得 container width
- 為元素加上 class
fb_iframe_widget
- 完成主要的畫面產出(需載入 iframe -> 較花時間)
如果把兩次 FB.XFBML.parse()
交錯在一起呢?
- (A) 找到有
fb-page
class 的元素 - (A) 透過 element.offsetWidth 取得 container width (正常值)
- (A) 為元素加上 class
fb_iframe_widget
- (B) 找到有
fb-page
class 的元素 (雖然發現已經在 parse 但由前段說明得知會再跑一次) - (B) 透過 element.offsetWidth 取得 container width
(由於已經變成
display: inline-block
,基本上會是0
) - (B) 為元素加上 class
fb_iframe_widget
- (A) 完成主要的畫面產出(需載入 iframe -> 較花時間) (container width 正常)
- (B) 完成主要的畫面產出(需載入 iframe -> 較花時間) (container width
0
)
由於最後完成的 render 的是 (B),我們 adaptive width 吃到的 container width 會是 0
,結果來看就是
無論你的 Page plugin 的外層元素寬度是多少,它都會以最小值 180px 產出畫面
最後
本來我想說單純給我們的 directive render 一個 delay 就好了,結果發現不管怎麼量,FB SDK 內的 domReady
function 之於 angular 內部的 bootstrap 總是有超過 200ms 的差距… 真心扯到爆啊~~~
最後決定,在 directive compile 階段就先把判斷 plugin widget 的關鍵 class 拔掉(e.g. fb-page
),等到 FB SDK 的自動 parse 跑完再把它加回來跑我們的 FB.XFBML.parse()
。
總之上面整個 debug + 修正的過程花了我 3 小時,而由於這次改動是為了解決遠古怪獸,對現有的 plugin directive 的 render 流程影響滿大的,造成成群的 test failure …
所以把 test 們改到好又花了我 2 小時。
欸,我以為 FB 是去小便都會被天才少年夾擊(天才 | 我 | 天才)的地方,上面那個遠古怪獸到底是 WTFFFFFFFFFFFFFFF