題記:

各位開發者好,我是白鷺引擎技術負責人王澤,從2019年開始我會不定期(一般是兩周)更新一些與白鷺引擎的開發迭代有關的思考或者趣事,希望大家喜歡這個專題系列。

Egret Pro 原計劃在今天(2019年3月1日)正式發布,可惜事與願違,由於在產品發布前最終測試階段發現了一些問題,我決定將最終發布日期推遲三個工作日,改在下週三(2019年3月6日)發布。

雖然這次發布跳票了,但是這並不影響我提前為各位開發者介紹一下 Egret Pro 的一些新特性。在 Egret Pro 的諸多新特性中,其中一項是包含了一個可以提升20倍編譯速度的編譯器。在本週一 Egret Pro 的首次對外宣佈時,很多開發者都對我們宣稱的20倍編譯速度提升很感興趣,今天我向大家介紹一下我們為此做的工作以及其背後原理。

首先,我們需要了解為什麼在重度項目中原來的編譯速度很慢,讓我們分析如下代碼:

如果您在項目中編寫了行如上述邏輯的兩個類,就會遇到一個問題是:必須首先載入 a.ts ,再載入 b.ts ,反之如果先載入 b.ts,此時 class A 是不存在的,進而導致載入報錯。但是各位開發者您可能從來沒有注意過這個問題,因為您使用白鷺引擎時,載入順序似乎永遠是正確的(當然也偶爾遇到一些邊角問題導致順序錯誤)。

這個問題是早期JavaScript語言的一大問題,由於JavaScript在載入後是立即執行的,又因為瀏覽器環境下腳本載入是非同步的,導致語言層面無法實現一個簡單的需求:在運行 b.ts 之前把他依賴的其他腳本提前載入進來。當然這也不能過分責怪JavaScript的作者,畢竟20多年前,他只是想為瀏覽器設計一種「可以做一些簡單的數值驗證和小動畫的簡單腳本」,根本沒想到現在已經有人會用瀏覽器「裝備回收,點擊就送」。

為瞭解決這個問題,業界在21世紀的前十年湧現了很多由社區驅動的解決方案,比如適用於NodeJS的commonjs和適用於瀏覽器的amd模塊系統等。

白鷺引擎在2014年設計時,沒有採用amd模塊系統,主要原因是這種系統的編寫方式過於複雜,對開發者並不友好,又因為白鷺引擎自身採用TypeScript,用戶邏輯的類型系統更為完備,所以我們自主開發了一種獨特的機制用於解決文件的依賴順序問題:當您使用白鷺引擎並執行egret build時,您會發現白鷺引擎編譯器會自動在項目根目錄下生成一個名為 manifest.json的配置文件,其結構大致如下:

當您觀察game欄位後,會發現這裡面的依賴順序一定是正確的,也就是說,當您執行egret build的時候,引擎內部分析您的項目代碼,生成了一份正確的依賴關係,並根據這份依賴關係來決定代碼的載入順序。這個功能使得開發者無需關心代碼的依賴順序,為開發者節省了很多用在檢查代碼依賴順序的時間(我在2013年開發白鷺引擎之前做HTML5遊戲的時候沒少因為這個問題各種坑) 。但是不幸的是,正是因為這個功能,導致了遊戲編譯速度在大型項目中比較緩慢,特別是在Windows筆記本設備中。

解決這個問題的關鍵在於,有沒有更好的方式去分析JavaScript(或者TypeScript) 的代碼依賴順序。在2014年白鷺引擎剛開發的時候答案是「沒有」,但是現在情況已經不一樣了,我們有了新的語法標準:ECMAScript 2015 Modules, 以及一個強大的社區驅動的工具:webpack。

還是上述用來描述 a.ts 和 b.ts 的代碼,我們將其改用ES2015的實現:

如果您將上述代碼放在一個現代瀏覽器(比如Chrome)中,會發現即使只載入 b.js,他也會在執行前優先去載入 a.js,為了實現該功能,您需要修改兩處邏輯:

1、在 a.js 中將一個類標記為exports;

2、在 b.js 中在使用 A 之前添加一句import。

當然,上述代碼在TypeScript中也是完全一樣的,畢竟TypeScript是JavaScript的超集。

雖然上述代碼在現代瀏覽器上可以順利執行,但是開發一款HTML5遊戲必須考慮瀏覽器兼容性問題(從2018年開始還需要額外再考慮一下「小遊戲平臺兼容性問題」),所以這種寫法肯定是不能直接運行在全部設備上,好在我們還有一個名為webpack的工具,他可以幫助我們將上述代碼編譯成一個可以運行在所有瀏覽器中的單一文件。

當採用了ES2015+webpack後,白鷺引擎編譯器再也不需要計算依賴,只需要專註的執行TypeScript到JavaScript的代碼編譯即可,剔除這個步驟,再加上一些其他方面的零敲碎打的優化,編譯性能就得到了20倍的提升。

在這個過程中有一些事項需要和開發者說明:

首先,經過我們的測試,這項優化是在越大的項目提升越明顯,小型項目的提升只有兩三倍,而我們目前支持的正在開發中的重度遊戲(450個TypeScript文件,8萬行代碼,編譯後體積 1.5mb)提升有20倍,我們預計這個項目在正式完成上線後,隨著代碼量繼續膨脹,提升會更為明顯。

其次,開發者會發現,採用新方式會要求您修改現有所有代碼,為其添加import與 export,這可能對您的項目是一個巨大的工作量。好在我們為此開發了一個腳本,可以為您的項目自動添加import和export, 由於這個腳本是為我們作為對比參照的重度遊戲項目定製開發的,所以很難適配所有情況,這意味著我們無法實現將所有白鷺引擎製作的項目「一鍵升級」到新的方式,但是如果您希望在持續維護的項目中使用這項功能的話,我們可以有針對性的根據您的項目開發定製升級腳本(這將作為白鷺團隊引擎重度遊戲解決方案的一部分),如果您擔心風險過大,我們推薦您在新項目或者尚未上線的項目中使用 Egret Pro 的新編譯器。

再次,由於webpack本身配置量非常複雜,以及webpack每個大版本都有非常恐怖的不向下兼容的改動,再加上白鷺引擎團隊定製修改了TypeScript編譯器等諸多原因,雖然EgretPro的底層採用了webpack,但是我們不會將其暴露給開發者,所有的webpack配置都是按照白鷺引擎的規範硬編碼在編譯器中,暫不允許開發者自由擴展。

最後,import 語法在最新的 VSCode 中是可以自動生成的,開發者無需擔心新的編寫方式需要額外手工編寫許多import代碼,所以我們建議開發者使用 VSCode 編寫遊戲邏輯,並在白鷺新推出的Egret UI Editor或者Egret Wing中編輯皮膚。

以上就是 Egret Pro 帶來的20倍編譯速度提升背後的技術原理,Egret Pro將於下週三發布,感謝各位開發者一如既往對白鷺引擎的支持,幫助開發者提升開發效率是白鷺引擎團隊一如既往的使命。我們非常有自信這一次的編譯速度提升可以每天為您至少節省一個小時,把更多的時間用在有創造性的工作以及陪伴家人與朋友上。


推薦閱讀:
相關文章