編者按:本文作者為 Soledad Penadés, Sole 在 Mozilla 的 Tech Evangelism 團(tuán)隊(duì)工作,幫助人們?cè)诰W(wǎng)絡(luò)上創(chuàng)造神奇的東西。本文主要介紹 node-firefox 的基本知識(shí),以及它如何幫助你加速 Firefox OS 應(yīng)用開發(fā),由 OneAPM 工程師編譯呈現(xiàn)。
在 Mozilla 基金會(huì),我們一直致力于尋找簡化開發(fā)人員生活的方法。當(dāng)胸懷抱負(fù)的應(yīng)用開發(fā)者告訴我們初學(xué)開放式 Web 應(yīng)用很麻煩時(shí),我們便致力于將應(yīng)用管理器轉(zhuǎn)變?yōu)閷?duì)更多初學(xué)者友好的環(huán)境,反過來也給 WebIDE 讓路。該工具簡化了許多曾經(jīng)緩慢而繁瑣的行為,比如創(chuàng)建新的應(yīng)用、下載和安裝模擬器或運(yùn)行和調(diào)試應(yīng)用。
但仍有部分開發(fā)者感覺受冷落了:計(jì)算機(jī)高手!他們已經(jīng)具備了基于 node.js 的構(gòu)建工具鏈,任務(wù)包括資產(chǎn)優(yōu)化、代碼提示、或測(cè)試運(yùn)行等。他們也經(jīng)常使用像 Browserify 這樣的工具,或許甚至都不編寫 JavaScript 代碼,相反,卻傾向于選擇 CoffeeScript 這樣的語言。不過,所有這些好東西都要求你先構(gòu)建應(yīng)用或網(wǎng)站,之后才能將其用于你的設(shè)備或?yàn)g覽器中。
本來,我們想讓這些開發(fā)人員離開自己心愛的命令行(或編輯快捷鍵?。┺D(zhuǎn)而使用 WebIDE,通過單擊按鈕來部署應(yīng)用,然后再回到他們喜歡的編輯器。但是,他們卻一致回答:我們不喜歡點(diǎn)擊!我們喜歡終端!
如何使 WebIDE 更加高效?
大家不喜歡 WebIDE,因?yàn)樗馕吨舷挛牟粩嘧兓?。它并不高效,我們是工程師,如果工程師喜歡一件事的程度超過構(gòu)建新的應(yīng)用,那它就很可能是優(yōu)化并簡化流程。
既然我們已經(jīng)有了構(gòu)建腳本,只剩下一個(gè)步驟——部署,就能讓我們的應(yīng)用投入運(yùn)行時(shí),這也是我們使用 WebIDE 的目的。所以,顯而易見問題將是:我們能利用 WebIDE 進(jìn)行部署嗎?以編程的方式?
服務(wù)器與 actors
每一個(gè) Firefox 運(yùn)行時(shí)都有所謂的遠(yuǎn)程調(diào)試服務(wù)器。由于一些明顯的安全原因,默認(rèn)并不啟用該服務(wù)器,但是當(dāng)啟用時(shí),客戶端可與其連接并利用它的各種功能優(yōu)勢(shì),比如安裝應(yīng)用、訪問控制臺(tái)等。這就是 WebIDE 內(nèi)部所做的事情。
每個(gè)功能都由一個(gè) actor 提供。例如,假設(shè)我們想要列出已安裝的應(yīng)用,那么可以……
首先,找到
webAppsactor然后運(yùn)行
getAll命令再然后,得到回應(yīng)的應(yīng)用列表
還有一個(gè)例子是安裝打包的應(yīng)用,步驟為:
首先,使用任何庫或任何你喜歡的方式壓縮應(yīng)用內(nèi)容
然后得到
webAppsactor用壓縮文件內(nèi)容調(diào)用
webApps actor中的uploadPackage命令調(diào)用結(jié)果即為
Fileactor用返回值
Fileactor 調(diào)用webAppsactor 中的install命令完成!
因此,安裝應(yīng)用的魔法不在 WebIDE ,而是在服務(wù)器中!我們可以以編程方式利用這類魔法,但是從頭構(gòu)建一個(gè)客戶端,建立 TCP 連接并語法解析包,并不是你真正想做的:相反,你想做的是編寫應(yīng)用并將其推到設(shè)備中運(yùn)行。
不用絕望,因?yàn)?node-firefox 能幫你實(shí)現(xiàn)這一目標(biāo)。它不是一串整體的代碼,而是一系列 node.js 模塊,每個(gè)模塊執(zhí)行不同的任務(wù),托管在各自的代碼庫中,并發(fā)布于 npm 注冊(cè)表中。只要你需要,你可以在腳本或任務(wù)運(yùn)行器中盡情使用這些模塊,因此,你終于不用離開命令行就能構(gòu)建并運(yùn)行應(yīng)用了。
行動(dòng)是金,雄辯是銀
說了這么多,現(xiàn)在讓我們看看如何編寫一個(gè)能啟動(dòng)模擬器的腳本吧!
首先使用 npm 指令在項(xiàng)目中安裝模塊:
npm install --save node-firefox-start-simulator
下面是寫好的腳本:
var startSimulator = require('node-firefox-start-simulator');
startSimulator({ version: '2.2' })
.then(function(simulator) {
console.log('Listening in port', simulator.port);
});
好啦!只需幾行代碼,你就能以編程方式啟動(dòng)2.2版本的模擬器。如果你不關(guān)心版本問題,就不要在startSimulator中傳入任何參數(shù),這樣就將啟動(dòng)所發(fā)現(xiàn)的第一個(gè)模擬器:
startSimulator().then(function(simulator) {
// your code
});
我們還可以通過動(dòng)圖查看這個(gè)過程。下圖就顯示了通過 node.js 腳本啟動(dòng)模擬器、安裝應(yīng)用和運(yùn)行應(yīng)用的所有過程:

該示例使用的代碼實(shí)際上就是 node-firefox-unistall-app的代表范例。每個(gè)node-firefox模塊都含有一個(gè)示例文件夾,幫助你快速入門。
如我們開始所提到的,許多轉(zhuǎn)向應(yīng)用開發(fā)的網(wǎng)頁開發(fā)者想繼續(xù)使用任務(wù)運(yùn)行器,因此我們也就如何使用帶gulp的node-firefox寫了一個(gè)示例。
讓我們運(yùn)行這個(gè)default-one任務(wù)。這樣會(huì)啟動(dòng)模擬器、部署應(yīng)用,再多點(diǎn)挑戰(zhàn),還能持續(xù)關(guān)注 CSS 變化。如果你編輯并保存了任何一個(gè)應(yīng)用的樣式表,文件監(jiān)視器會(huì)檢測(cè)其變化并發(fā)送新的文件內(nèi)容到運(yùn)行時(shí),這樣不用關(guān)閉、推進(jìn)并重新啟動(dòng)整個(gè)應(yīng)用就可迅速替換樣式表。下面的例子將背景顏色從穩(wěn)重的深藍(lán)色改變成永恒不變的 Paul Rouget 粉紅色!

實(shí)時(shí) CSS 重載很適合搭建與試驗(yàn) UI 界面。不必重載應(yīng)用并導(dǎo)航到你想工作的具體部分,這樣可以節(jié)省大量時(shí)間——要是當(dāng)年筆者在編程安卓應(yīng)用時(shí)也能用這個(gè)就好了。
但是我們還可以做得更好。default-all任務(wù)和default-one的功能相同,但前者是針對(duì)系統(tǒng)安裝的所有模擬器,因此你能同時(shí)看到所有模擬器的 CSS 改變效果:

不幸的是,模擬器2.1和2.2中存在一個(gè)問題,它們不能重載樣式表的變化,但這個(gè)問題已經(jīng)存檔并會(huì)到解決。
目前我們能做什么?
當(dāng)前這套模塊可幫助你找到運(yùn)行時(shí)在監(jiān)聽的端口,找到并啟動(dòng)模擬器;連接到運(yùn)行時(shí);找到、安裝、卸載并運(yùn)行應(yīng)用,重載樣式表。
基本原理
你或許已經(jīng)注意到一個(gè)模式,但是以防還不夠明顯,我們正在努力編寫一些簡單的模塊。每個(gè)模塊應(yīng)僅執(zhí)行一個(gè)動(dòng)作,返回一個(gè) Promise 并盡量減少使用依賴。
小的模塊很易理解、使用并進(jìn)行測(cè)試。同樣,將來大多數(shù) Web API 的設(shè)計(jì)目的都是服務(wù)于 Promises ,我們想編寫的代碼應(yīng)著眼于未來而不是過去。此外,減少使用依賴的數(shù)量也可使新手更易熟悉模塊,因?yàn)橐私獾牟皇煜さ男略馗倭恕?/p>
最后,由于所有模塊的工作方式都相同,所有當(dāng)你知道如何使用一個(gè)模塊后,你就知道了如何使用剩下的——唯一變化的就是參數(shù)和結(jié)果。
理想想法(關(guān)于我們目前還無法做到的)
有很多事情我們想知道將來能否實(shí)現(xiàn),有些人稱之為特色,但我們稱之為‘理想想法’。
一個(gè)經(jīng)常出現(xiàn)的例子即 WebCLI:與 WebIDE 相對(duì)應(yīng),你通過 WebIDE 所做的所有事情都可以通過一個(gè)命令行工具來實(shí)現(xiàn)。筆者不斷糾結(jié)于這兩個(gè)觀點(diǎn)——“這想法很棒”和“或許我們根本不需要這個(gè),有一個(gè)任務(wù)庫就足夠了”,不過大家似乎比較喜歡這個(gè)想法,所以應(yīng)該沒那么差!
還有一個(gè)很棒的特色是遇到從命令行運(yùn)行卻崩潰的應(yīng)用,可以使用 DevTools 調(diào)試程序。通過命令行運(yùn)行應(yīng)用的想法很好,但是命令行調(diào)試程序卻沒那么給力!為什么不選擇一個(gè)兩全其美的方法呢?
或者,用命令行控制任何瀏覽器都可以干凈利索,只要通過 Valence 將二者相聯(lián)系!
最后是筆者最鐘愛的夢(mèng)想想法:Firefox OS 定制版。想象一下,如果我們僅僅編寫一個(gè)腳本就能創(chuàng)建一個(gè)空白 Firefox OS 平板,裝上我們鐘愛的應(yīng)用和設(shè)置,生成整體的 Firefox OS 圖像,那么之后我們便可將其閃存到設(shè)備上。由于這不是一個(gè)二進(jìn)制大對(duì)象而只是一個(gè)腳本,所以我們僅可在其函數(shù)庫中進(jìn)行發(fā)布,其他人可根據(jù)版本合成或創(chuàng)建他們自己的 Firefox OS。
如何實(shí)現(xiàn)呢?
我們面臨的問題還有很多,需要很多領(lǐng)域的協(xié)作。或許最緊急的任務(wù)是獲取更好的多平臺(tái)支持。目前,我們只能通過網(wǎng)絡(luò)與運(yùn)行時(shí)進(jìn)行交互,而不是實(shí)際的設(shè)備。另外,除了 Mac OS,對(duì)平臺(tái)的支持還極度缺乏。
另一個(gè)重要方面是測(cè)試。如果我們更早、更多、更頻繁地進(jìn)行測(cè)試,將能檢測(cè)到像 CSS bug 這樣的問題,這個(gè)問題是筆者在創(chuàng)建gulp 演示程序時(shí)偶然發(fā)現(xiàn)的。我們想在幾個(gè)平臺(tái)上運(yùn)行這些模塊,并讓這些模塊連接到其他不同的平臺(tái),包括實(shí)際的設(shè)備。
當(dāng)然我們需要更多模塊和更多范例!為了保證兩個(gè)人不會(huì)編寫同一個(gè)模塊,我們討論在高級(jí)項(xiàng)目問題跟蹤器中提出新模塊。我們非常期待見到更多的范例,或者更好的范例——使用我們的代碼將現(xiàn)有功能鉤嵌到其他節(jié)點(diǎn)模塊中。例如,可通過 firefox-app-validator-manifest模塊添加清單驗(yàn)證。
還有,我們一如既往的需要你們。我們不是你們,因此我們不知道你們的需要和想法。當(dāng)然,我們也不能像你們一樣使用軟件。我們需要你的輸入信息,還需要你們的貢獻(xiàn)!
我們期待你們使用 node-firefox 創(chuàng)建的成果。如果遇到任何問題,請(qǐng)將問題整理成文檔發(fā)給我們,或者在 irc 跟我們說。我們會(huì)在 irc.mozilla.org 中的 #apps 和 #devtools 頻道解疑答惑。
致謝
這里要不感謝 Nicola Greco 就太不厚道了, 去年夏天筆者指導(dǎo)過他,當(dāng)時(shí)他還在 Mozilla 實(shí)習(xí)。是他提出了構(gòu)建個(gè)人節(jié)點(diǎn)模塊的初步設(shè)想,這種模塊會(huì)幫助你開發(fā) Firefox OS 應(yīng)用。去看一下他的實(shí)習(xí)總結(jié)報(bào)告吧,真的的非常有趣且具有說明性!
非常感謝所有(極其耐心的) DevToolers:Ryan Stinnet、Alexandre Poirot、Jeff Griffiths 和 Dave Camp,他們幫助我們找到遠(yuǎn)程服務(wù)器的方向,actors 等等。尤其感謝 Heather Arthur,他編寫了 firefox-client,使得編寫node-firefox的方式比原來更簡便舒適。
OneAPM 是應(yīng)用性能管理領(lǐng)域的新興領(lǐng)軍企業(yè),能幫助企業(yè)用戶和開發(fā)者輕松實(shí)現(xiàn):緩慢的程序代碼和 SQL 語句的實(shí)時(shí)抓取。想閱讀更多技術(shù)文章,請(qǐng)?jiān)L問 OneAPM 官方博客。