主页 > 知识库 > 网络编程 > 其他 >

使用Node.js编写Shell脚本,暨Jscex 0.6.5版本发布

来源:网络 作者:老赵 发表于:2012-07-02 08:34  点击:
昨天不得不花时间做了点保护博客阅读体验的事情,但其实这篇才是我真正想写的。上个星期在香港出差,晚上的活动大都是喝酒,回到酒店便借着些许酒劲改进Jscex。如今虽然Jscex的开发工作并没有详细的时间计划,但我正在使用GitHub的Issues页面记录需要制作的
昨天不得不花时间做了点保护博客阅读体验的事情,但其实这篇才是我真正想写的。上个星期在香港出差,晚上的活动大都是喝酒,回到酒店便借着些许酒劲改进Jscex。如今虽然Jscex的开发工作并没有详细的时间计划,但我正在使用GitHub的Issues页面记录需要制作的任务点,因此每天都是朝着目标逐步前进的。按照计划,Jscex的0.6.5的主要目标是对Jscex的模块机制进行改进,统一辅助方法,并使用Node.js重新编写发布脚本。这些工作的目的都是为接下来的0.7.0版本作准备,它将会是Jscex在项目功能与质量,以及专业性上有重大突破的版本。
Jscex的模块化划分十分细致,目前正式对外发布的也已经有六个模块(还有一个是命令)。模块化的目的是为了选择性的加载,例如在前端开发过程时需要加载所有的模块,而真正部署时则无需最大的两个模块:JIT 编译器及解析器(前者依赖后者),这既照顾到了JavaScript编程体验,也考虑到前端部署时的尺寸。但是模块化便对模块管理提出了要求,这在 Node.js平台下问题不大,因为NPM自带包管理功能,但在浏览器上便没有那么好的支持了。例如,模块依赖时还会涉及到版本,版本过高或者过低都是问 题,如何在模块没有加载,或是加载了错误的版本时清晰地告诉用户,这便是0.6.5版本中想要解决的问题。此外,Jscex还直接支持不同的包加载环境 (如AMD环境,之前我也谈过这方面的单元测试),这也是模块机制的重要责任。有了核心模块机制以后,各模块只需要注册自己的信息以及初始化方法,之前提过的错误提示,包加载环境支持等功能,便可以一并使用了。之后如果需要修复问题,或提供更多的功能,也只需要修改这个核心模块机制——简单地说,其实就是DRY原则。
更重要的一点是,这个各个模块在使用这个模块机制的时候,其实已经提供了自己的元信息,例如模块名称,当前版本,它所依赖的模块及其版本等等。换句话说,在发布这些脚本的时候,我们完全可以直接读取这些信息,而无需额外的配置文件。因此,我也使用Node.js替换了原来的Shell编写发布脚本。使用Node.js来代替Shell脚本在某些情况下的确会更为方便, 对于一些常见逻辑表达(条件判断,循环等等)或是操作(文件处理,字符串分析等等)来讲,JavaScript语言的可读性无疑会比Shell高很多(因 此也有很多人使用Ruby或Python来代替Shell脚本),对于熟悉JavaScript的同学来说则更不用说了。
大量使用Node.js来编写脚本并不如想象中的麻烦,它受JavaScript异步特性的影响并不大,这是因为Node.js标准库里包含了许多同步的方法,使用这些同步方法便可以完成绝大部分工作了,例如:
"use strict";

var path = require("path"),
    fs = require("fs"),
    utils = require("../lib/utils"),
    Jscex = utils.Jscex,
    _ = Jscex._;

var devDir = path.join(__dirname, "../bin/dev");
var srcDir = path.join(__dirname, "../src");

if (path.existsSync(devDir)) {
    utils.rmdirSync(devDir);
}

fs.mkdirSync(devDir);

var coreName = "jscex-" + Jscex.coreVersion + ".js" utils.copySync(path.join(srcDir, "jscex.js"), 
path.join(devDir, coreName));
console.log(coreName + " generated.");

var moduleList = ["parser", "jit", "builderbase", "async", "async-powerpack"];

_.each(moduleList, function (i, module) {
    var fullName = "jscex-" + module;
    var version = Jscex.modules[module].version;
    var outputName = fullName + "-" + version + ".js";
    utils.copySync(path.join(srcDir, fullName + ".js"), path.join(devDir, outputName));
    console.log(outputName + " generated.");
});
以上便是发布开发版Jscex的脚本, 可见其中每一步IO操作,例如判断目录是否存在,删除/创建目录以及复制文件,都使用了同步的版本。不过,Node.js并不能够完全代替Shell脚 本,因为Shell脚本有其重要的武器:管道。试想,你如何使用JavaScript来实现下面这行Shell脚本所做的事情?
cat /data/logs/run.log | grep 'node' | grep -v 'innode' | awk {'print $2'} | xargs sudo kill -9
因此,有时候我们不可避免要在Node.js中调用Shell脚本。同理,我们总会有需要调用外部程序的时候,例如,在发布生产环境的Jscex时,我需要使用Google Closure Compiler来压缩脚本体积,这就需要使用exec来执行外部命令。可惜的是,exec方法没有同步的版本,因此我们必须使用回调函数来处理结果,这又会再次陷入回调函数的泥潭。不过幸好我们有Jscex:
var fromCallback = Jscex.Async.Binding.fromCallback,
    exec = require('child_process').exec,
    execAsync = fromCallback(exec, "_ignored_", "stdout", "stderr");

var buildOne = eval(Jscex.compile("async", function (module) {
    var fullName, version;
    if (!module) {
        fullName = "jscex";
        version = Jscex.coreVersion;
    } else {
        fullName = "jscex-" + module;
        version = Jscex.modules[module].version;
    }

    var inputFile = fullName + ".js";
    var outputFile = fullName + "-" + version + ".min.js";

    var command = _.format(
        "java -jar {0} --js {1} --js_output_file {2} --compilation_level SIMPLE_OPTIMIZATIONS",
        gccPath,
        path.join(srcDir, inputFile),
        path.join(prodDir, outputFile));

    utils.stdout("Generating {0}...", outputFile);

    var r = $await(execAsync(command));
    if (r.stderr) {
        utils.stdout("failed.\n");
        utils.stderr(r.stderr + "\n");
    } else {
        utils.stdout("done.\n");
    }
}));
以上代码片段出自生产环境的Jscex发布脚本,可见有了Jscex之后,“阻塞”式地exec外部调用也完全不是问题。可以说,使用Jscex,可以基本解决Node.js代替编写Shell脚本的编程习惯或是风格问题,也欢迎大家多多尝试这种方法,并多多反馈,有问题及时发布在GitHub的Issues页面中。
至于Jscex的0.7.0版本,目前的计划是使用一个合适的JavaScript语法分析器来替换并统一UglifyJS和Narcissus的 分析器。UglifyJS的分析器提供的信息太少,而Narcissus则实现地十分不靠谱,例如它连\r\n这种换行符都不支持,此外它还自做主张地将 module作为关键字,这对来说Node.js是个很大的麻烦,因此其实目前Jscex的预编译器使用的是经过少许修改的Narcissus语法分析 器。在0.7.0版本中,我希望能从语法分析器中得到更多信息,这样便可以引入Source Map,更进一步地支持调试。此外,在改写Jscex的过程中,详细的单元测试自然是必不可少的。
正像我一开始说的那样,Jscex的0.7.0版本将会在项目功能与质量,以及专业性上有重大突破。这么做也不枉已经有600人在GitHub上关注着Jscex:

在Node.js的模块列表上,流程控制分类有80余个项目。其中关注人数最多的是async(2444人),其次是Step(862人),第三便是Jscex。

    有帮助
    (0)
    0%
    没帮助
    (0)
    0%
    百利在线app 下载