2012年6月17日 星期日

GWT 的 Super Dev Mode 是怎麼運作的?

原文網址:http://tbroyer.posterous.com/how-does-gwts-super-dev-mode-work

GWT 的 Super Dev Mode(別名:Super Draft Mode)一個月前第一次 tease,然後持續發展到上個禮拜正式 land,for your testing pleasure.(譯註:翻譯不能 Orz)

這個 Dev Mode 強化了哪些東西?

在回答這個問題前,讓我們先回頭了解一下 Dev Mode 的構造,它是由 browser plugin 與 code server 所組成、用 TCP 的 socket 彼此溝通以在 JVM 中執行你的 GWT 碼然後跟 browser 互動(以及執行 JSNI),而不用先跑一次漫長的 compile 過程。GWT 的 Dev Mode 也可以(額外)嵌入一個 servlet container(預設是 Jetty 6,也可以用其他的),所以它可以執行 server 端的程式碼。在 GWT 開發指南中可以找到這張圖:
Dev Mode 其中一個優點是在 JVM 中執行你的 client 端程式碼,你可以使用標準的 Java debugger,有 breakpoint、可以觀察變數......等等。此外,server 端的程式碼也在同一個 JVM 上頭執行,就更容易 debug(不過只適用於小程式)。缺點就是需要一個 browser plugin(它得在 UI thread 中阻斷 JS 的執行,但是同步的 XMLHttpRequest 沒辦法提供夠好的效能、Dev Mode 又很聒噪地一直發,更不用說同步的 XHR 將要被淘汰了。)

需要一個 browser plugin 會導致很多問題:
  • 每個 browser 有它自己的 API(至少對 Dev Mode 而言,需要 branch into JS 引擎、以及提供一個設定畫面),這表示你必須對每個 browser、每個平台維護一個 plugin。這是為甚麼只有 IE(顯然僅限 Windows)、Firefox(所有平台)、Chrome(所有平台)、Safari(僅限 Mac)上有 plugin,而 Windows 上的 Opera、Safari 沒有,更不用說 mobile browser 了。
  • 你需要執行一個 plugin,這在 Web Worker 中辦不到的、對 browser extension 來說是個挑戰(如果要全部通用的話),在 mobile browser 上仍就不可能。
  • Firefox 每次有新版本時,plugin 也必須更新,因為它是 binary 的 extension;Gecko SDK 也會在每次更新時改變。這在去年 Mozilla 轉變成 rapid release process 時變成問題。雖然從二月導入 ESR 之後有所緩解,但仍無法在 Beta、Aurora(甚至 Nightly)版本的 Firefox 中使用 Dev Mode;and sticking to the ESR (which is not the case) would make it impossible to use bleeding edge feature in Dev Mode. (譯註:翻譯不能 Orz)
  • Dev Mode 需要某些 browser API,但並不總是能滿足需求:在 Chrome 中偶爾會爛掉,GWT Team 則建議使用其他 browser
一言以蔽之,維護 Dev Mode 已經變成一場惡夢:plugin 必須每六週更新一次;開發者在 Firefox 更新但是新版 Dev Mode 還沒出來前會抓狂;而 Chrome 很難使用,因為它的行為不穩定也不可遇測;在 Safari 也有相同問題,而支援 IE9 方面上也需要作一些調整

邁向 Super Dev Mode

過去幾年,Google 一直努力於他們 Closure Tool 的其中一部分,設法能 debug compile 後的 JavaScript(最初是用 Closure Compiler 產生)——如果原本的程式碼是你寫的。他們最初以 Firebug 的 extension 方式寫了一個 Closure Inspector;隨著 compiled-to-JS 語言(像是 CoffeeScript)的興起,他們提煉成果、並開始與 Mozilla 合作制定一個現在稱為 Source Maps 的規格:這是一個不管原始語言是什麼,都可以從 compile 後的 JS 對應回原始的程式碼。Closure Inspector 沒有再維護了(也無法在最新版的 Firefox 與 Firebug 上運作),但是 Chrome 現在內建、Mozilla 也開始積極改善他們新的 developer tool,將會有這個功能。Safari、Opera 與 IE 支援這個功能也是遲早的問題(Opera Dragonfly 是 open source,如果你想貢獻 Source Maps 的支援度,快去吧!)

在 Mobile browser 上也會擁有遠端 debug 的功能,幾乎所有瀏覽器都有:Android 版 ChromeFirefox快了)、Opera早就有了)、Safari(雖然只有在 iOS 模擬器上,不過有用 UIWebViews 的 application 也行)。

結合這些功能,你就會有一個不用 plugin 的 Dev Mode 代替品,那就是 Super Dev Mode 啦。

所以,怎麼運作的?

Super Dev Mode 用另一種實作方式來取代 Dev Mode 中的 code server,它仍然會提供程式碼給 browser,但是將你的 Java 程式碼 compile 成沒有最佳化的 JavaScript(又名 draft,也叫做 Super Draft Code)。

現在,你可以在任意的 HTTP server(包含 Dev Mode)上執行你的 application,因為 Super Dev Mode 跟 Dev Mode 不同,就只是個 code server。這表示必須 compile 一次你的 application(如果用 Dev Mode 當 HTTP server 就可以不用)。在確認穩定之前,你必須自己設定 devModeRedirectEnabled 這個屬性為 true,讓 compile 時能啟動 Super Dev Mode。Super Dev Mode 也需要使用 xsiframe 這個 linker,所以你需要把下面這兩行加到 GWT module 中(記得在產出 production 時拿掉第二行)。
<add-linker name="xsiframe" />
<set-configuration-property name="devModeRedirectEnabled" value="true" />

在載入你的 application 之後,啟動 Super Dev Mode 就只需要點一個 bookmarklet。這個 bookmarklet 會 inject 一段 script 到頁面中,從 code server 讀取資料、列出哪些 GWT module 已經被載入、並問你要 debug 哪一個?然後它會抓取 browser 的 deferred-binding 值,向 code server 要求 compile 相關的 permutation,接著重新載入頁面來使用(有些資料存在 browser 的 session 儲存區中,並且在載入時觸發 script 的 injection 以從 code server 載入 application 而不是從 HTTP server)。因為 compile 是彈性的,它只會發出單一 permutation,compile 過程會在 10 秒內完成... 至少是以此為目標(有些 generator 還沒有更新到能享有 incremental generation 的好處,會拖慢 Super Dev Mode)。

你可以在 Chrome Developer Tools 中看到你的 Java code,然後你可以設定中斷點、觀察變數......等等,就跟你在 Java IDE 選擇對一個 Java application 作 debug 一樣,只不過你是在 browser 上頭 debug JS。還有一個優點是 Dev Mode 絕對沒有的,就是你可以跳進 JSNI method、然後觀察裡頭的變數。如果你的 browser 不支援 Source Maps,JavaScript 會以 -style PRETTY 的方式 compile,所以會相對好讀許多;不過還是用 Source Maps 比較優(就像用 Source Maps 來 debug CoffeeScript 會比較好一樣)。

你可以改變你的 code(在 Vim 或 Eclipse),當你覺得可以測試時,不用像之前 Dev Mode 一樣 reload 頁面,而是再按一次 bookmarklet。

要關閉 Super Dev Mode,有另一個 bookmarklet 可以清除 session 然後 reload 頁面,compile 過的 application 就會載入。

當存取 code server 的 web 介面時(預設是 http://localhost:9876),bookmarklets 就會出現,直接把它們拖曳到你的書籤列中。

總結來說,Super Dev Mode 載入一個有彈性的 GWT compiler,有一個 endpoint 會儘快地以 on-the-fly 的方式重新 compile 一個 permutation,然後提供這些檔案以及相關的 Source Maps 與 Java source 檔案。

限制與安全性

技術上來說,目前 compile 需要用 JSONP 來觸發,因為得繞過 Same Origin Policy。我們一直在討論要改用 CORS,它的優點是允許將 application 的 origins 加到白名單上(當你忘記把你的 application 加到白名單上、或是忘記啟動 code server,client-side 的error-detection 會發出警告)。

Super Dev Mode 每次會在新的目錄下 compile 你的 application,所以 server-side 的 code 不會有 .gwt.rpc 檔,直到你把它們複製到 war 目錄下、或是改寫 loadSerializationPolicy 去搜尋你的 Super Dev Mode app space(雖然我很懷疑能否在 App Engine 中使用)。用 RequestFactory 應該不會有什麼問題。

接下來呢?

Super Dev Mode 仍然是一個比實驗階段還實驗階段的功能,現在還不要期望太多。非常歡迎妳們的回饋意見,無論是以錯誤回報的方式,還是在論壇中提出建議。Super Dev Mode 會包含在 GWT 2.5 中,然後 deploy 到 Central Repository(給 Maven、Gradle、Ivy 等使用者)。

期待在 2.5 版發佈之後,Super Dev Mode(如同其他 GWT 中的改變)會有更多改善 :-)

沒有留言:

張貼留言