我正在重构我的 JavaScript 库以利用单个命名空间。我们有大约 200 个模块,它们以前将自己注册为 jQuery 插件或全局对象(不好)。在过去的分配中,为了让 Intellisense 工作,我为每个模块(我想要 Intellisense)添加了模块引用作为
/// <reference path="" />
到每个模块文件的顶部。
前一个时代的一切都是有缺陷的、脆弱的和不优雅的。
我希望在新的分配中解决这个问题。这次重构的主要目标之一是让新开发人员可以轻松地开始在库中工作,而 Intellisense 有很大的好处。
目前,我将所有 *.js 文件连接到一个 nameSpace-vsdoc.js 文件中。每个类的每个方法都使用 vsdoc 语法记录。每个模块都使用它,单个 vsdoc 参考。这工作正常,但它很笨拙。Intellisense 比以前好 300%,但仍然不够准确。它错过了很多我的 xml 文档,并且它不能很好地递归到返回稍微复杂的对象的方法/类中。
YUI Doc 提供了一种从 JsDoc 语法构建文档的方法,但这对 Intellisense 没有帮助。深入的灵魂谷歌搜索未能揭示任何第 3 方解决方案。
是否有任何工具可以以更智能的方式生成 VsDocs?
更新:
经过一些广泛的思考、测试和增量重构,我有了一个看起来像这个 jsFiddle的基本命名空间。
这使我能够在自执行函数中编写松散耦合的模块,这些模块在命名空间上注册所需的方法。所有模块都以:
/// <reference path="~/js/NameSpace-vsdoc.js" />
我使用一个简单的 Perl 脚本生成了这个 vsdoc,该脚本已附加到 VS 2010 构建事件中:
use strict;
my $dir = $ARGV[0];
my $destfile = "$dir\\js\\NameSpace-vsdoc.js";
unlink($destfile);
my $js = "";
$js .= extractFile("$dir\\js\\_first-vsdoc.js");
$js .= extractFile("$dir\\js\\NameSpace.js");
$js .= extract("$dir\\js\\modules");
#Add additional directories as needed
$js .= extractFile("$dir\\js\\_last-vsdoc.js");
open(VSDOC, "> $destfile") or die("Cannot open vsdoc file: $destfile ; $!");
print VSDOC $js;
close(VSDOC);
sub extract
{
my $ret = "";
my $path = $_[0];
opendir(JSDIR, $path) or die("Cannot open js directory: $path ; $!");
while((my $filename = readdir(JSDIR)))
{
if($filename =~ /.*\.js$/ &&
$filename !~ /-vsdoc/ &&
$filename !~ /_first/ &&
$filename !~ /_last/ &&
$filename !~ /.min\.js/)
{
$ret .= extractFile("$path\\$filename");
}
}
closedir(JSDIR);
return $ret;
}
sub extractFile
{
my $ret = "";
my $filename = $_[0];
open(JSFILE, "$filename") or die("Cannot open js file: $filename ; $!");
while((my $line = <JSFILE>))
{
if($line !~ m/-vsdoc\.js/ )
{
$ret .= $line;
}
}
close(JSFILE);
return $ret;
}
printf("Finished generating NameSpace vsdoc.\n");
_first-vsdoc.js 和 _last-vsdoc.js 文件将整个内容包装在一个自执行函数中。然后,我根据需要/适当将生成的 vsdoc 传递给 Closure Compiler、YUI Compressor 和 Uglify。
这个过程比以前工作得更好,但它仍然不是没有缺陷。
从头开始,在引用 NameSpace-vsdoc.js 的 NewModule.js 中,我得到了正确的 Intellisense:
Ns.register() //visible
Ns.controls.register() //visible
Ns.actions.register() //visible
但是,当我将 NewModule.js 定义为(并编译)时:
(function _alertClosure() {
Ns.register('alert', function alert(someText) {
///insert proper vsdoc style comment
});
}());
我没有得到适当的智能感知:
Ns.alert() //no Intellisense help
这令人困惑,因为它在子命名空间上运行良好。我被迫这样做:
Ns.alert = Ns.alert || Ns.register('alert', function ....
编译,突然(显然)智能感知按预期工作。
Intellisense 使用 jQuery 的 vsdoc(我在构建这个过程时仔细研究过)与链式方法一起工作,并且 jQuery 不会使用y.x = y.x || new x()
诡计来实现它。
所以这里是修改后的问题:从结构的角度来看,我能感觉到 jQuery 的 vsdoc 和我自己的唯一可辨别的区别是 jQuery 将整个命名空间组装在同一个闭包内。我的命名空间和我的每个模块都包装在单独的闭包中。相比之下,我的 vsdoc 看起来像是一长串自执行函数。
放弃闭包/模块模式的风险太大了;并且很难孤立地检验假设。Intellisense 在库较小且因此无法生成数千个“Javascript Intellisense Message: C:\\js\NameSpace-vsdoc.js(40:16) : Object required”错误时运行良好。
想法?