CommonJS 與 Node.js 的 server side 模組化開端
Table of Contents
前言
昨天聊完了在 CommonJS 出現前的各種模組化歷史,雖然沒提到太多細節,今天在繼續考古的過程中發現了一篇文章,Sea.js 作者玉伯 (lifesinger) 曾更簡單明瞭的提過從模組模式到 YUI3 的脈絡,有興趣深入的讀者可以再參考看看。
JavaScript 的 Server Side 模組化 (2009-2010)
一些歷史
就在 Ajax、jQuery、YUI3 等技術與工具盛行之時,網頁應用逐漸變得複雜,有一群開發者也正努力想解決當時 JavaScript 在 server side 模組化缺乏一個統一規範的問題,這得從 ServerJS 專案開始說起。
當年 Mozilla 開發者之一的 Kevin Dangoor 在 2009 年初發表了一篇《What Server Side JavaScript needs》,其中講到一些 JavaScript 尚需補足的部份:
- 缺乏標準的安裝與載入模組的語法
- 缺乏標準的模組管理系統:社群既有模組無法發佈至一個共同的 repository 中,且也沒有像 Linux 那種用 apt-get 安裝套件的方式
- server side API 在不同的執行環境中不一致:當時的 JavaScript 有多種不同的執行環境,諸如 Chrome 的 V8、Firefox 的 SpiderMonkey、Safari 的 JSCore、Java 的 Rhino 等,雖然這些執行環境在瀏覽器端的 API 有共同標準,但在檔案處理、目錄操作這類 server side 的功能卻有各自的實作
綜上所述 Kevin 發起這個稱為 ServerJS 的討論小組想要建立標準與模組化的方式,同年的 8 月時 ServerJS 更名為 CommonJS,展現也想將此標準推向瀏覽器端的野心。並在同年的 JSConf EU 上講了相關的議程。
順帶一提,Ryan Dahl 也在同一場研討會中發表了 Node.js,其中模組化的實作便是直接用上了 CommonJS,可以說反而因此讓 CommonJS 成為最廣為人知的實踐範例。
另外附上一些考古到的討論紀錄:
關於 CommonJS 與 Node.js 中的實作
講了這麼多歷史,實際來看個 Node.js 中 CommonJS 模組的範例:
從上面的這個範例,我們可以透過 module.exports
這個去輸出模組內的變數 、函式、class 等內容,並用 require
在需要的地方去載入模組。
而參考 Node.js 中 CommonJS 模組的文件,以下紀錄一些我有疑慮的注意事項。
Q. 可以用 exports
或 module.exports
來輸出內容,兩者有什麼差別?
兩種輸出方式達到的效果是一樣的,可以理解為當我們在 Node.js 建立一個模組時,Node.js 會為這個模組生成像這樣的空物件,而讓我們可以在模組中去輸出內容 (ref):
但要特別注意的是直接將輸出值指定給 exports 並不會真的改變此模組的輸出,仍會需要用 module.exports
,舉例像是這樣:
綜上所述,一般來說都還是會傾向直接用 module.exports
來輸出。
Node.js 中的 CommonJS 注意事項
require
是同步載入,也就是說在模組載入完成前,程式不會繼續執行require
會緩存載入過的模組,因此多次去載入同一個模組並不會讓這個模組被多次執行
關於 Node.js 歷史的延伸資訊
關於 Node.js 的歷史雖然很精彩,但跟此系列較無關所以這邊不會贅述,有興趣的話可以參考 Honeypot 幾個月前推出的 Node.js: The Documentary | An origin story 這個高規格製作的 Node.js 紀錄片。
不得不說 Node.js 社群與 Joyent 的 drama 真的是讓這個紀錄片變成一個節奏緊湊精采的 Netflix 電影的感覺,紀錄一些影片中會提到的部分:
- Node.js 作者 Ryan Dahl 背景與發明動機
- 二代目領導 aka NPM 作者 Isaac Schlueter 觀點
- 三代目領導 Joyent 的 TJ Fontaine 與社群之戰
- 社群版分叉 io.js 的經過
- Joyent 與社群達成共識,讓 Node.js 回歸開放
小結
今天又不小心挖得太深入,原本差點還要來寫 Node.js 的紀錄片筆記,但如上述較無關所以最後只保留了一小段,明天將會聊聊 CommonJS 社群對於走向 client side 模組標準化的意見分歧,而產生了 AMD、CMD、UMD 的百家爭鳴的故事。