Feflow是一個前端整合開發環境,最新版本是v0.14.1,託管在Github上:feflow。目前已經在NOW直播、花樣直播、花樣交友、手Q附近、群視訊、群送禮、迴音等業務廣泛使用。有60+ WEB/IOS/Andriod 穩定使用者,累計投入生產專案達到200+。
本文將會詳細介紹Feflow的技術架構和實現原理。
1. 起源
Feflow於2017年3月份投入開發,最初只是為了解決專案建立不智慧的問題。後面逐步解決了團隊的構建、規範、CI和自動化問題,最終隨著功能的不斷完善而成為團隊基礎的前端整合開發環境。
開發Feflow並不是為了重複造輪子,最核心的目的是打造一體化的工作流程和一致性的團隊開發方式。它基於社群已有的完備工具鏈體系,取眾家之所長。
下圖描述了社群工具鏈生態:
2. 設計思路
Feflow 借鑑了 Pipline 的思想,將日常的研發工作劃分為:初始化、本地開發、打包構建、檢查、釋出上線五個步驟。分別對應 init、dev、build、test和deploy五個基本命令。
除了服務好基本的開發工作流和規範,Feflow 提供了易於擴充套件的外掛機制,用於打造團隊統一的工具鏈生態。
3. 整體架構
下圖介紹了Feflow的系統架構,從下到上分為4層。分別是控制檯、引數解析器、Feflow核心、外掛層。對應的功能分別是:
- 控制檯:開發者和Feflow的命令互動層,開發者在控制檯裡面輸入一系列的命令。
- 引數解析器:負責解析開發者輸入的命令資訊,轉換成一個Object物件。然後將物件傳遞給Feflow核心。
- 核心層:一方面提供Feflow的上下文(包括版本資訊、Feflow配置資訊、日誌模組和一些幫助函式)、外掛註冊和載入機制、核心和外掛的更新機制;另一方面提供基礎的工作流命令。
- 外掛層:主要是官方外掛和開發者編寫的外掛。
4. 外掛機制
外掛是為了擴充套件子命令而設計的,Feflow外掛需要以 feflow-plugin-*
開頭,外掛開發完成需要釋出到npm或者tnpm。
4.1 外掛上下文
在 Feflow 外掛中,可以直接通過全域性變數 feflow
來獲取上下文。這個實現是藉助 Node.js 提供的 module 和 vm模組來實現全域性變數的注入。從而能夠訪問上下文的各種屬性和方法,包括:
- Feflow配置:版本資訊、Home目錄路徑、外掛路徑等
- 上下文函式:命令註冊物件、日誌物件
- 幫助函式
部分實現原始碼:
/** * 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);
}複製程式碼
4.2 命令註冊
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));
}複製程式碼
4.3 外掛安裝
外掛開發好並且釋出到 npm 或者 tnpm 後,接下來就是外掛安裝使用了。通過以下命令安裝一個外掛:
$ feflow install <
package>
複製程式碼
Feflow 會將外掛安裝在 ~/.feflow/node_modules
下。
5. 更新機制
對於軟體系統而言,都會存在釋出新版本增加Feature或者修復Bug的情況。比如大家玩王者榮耀或者吃雞遊戲時剛剛進入啟動介面會下載更新包,部分大版本會強制升級等等。
5.1 更新檢查流程
Feflow也提供了增量更新機制,每次初始化Feflow時都會將本地的版本和遠端版本進行比較,如果本地版本和遠端版本不相容,則會強制幫開發者進行增量更新。
5.2 實現原理
版本檢查機制主要是藉助 npm 的 registry 機制來實現的。如果你有使用過Feflow或者它的外掛,你會發現相關npm包的 package.json
裡面有一個自定義欄位:
"configs": {
"compatibleVersion": ">
=0.14.0"
}, ...複製程式碼
compatibleVersion
表示和即將釋出版本相容的使用者使用版本,此處遵從 semver 版本校驗規範。如果是相容的,則不會幫開發者更新本地外掛,不相容則會強制更新。
5.3 實際效果
更新機制最大的優勢是:統一管控能力,將最新的Feature同步給開發者,同時可以保證大家使用的版本沒有致命Bug。
下圖是建立專案的效果(可以保證團隊每次建立新專案使用的是最新的腳手架):
6. 日誌
Feflow 上下文提供了 log 物件,通過這個物件可以讓控制檯裡面顯示出規範的日誌輸出。
6.1 日誌分級
const log = feflow.log;
log.info() // 提示日誌,控制檯中顯示綠色log.debug() // 除錯日誌, 命令列增加--debug可以開啟,控制檯中顯示灰色log.warn() // 警告日誌,控制檯中顯示黃色背景log.error() // 錯誤日誌,控制檯中顯示紅色log.fatal() // 致命錯誤日誌,,控制檯中顯示紅色複製程式碼
6.2 日誌分片
如果使用了 Feflow 上下文提供了 log 物件進行日誌輸出,那麼這些日誌資訊會寫入到 ~/.feflow/logs
本地檔案系統裡面。這便於後續問題的排查及錯誤上報等。
Feflow提供了日誌分片的能力,將日誌按天進行輸出。
Issues
反饋或建議地址:issues,如果您的業務希望接入Feflow,可以聯絡我。