[英]Getting closure-compiler and Node.js to play nice
是否有任何項目一起使用node.js和closure-compiler(簡稱CC)?
官方的CC建議是一起編譯應用程序的所有代碼,但是當我編譯一些包含require("./MyLib.js")
簡單node.js代碼時,該行直接放入輸出中,但它沒有在這種背景下沒有任何意義。
我看到幾個選項:
我一直在使用Closure Compiler with Node來完成我尚未發布的項目。 它采用了一些工具,但它有助於捕獲許多錯誤並且具有非常短的編輯 - 重啟 - 測試周期。
首先,我使用plovr (這是我創建和維護的項目),以便一起使用Closure Compiler,Library和Templates。 我以Closure Library的樣式編寫Node代碼,因此每個文件都定義了自己的類或實用程序集合(如goog.array
)。
下一步是為要使用的Node函數創建一組externs文件。 我公開發表了一些這些內容:
https://github.com/bolinfest/node-google-closure-latitude-experiment/tree/master/externs/node/v0.4.8
雖然最終,我認為這應該是一個更加社區驅動的東西,因為有很多功能需要記錄。 (這也很煩人,因為一些Node函數有可選的中間參數而不是最后一個參數,使得類型注釋變得復雜。)我自己沒有開始這個動作,因為我們可以用Closure Complier做一些工作來減少它的尷尬(見下文)。
假設您已為Node命名空間http
創建了externs文件。 在我的系統中,我已經決定,只要我需要http
,我將通過以下方式包含它:
var http = require('http');
雖然我沒有在我的代碼中包含require()
調用。 相反,我使用Closure Compiler的output-wrapper
功能在文件的開頭添加所有require()
,在plovr中聲明,在我當前的項目中如下所示:
"output-wrapper": [
// Because the server code depends on goog.net.Cookies, which references the
// global variable "document" when instantiating goog.net.cookies, we must
// supply a dummy global object for document.
"var document = {};\n",
"var bee = require('beeline');\n",
"var crypto = require('crypto');\n",
"var fs = require('fs');\n",
"var http = require('http');\n",
"var https = require('https');\n",
"var mongodb = require('mongodb');\n",
"var nodePath = require('path');\n",
"var nodeUrl = require('url');\n",
"var querystring = require('querystring');\n",
"var SocketIo = require('socket.io');\n",
"%output%"
],
這樣,我的庫代碼從不調用Node的require()
,但編譯器容忍在我的代碼中使用http
這樣的東西,因為編譯器將它們識別為externs。 由於它們不是真正的外部因素,因此必須按照我的描述進行。
最后,在討論列表中討論了這個之后,我認為更好的解決方案是為命名空間創建一個類型的新類型注釋:
goog.scope(function() {
/** @type {~NodeHttpNamesapce} */
var http = require('http');
// Use http throughout.
});
在這種情況下,externs文件將定義NodeHttpNamespace
,以便Closure Compiler能夠使用externs文件對其進行類型檢查。 這里的不同之處在於,無論您想要什么,都可以將require()
的返回值命名為,因為http
的類型將是這種特殊的命名空間類型。 (為$
確定一個“jQuery名稱空間”是一個類似的問題。)這種方法將不再需要為Node命名空間命名本地變量,並且不需要在plovr配置中使用那個巨大的output-wrapper
。
但這是一個題外話......一旦我按照上面所述設置了東西,我就有了一個shell腳本:
RAW
模式下構建所有內容。 node
。 使用RAW
模式會導致所有文件的大量連接(盡管它還負責將Soy模板甚至CoffeeScript轉換為JavaScript)。 不可否認,這使得調試變得很痛苦,因為行號是無稽之談,但到目前為止我一直運作良好。 Closure Compiler執行的所有檢查都使它值得。
閉包編譯器的svn HEAD似乎支持AMD
我用一種更簡單的方法取代了我的舊方法:
新的方法
有趣的是,我甚至不必為require()
調用添加extern。 Google Closure編譯器自動理解這一點。 我確實必須為我使用的nodejs模塊添加externs。
老方法
根據OP的要求,我將詳細闡述使用Google Closure Compiler編譯node.js代碼的方法。
我受到了bolinfest解決問題的方式的啟發,我的解決方案使用了同樣的原則。
不同之處在於我創建了一個執行所有操作的node.js腳本,包括內聯模塊(bolinfest的解決方案讓GCC負責處理)。
這使它更加自動化,但也更脆弱。
我剛剛為編譯服務器代碼的每一步添加了代碼注釋。
看到這個提交:
https :
//github.com/blaise-io/xssnake/commit/da52219567b3941f13b8d94e36f743b0cbef44a3
總結一下:
require()
調用,包括賦值部分。
var Server = require('./lib/server.js');
require()
調用,所以我遞歸地重復步驟3和4,直到所有的
require()
調用都消失了,我留下了一個包含所有代碼的巨大字符串。
require
調用已編譯的代碼。
預編譯代碼。
所有
require
呼叫都被刪除。
我的所有代碼都被夷為平地。
http://pastebin.com/eC2rVMiN
編譯后的代碼。
Node.js核心
require
手動預先調用。
http://pastebin.com/uB8CaejN
為什么你不應該這樣做:
require
調用,內聯和刪除
module.exports
。
為什么你應該:
Node.js上的Closure Library在60秒內完成。
它受支持,請訪問https://code.google.com/p/closure-library/wiki/NodeJS 。
選項4:不要使用閉包編譯器。
節點社區中的人不傾向於使用它。 你不需要縮小node.js源代碼,這很愚蠢。
對縮小沒有好處。
至於關閉的性能優勢,我個人懷疑它實際上使您的程序更快。
當然還有成本,調試編譯的JavaScript是一場噩夢
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.