踩到 ui-router 0.2.0 的 bug

其實這是一個看一看 ui-router 的 wiki,再瞄一下 source code 就可以發現的 bug ,不過由於影響不是慎大,也沒有寫在 test spec 裡,它就這樣在 0.2.0 release 接近兩個月的現在還躺在那兒。

竹林中

陰影

昨天在忙 git-source (其實也就是在忙這個 blog),觀察到一件讓我非常在意的事情。

下面是一頁我在 localhost 測試嵌入 git-source 到頁面中的截圖,這頁一開進去,歷史記錄馬上就有三筆。

怎麼可能!? 其1

緊接著,我按一次「重新整理」,變成下面這樣:

怎麼可能!? 其2

此刻,我驚覺這不是一個小問題,弄不好可能會毀掉我的 git-source 專案…

搜索

我在應用 git-source 到 ngNoob 的初期就有發現到,點進一篇文章之後幾乎就無法用「上一頁」的方式點回來,因為有大量的歷史記錄被塞給瀏覽器。當時我以為是 Tumblr 或是這個 blog theme 的問題所以不以為意,事到如今…

難道是我的 git-source 出的包!?

首先必須要找出問題的來源,於是我在 code 中埋首好一陣子,嘗試各種能夠避免出現上述情況的方法(刪改大法!);同時也去 ui-router(git-source 的關鍵 module) 那邊看看他們的 example 跟我的寫法有什麼不同(已試過如果嵌入 ui-router 的 example 是不會有同樣現象發生)。

經過了一小時,不可以說是一無所獲,但尚無法掌握決定性的觸發原因.. 基本上已經鎖定在 .config 的時候,就差臨門一腳了。

此時我腦中浮現了一個我曾經看過(但也是不以為意)的 routing behavior。

首先 ui-router 設定如下:

// inside angular app config
$stateProvider
  .state('route1', {
    url: '/route1?this&is&a&test',
    templateUrl: 'route1.html'
  });

接著當你嘗試在網址列以

#/route1?test=1&is=2&this=3&a=4

存取 route1 的時候,你會看到 URL 自動被轉換成

#/route1?this=3&is=2&a=4&test=1

這不就是增加了一次 history 嗎!

真身

經過修改 code 進行交叉比對之後,確認就是在上述的設定下會有被大量幅報 browser history 的現象,而每個內嵌的 iframe 剛好報一個。

這是 ui-router 有意要讓它發生的嗎?重重的疑惑驅始我去 trace ui-router 的 source code…

ui-router 內的 state change 觸發都是由 $state.transitionTo 負責的,而它有參數可以決定本次的 state transition 要不要 update location (即改變 URL)。

循著這個概念,我就直接往與 transitionTo 有關的地方找去,還順便去 github 上 blame 了一下…

於是我找到了關鍵的 commit

丟系哩!!!

(Bug) Demo

下面的 demo 因為牽涉到 $location ,建議開到 Plunker 去用另開視窗的模式觀看。

現象

在 發現 / 搜索 bug 過程中擔任關鍵角色的現象。

下方的 location change log 會在每次準備進行 state transition 的時候清空 (也就是 $stateChangeStart 的時候),讓我們可以清楚的觀察到 URL 改變的觸發情況。

直搗黃龍

直接使用 $state.transitionTo() 來做第三個參數代入 false 的 state transition。如果 $state.transitionTo() 真的沒有問題,理應下方的 location change log 在切換 route 時會保持空白。

後記

implied facepalm

ui-router 還是很好用啦…

然後我已經 report issue 了,只好先用 fork 來的 custom build 撐一下: