We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
这里假设本文读者对FIS已经比较熟悉,如还不了解,可猛击官方文档。
虽然FIS整体的源码结构比较清晰,不过讲解起来也是个系统庞大的工程,笔者尽量的挑重点的讲。如果读者有感兴趣的部分笔者没有提到的,或者是存在疑惑的,可以在评论里跑出来,笔者会试着去覆盖这些点。
下笔匆忙,如有错漏请指出。
如在开始剖析FIS的源码前,有三点内容首先强调下,这也是解构FIS内部设计的基础。
1、 FIS支持三个命令,分别是fis release、fis server、fis install。当用户输入fis xx的时候,内部调用fis-command-release、fis-command-server、fis-command-install这三个插件来完成任务。同时,FIS的命令行基于commander这个插件构建,熟悉这个插件的同学很容易看懂FIS命令行相关部分源码。
fis release
fis server
fis install
fis xx
fis-command-release
fis-command-server
fis-command-install
commander
2、FIS以fis-kernel为核心。fis-kernel提供了FIS的底层能力,包含了一系列模块,如配置、缓存、文件处理、日志等。FIS的三个命令,最终调用了这些模块来完成构建的任务。参考 fis-kernel/lib/ 目录,下面对每个模块的大致作用做了简单备注,后面的文章再详细展开。
fis-kernel
fis-kernel/lib/
lib/ ├── cache.js // 缓存模块,提高编译速度 ├── compile.js // (单)文件编译模块 ├── config.js // 配置模块,fis.config ├── file.js // 文件处理 ├── log.js // 日志 ├── project.js // 项目相关模块,比如获取、设置项目构建根路径、设置、获取临时路径等 ├── release.js // fis release 的时候调用,依赖 compile.js 完成单文件编译。同时还完成如文件打包等任务。├── uri.js // uri相关 └── util.js // 各种工具函数
3、FIS的编译过程,最终可以拆解为细粒度的单文件编译,理解了下面这张图,对于阅读FIS的源码有非常大的帮助。(主要是fis release这个命令)
开篇的描述可能比较抽象,下面我们来个实际的例子。通过这个简单的例子,我们可以对FIS的整体设计有个大致的印象。
下文以fis server open为例,逐步剖析FIS的整体设计。其实FIS比较精华的部分集中在fis release这个命令,不过fis server这个命令相对简单,更有助于我们从纷繁的细节中跳出来,窥探FIS的整体概貌。
fis server open
假设我们已经安装了FIS。好,打开控制台,输入下面命令,其实就是打开FIS的server目录
从package.json可以知道,此时调用了 fis/bin/fis,里面只有一行有效代码,调用fis.cli.run()方法,同时将进程参数传进去。
package.json
fis/bin/fis
fis.cli.run()
#!/usr/bin/env node require('../fis.js').cli.run(process.argv);
接下来看下../fis.js。代码结构非常清晰。注意,笔者将一些代码给去掉,避免长串的代码影响理解。同时在关键处加了简单的注释
../fis.js
// 加载FIS内核 var fis = module.exports = require('fis-kernel'); //项目默认配置 fis.config.merge({ // ... }); //exports cli object // fis命令行相关的对象 fis.cli = {}; // 工具的名字。在基于fis的二次解决方案中,一般会将名字覆盖 fis.cli.name = 'fis'; //colors // 日志友好的需求 fis.cli.colors = require('colors'); //commander object // 其实最后就挂载了 commander 这个插件 fis.cli.commander = null; //package.json // 把package.json的信息读进来,后面会用到 fis.cli.info = fis.util.readJSON(__dirname + '/package.json'); //output help info // 打印帮助信息的API fis.cli.help = function(){ // ... }; // 需要打印帮助信息的命令,在 fis.cli.help() 中遍历到。 如果有自定义命令,并且同样需要打印帮助信息,可以覆盖这个变量 fis.cli.help.commands = [ 'release', 'install', 'server' ]; //output version info // 打印版本信息 fis.cli.version = function(){ // ... }; // 判断是否传入了某个参数(search) function hasArgv(argv, search){ // ... } //run cli tools // 核心方法,构建的入口所在。接下来我们就重点分析下这个方法。假设我们跑的命令是 fis server open // 实际 process.argv为 [ 'node', '/usr/local/bin/fis', 'server', 'open' ] // 那么,argv[2] ==> 'server' fis.cli.run = function(argv){ // ... };
我们来看下笔者注释过的fis.cli.run的源码。
fis.cli.run
fis -h
fis --help
fis -v
fis --version
//run cli tools fis.cli.run = function(argv){ fis.processCWD = process.cwd(); // 当前构建的路径 if(hasArgv(argv, '--no-color')){ // 打印的命令行是否单色 fis.cli.colors.mode = 'none'; } var first = argv[2]; if(argv.length < 3 || first === '-h' || first === '--help'){ fis.cli.help(); // 打印帮助信息 } else if(first === '-v' || first === '--version'){ fis.cli.version(); // 打印版本信息 } else if(first[0] === '-'){ fis.cli.help(); // 打印版本信息 } else { //register command // 加载命令对应的插件,这里特指 fis-command-server var commander = fis.cli.commander = require('commander'); var cmd = fis.require('command', argv[2]); cmd.register( commander .command(cmd.name || first) .usage(cmd.usage) .description(cmd.desc) ); commander.parse(argv); // 执行命令 } };
通过fis.cli.run的源码,我们可以看到,fis-command-xx插件,都提供了register方法,在这个方法内完成命令的初始化。之后,通过commander.parse(argv)来执行命令。
fis-command-xx
register
commander.parse(argv)
整个流程归纳如下:
三个命令相关的插件中,fis-command-server的代码比较简单,这里就通过它来大致介绍下。
根据惯例,同样是抽取一个超级精简版的fis-command-server,这不影响我们对源码的理解
var server = require('./lib/server.js'); // 依赖的基础库 // 命令的配置属性,打印帮助信息的时候会用到 exports.name = 'server'; exports.usage = '<command> [options]'; exports.desc = 'launch a php-cgi server'; // 对外暴露的 register 方法,参数的参数为 fis.cli.command exports.register = function(commander) { // 略过若干个函数 // 命令的可选参数,格式参考 commander 插件的文档说明 commander .option('-p, --port <int>', 'server listen port', parseInt, process.env.FIS_SERVER_PORT || 8080) .action(function(){ // 当 command.parse(..)被调用时,就会进入这个回调方法。在这里根据fis server 的子命令执行具体的操作 // ... }); // 注册子命令 fis server open // 同理,可以注册 fis server start 等子命令 commander .command('open') .description('open document root directory'); };
好了,fis server open 就大致剖析到这里。只要熟悉commander这个插件,相信不难看懂上面的代码,这里就不多做展开了,有空也写篇科普文讲下commander的使用。
如序言所说,欢迎交流探讨。如有错漏,请指出。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
序言
这里假设本文读者对FIS已经比较熟悉,如还不了解,可猛击官方文档。
虽然FIS整体的源码结构比较清晰,不过讲解起来也是个系统庞大的工程,笔者尽量的挑重点的讲。如果读者有感兴趣的部分笔者没有提到的,或者是存在疑惑的,可以在评论里跑出来,笔者会试着去覆盖这些点。
下笔匆忙,如有错漏请指出。
Getting started
如在开始剖析FIS的源码前,有三点内容首先强调下,这也是解构FIS内部设计的基础。
1、 FIS支持三个命令,分别是
fis release
、fis server
、fis install
。当用户输入fis xx
的时候,内部调用fis-command-release
、fis-command-server
、fis-command-install
这三个插件来完成任务。同时,FIS的命令行基于commander
这个插件构建,熟悉这个插件的同学很容易看懂FIS命令行相关部分源码。2、FIS以
fis-kernel
为核心。fis-kernel
提供了FIS的底层能力,包含了一系列模块,如配置、缓存、文件处理、日志等。FIS的三个命令,最终调用了这些模块来完成构建的任务。参考fis-kernel/lib/
目录,下面对每个模块的大致作用做了简单备注,后面的文章再详细展开。3、FIS的编译过程,最终可以拆解为细粒度的单文件编译,理解了下面这张图,对于阅读FIS的源码有非常大的帮助。(主要是
fis release
这个命令)一个简单的例子:fis server open
开篇的描述可能比较抽象,下面我们来个实际的例子。通过这个简单的例子,我们可以对FIS的整体设计有个大致的印象。
下文以
fis server open
为例,逐步剖析FIS的整体设计。其实FIS比较精华的部分集中在fis release
这个命令,不过fis server
这个命令相对简单,更有助于我们从纷繁的细节中跳出来,窥探FIS的整体概貌。假设我们已经安装了FIS。好,打开控制台,输入下面命令,其实就是打开FIS的server目录
从
package.json
可以知道,此时调用了fis/bin/fis
,里面只有一行有效代码,调用fis.cli.run()
方法,同时将进程参数传进去。接下来看下
../fis.js
。代码结构非常清晰。注意,笔者将一些代码给去掉,避免长串的代码影响理解。同时在关键处加了简单的注释我们来看下笔者注释过的
fis.cli.run
的源码。fis -h
或者fis --help
,打印帮助信息fis -v
或者fis --version
,打印版本信息fis-command-server
通过
fis.cli.run
的源码,我们可以看到,fis-command-xx
插件,都提供了register
方法,在这个方法内完成命令的初始化。之后,通过commander.parse(argv)
来执行命令。整个流程归纳如下:
fis server open
fis-command-server
fis-command-server源码
三个命令相关的插件中,
fis-command-server
的代码比较简单,这里就通过它来大致介绍下。根据惯例,同样是抽取一个超级精简版的
fis-command-server
,这不影响我们对源码的理解好了,
fis server open
就大致剖析到这里。只要熟悉commander
这个插件,相信不难看懂上面的代码,这里就不多做展开了,有空也写篇科普文讲下commander
的使用。写在后面
如序言所说,欢迎交流探讨。如有错漏,请指出。
The text was updated successfully, but these errors were encountered: