[英]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.