(English Version available here)
用兩周多的時間,路路續續把原本用 Coffeescript 撰寫的 Hubot 聊天機器人框架移植成使用到 ES6 特性的純 Javascript 版本。 現在這個移植版本已經可供使用。移植後依然可以使用 Hubot 原來以 Coffeescript 撰寫的各種擴充套件 (Plugins) 。 https://github.com/gasolin/webbybot (目前的版本完全移植 Hubot 的功能,已開 Issue 詢問 Hubot 是否有興趣 merge 回去,在此之前先放在自己的 webbybot repo 裡) 移植的動機之一是為了了解整個聊天機器人框架,為後續可能的修改打基礎。 其二則是嘗試平常不常用到的 ES6 新特性。 過去 Coffeescript 和 Typescript 等最終編譯成 Javascript 執行的語言,都走在 Javascript 之前,提供了許多語法上的新特性。但在 2015 年 Javascript 開始的新發佈規劃 (一年一版) 下,ES6 (ES2015) 已將 Coffescript 眾多特性都收編了。且現在透過 Babel 可以將 ES6 編譯成現有的 Javascript 直譯器能讀懂的語法。在這樣的趨勢下,過去開發者想為這些新特性多學一套語言的誘因就不再存在了。 移植過程中採用的作法與遇到了一些坑,在此一一列出來。 1. 不用 grunt gulp, 直接使用 npm script 在 package.json 裡可以直接在 "script" 屬性中定義一些要執行的腳本,例如 webbybot 透過 "npm run build" 來將 ES6 轉換成 Javascript 直譯器能讀懂的語法。用 “npm run lint" 來做 style check。 2. 不用 webpack, 直接使用 babel 移植之初決定使用 webpack 的 babel loader 來轉換 ES6,但這是一連串從「錯誤中學習」的開始。 webpack 支援使用 require 命令載入各種檔案,而且 webpack 在轉換的過程中會將檔案打包成一份。但後端程式其實不太需要打包,而且 Hubot 作為一個框架,執行後從外部讀取 Plugin 是非常重要的功能。 使用 webpack 時,它會將程式中出現的 require 都視為它的 require,而嘗試從打包好的檔案中找到我們需要的外部 plugin,結果是徒勞的。當我們換用 npm script 直接呼叫 babel-cli 來打包,原來使用 webpack 時出現的諸多問題也都一併解決了。 3. 該不該 return 在移植的過程中常用到的工具是 Coffeescript 官網的 "Try Coffeescript" 分頁。可以即時將 Coffeescript 結果轉換成 Javascript。 但是真的把程式碼貼上去會發現, Coffeescript 所轉出來的 Javascript 所有的函式都會回傳值。需要手工一個個確認。 4. test cases Hubot 本身有很完整的單元測試。所以每移植一支程式碼時,只要一併移植對應的單元測試,就可以捉對拿來直接測試。單元測試移植時出現最多該不該 return 的問題。 5. class and super Hubot 使用了很多 Coffeescript 的 Class 語法。Class 與 super 的用法在 MDN 上可以找到相關教學。 6. Default + Rest + Spread Hubot 程式碼裡常常會出現諸如 reply (strings...) 的語法。Coffeescript 裡的 "strings..." 可以對應到 ES6 的 "...strings"(... 放置位置剛好相反)。 "...strings" 代表的是一個陣列。在程式中有時要展開有時不用,其實頗令人苦惱。7. 使用 for..of 替換 for.. in 迴圈 碰到 for..in 迴圈有幾種解法,最不會出錯的是將 Array iteration 改寫成 forEach。但是用 forEach ˇ的話無法在執行中使用 break/return 跳出是其缺點。其二是在 for..in 迴圈裡加入 hasOwnProperty 確認不會跑到無關的 function。 在 Webbybot 的第二版中已使用 ES6 支援的 for..of 迴圈 來取代 forEach 和 for..in 迴圈。由於 for..of 迴圈只支援 iteratable ,不支援一般 Object,所以碰到要對 Object 跑迴圈時可以在 Object 外包一層 Object.keys,例如 `for (let item of Object.keys (TargetObj)) {...} 8. 使用 Object.assign 替換 Extend
要擴展一個物件的功能不用再用 lodash 或是自己寫 extend 函式,直接用 Object.assign 吧。
以上是移植過程中碰上的問題。感謝同事 Ray Lin 一起幫忙完成這次的移植。
現在 Webbybot (Hubot ES6 port) 整套都可以用 Javascript 寫了,歡迎試用或上 Patch 喔。