Feflow是一个前端集成开发环境,最新版本是v0.14.1,托管在Github上:feflow。目前已经在NOW直播、花样直播、花样交友、手Q附近、群视频、群送礼、回音等业务普遍使用。有60+ WEB/IOS/Andriod 稳定用户,累计投入生产项目达到200+。javascript
本文将会详细介绍Feflow的技术架构和实现原理。前端
Feflow于2017年3月份投入开发,最初只是为了解决项目建立不智能的问题。后面逐步解决了团队的构建、规范、CI和自动化问题,最终随着功能的不断完善而成为团队基础的前端集成开发环境。java
开发Feflow并非为了重复造轮子,最核心的目的是打造一体化的工做流程和一致性的团队开发方式。它基于社区已有的完备工具链体系,取众家之所长。node
下图描述了社区工具链生态: git
Feflow 借鉴了 Pipline 的思想,将平常的研发工做划分为:初始化、本地开发、打包构建、检查、发布上线五个步骤。分别对应 init、dev、build、test和deploy五个基本命令。github
除了服务好基本的开发工做流和规范,Feflow 提供了易于扩展的插件机制,用于打造团队统一的工具链生态。npm
下图介绍了Feflow的系统架构,从下到上分为4层。分别是控制台、参数解析器、Feflow内核、插件层。对应的功能分别是:json
插件是为了扩展子命令而设计的,Feflow插件须要以 feflow-plugin-*
开头,插件开发完成须要发布到npm或者tnpm。架构
在 Feflow 插件中,能够直接经过全局变量 feflow
来获取上下文。这个实现是借助 Node.js 提供的 module 和 vm模块来实现全局变量的注入。从而可以访问上下文的各类属性和方法,包括:函数
部分实现源码:
/** * Load a plugin with vm module and inject feflow variable, * feflow is an instance and has context environment. * * @param path {String} Plugin path * @param callback {Function} Callback */
loadPlugin(path, callback) {
const self = this;
return fs.readFile(path).then((script) => {
const module = new Module(path);
module.filename = path;
module.paths = Module._nodeModulePaths(path);
function require(path) {
return module.require(path);
}
require.resolve = function (request) {
return Module._resolveFilename(request, module);
};
require.main = process.mainModule;
require.extensions = Module._extensions;
require.cache = Module._cache;
// Inject feflow variable
script = '(function(exports, require, module, __filename, __dirname, feflow){' +
script + '});';
const fn = vm.runInThisContext(script, path);
return fn(module.exports, require, module, path, pathFn.dirname(path), self);
}).asCallback(callback);
}
复制代码
Feflow上下文提供了 cmd 对象,全部的命令都须要经过 cmd 进行注册,部分实现源码:
/** * Register a command, unique entrance for command registry. * * @param name {String} command name * @param desc {String} command description * @param options * @param fn {Function} command callback */
register(name, desc, options, fn) {
if (!name) throw new TypeError('name is required');
if (!fn) {
if (options) {
if (typeof options === 'function') {
fn = options;
if (typeof desc === 'object') { // name, options, fn
options = desc;
desc = '';
} else { // name, desc, fn
options = {};
}
} else {
throw new TypeError('fn must be a function');
}
} else {
// name, fn
if (typeof desc === 'function') {
fn = desc;
options = {};
desc = '';
} else {
throw new TypeError('fn must be a function');
}
}
}
if (fn.length > 1) {
fn = Promise.promisify(fn);
} else {
fn = Promise.method(fn);
}
const c = this.store[name.toLowerCase()] = fn;
c.options = options;
c.desc = desc;
this.alias = abbrev(Object.keys(this.store));
}
复制代码
插件开发好而且发布到 npm 或者 tnpm 后,接下来就是插件安装使用了。经过如下命令安装一个插件:
$ feflow install <package>
复制代码
Feflow 会将插件安装在 ~/.feflow/node_modules
下。
对于软件系统而言,都会存在发布新版本增长Feature或者修复Bug的状况。好比你们玩王者荣耀或者吃鸡游戏时刚刚进入启动界面会下载更新包,部分大版本会强制升级等等。
Feflow也提供了增量更新机制,每次初始化Feflow时都会将本地的版本和远程版本进行比较,若是本地版本和远程版本不兼容,则会强制帮开发者进行增量更新。
版本检查机制主要是借助 npm 的 registry 机制来实现的。若是你有使用过Feflow或者它的插件,你会发现相关npm包的 package.json
里面有一个自定义字段:
"configs": {
"compatibleVersion": ">=0.14.0"
},
...
复制代码
compatibleVersion
表示和即将发布版本兼容的用户使用版本,此处听从 semver 版本校验规范。若是是兼容的,则不会帮开发者更新本地插件,不兼容则会强制更新。
更新机制最大的优点是:统一管控能力,将最新的Feature同步给开发者,同时能够保证你们使用的版本没有致命Bug。
下图是建立项目的效果(能够保证团队每次建立新项目使用的是最新的脚手架):
Feflow 上下文提供了 log 对象,经过这个对象可让控制台里面显示出规范的日志输出。
const log = feflow.log;
log.info() // 提示日志,控制台中显示绿色
log.debug() // 调试日志, 命令行增长--debug能够开启,控制台中显示灰色
log.warn() // 警告日志,控制台中显示黄色背景
log.error() // 错误日志,控制台中显示红色
log.fatal() // 致命错误日志,,控制台中显示红色
复制代码
若是使用了 Feflow 上下文提供了 log 对象进行日志输出,那么这些日志信息会写入到 ~/.feflow/logs
本地文件系统里面。这便于后续问题的排查及错误上报等。
Feflow提供了日志分片的能力,将日志按天进行输出。
反馈或建议地址:issues,若是您的业务但愿接入Feflow,能够联系我。