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)Log和debug信息输出设置判断
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中暴露出必要的参数接口