Cordova CLI源码分析(三)——初始化

本部分主要涉及以下三个文件

1 cli.js

2 cordova.js

3 events.js

 

通过前一篇package.json的分析,可以知道,当命令行执行cordova相关命令时,首先调用main参数指向的cordova.js文件,加载模块的相关信息,把内部接口暴露出来,起到初始化作用,方便后续模块内部调用各部分接口;

然后bin 指向的./bin/cordova 文件,执行

1. .#!/usr/bin/env node

2. var CLI = require('../src/cli');

3. new CLI(process.argv);

调用 src/cli,js文件,这个文件才是真正解析命令行参数,并执行对应操作的内容;

 

cli.js源码

 

var optimist  = require('optimist'),
    cordova   = require('../cordova'),
    plugman   = require('plugman'),
    platforms = require("../platforms");

module.exports = function CLI(inputArgs) {
	//inputArgs参数是process.argv,命令行参数数组
	//第一个元素是node,第二个元素是脚本文件名,第三个元素开始每个元素是运行参数
	//所以假设用户输入的是:cordova create hello hellotest com.jinkai.hellotest
	//process.argv输出结果是:node cordova create hello hellotest com.jinkai.hellotest
    args = optimist(inputArgs)
        .boolean('d') //boolean判断命令行参数中是否存在d,如果有args.d返回true,否则false
        .boolean('verbose')
        .boolean('v')
        .boolean('version')
        .argv;//args.argv 返回命令参数

    if (args.v || args.version) {
        return console.log(require('../package').version);
    }
//arrayObject.slice(start,end) 方法可从已有的数组中返回选定的元素
//start	必需。规定从何处开始选取。如果是负数,那么它规定从数组尾部开始算起的位置。也就是说,-1 指最后一个元素,-2 指倒数第二个元素,以此类推。
//end	可选。规定从何处结束选取。该参数是数组片断结束处的数组下标。如果没有指定该参数,那么切分的数组包含从 start 到数组结束的所有元素。如果这个参数是负数,那么它规定的是从数组尾部开始算起的元素。
//返回值:返回一个新的数组,包含从 start 到 end (不包括该元素)的 arrayObject 中的元素
    var tokens = inputArgs.slice(2), //inputArgs从数组中提取第三个元素(包含第三个)到最后,产生一个新数组
        opts = {
            platforms: [],
            options: [],
            verbose: (args.d || args.verbose)
        },
        cmd;

    // provide clean output on exceptions rather than dumping a stack trace
    process.on('uncaughtException', function(err){
        if (opts.verbose) {
            console.error(err.stack);
        } else {
            console.error(err);
        }
        process.exit(1);
    });
    cordova.on('results', console.log);

    if (opts.verbose) {
        cordova.on('log', console.log);
        cordova.on('warn', console.warn);
        plugman.on('log', console.log);
        plugman.on('warn', console.warn);
        //Remove the corresponding token
        //删除token数组中的标识符,即-d ,--verbose这类参数
        if(args.d && args.verbose) {
            tokens.splice(Math.min(tokens.indexOf("-d"), tokens.indexOf("--verbose")), 1);
        } else if (args.d) {
            tokens.splice(tokens.indexOf("-d"), 1);
        } else if (args.verbose) {
            tokens.splice(tokens.indexOf("--verbose"), 1);
        }
        //arrayObject.splice(index,howmany,element1,.....,elementX) 函数
        //index	必需。规定从何处添加/删除元素。
				//howmany	必需。规定应该删除多少元素。必须是数字,但可以是 "0"。	
				//返回值:如果从 arrayObject 中删除了元素,则返回的是含有被删除的元素的数组			
    }

    cmd = tokens && tokens.length ? tokens.splice(0,1) : undefined;
    if (cmd === undefined) {
        return cordova.help();
    }

    if (cordova.hasOwnProperty(cmd)) {
        if (cmd == 'emulate' || cmd == 'build' || cmd == 'prepare' || cmd == 'compile' || cmd == 'run') {
            // Filter all non-platforms into options
            tokens.forEach(function(option, index) { //此处使用forEach遍历元素,不应使用for循环,避免node异步IO机制带来的问题
                if (platforms.hasOwnProperty(option)) {
                    opts.platforms.push(option);
                } else {
                    opts.options.push(option);
                }
            });        
            cordova[cmd].call(this, opts);
        } else if (cmd == 'create' || cmd == 'serve') {
            cordova[cmd].apply(this, tokens);
        } else {
            // platform/plugins add/rm [target(s)]
            var invocation = tokens.slice(0,1); // this has the sub-command, i.e. "platform add" or "plugin rm"
            var targets = tokens.slice(1); // this should be an array of targets, be it platforms or plugins
            invocation.push(targets);
            cordova[cmd].apply(this, invocation);
        }
    } else {
        throw new Error('Cordova does not know ' + cmd + '; try help for a list of all the available commands.');
    }
}

 

 

源码中加入了必要的注释;

这段代码的主要作用就

1)提取参数,然后调用针对命令参数,分别调用不同接口函数;

2)Logdebug信息输出设置判断

3)栈崩溃信息的美化处理

 

再来看一下cordova.js文件

var cordova_events = require('./src/events'),
    prepare        = require('./src/prepare'),
    platform       = require('./src/platform'),
    run            = require('./src/run'),
    hooker         = require('./src/hooker'),
    util           = require('./src/util'),
    path           = require('path'),
    fs             = require('fs'),
    compile        = require('./src/compile');

var off = function() {
    cordova_events.removeListener.apply(cordova_events, arguments);
};

var emit = function() {
    cordova_events.emit.apply(cordova_events, arguments);
};

module.exports = {
    help:      require('./src/help'),
    config:    require('./src/config'),
    create:    require('./src/create'),
    platform:  platform,
    platforms: platform,
    prepare:   prepare,
    compile:   compile,
    run:       run,
    ripple:    require('./src/ripple'),
    emulate:   require('./src/emulate'),
    plugin:    require('./src/plugin'),
    plugins:   require('./src/plugin'),
    serve:     require('./src/serve'),
    on:        function() {
        cordova_events.on.apply(cordova_events, arguments);
    },
    off:       off,
    removeListener:off,
    removeAllListeners:function() {
        cordova_events.removeAllListeners.apply(cordova_events, arguments);
    },
    emit:      emit,
    trigger:   emit,
    build:     require('./src/build')
};

 

这段代码作用主要有三个:

1)包含依赖文件 require(....)函数部分

2)对node.js事件机制的包装,on off两个函数对应绑定事件和移除事件,emit 发射事件,其中cordova_events = require('./src/events') ,调用events.js

var events = require('events');
var emitter = new events.EventEmitter();
module.exports = emitter;

 

3)Module.exports中暴露出必要的参数接口


posted on 2013-08-29 19:07  you Richer  阅读(361)  评论(0编辑  收藏  举报