騰訊IVWEB前端工程化工具feflow思考與實踐

本篇文章主要介紹騰訊IVWEB團隊從0到1在工程化的思考和實踐。feflow的全稱是Front-end flow(前端工做流),致力於提高研發效率和規範的工程化解決方案。願景是經過feflow,可使項目建立、開發、構建、規範檢查到最終項目上線的整個過程更加自動化和標準化。前端

要解決的問題

  • 項目的目錄結構按約定生成
  • 團隊有一套開發規範進行約束
  • 支持多種類型的構建,包括Fis構建和webpack構建
  • 團隊內部的代碼貢獻統計、離線包內置App等

爲了解決上述問題,咱們於17年2月底開始投入工程化feflow工具的開發和相關規範的制定,目前已經研發出了 feflow 的 CLI 版本,後續會推出 GUI 版本。node

架構設計

爲了讓 feflow 的具備高可擴展性,咱們設計了4層結構,分別是:插件生態、內核層、參數解析器和控制檯。除了貫穿整個開發工做流的基礎命令選擇經過內部插件內置在CLI 的Core裏面,其它非必要命令統一經過插件機制進行擴展。webpack

另外一方面,爲了使得 feflow 可以適用多種類型的項目。咱們開發了多種類型的業務腳手架,如:活動模板、App H5模板、RN模板和業務組件模板。git

執行過程

當用戶在控制檯裏面輸入某個命令。首先會經過CLI 的參數解析器,將這個命令解析成一個object對象,而後傳遞給CLI 的內核。全部的命令都是經過內核上下文提供的 register 函數 進行註冊的,一方面內核自身會讀取內置插件 註冊的基礎命令,另外一方面,內核會讀取本地已經安裝的外部插件註冊的命令。若是找到用戶輸入的命令則開始執行命令對應的回調函數。github

基礎命令設計

# 初始化項目
$ feflow init

# 本地開發
$ feflow dev

# 代碼質量檢查
$ feflow lint

# 打包構建
$ feflow build

# 代碼發佈
$ feflow publish

# 安裝插件、腳手架等
$ feflow install package

# 配置本地客戶端,如: npm 的源和 proxy
$ feflow config <key> <value>

前面提到,CLI 的命令包含兩部分,分別是內置在內核裏的基礎命令和外部插件提供的命令。那麼外部插件要如何設計呢?web

插件機制設計

插件實現原理

這裏有一個很是巧妙的設計,經過使用node提供的module和vm模塊,能夠通注入feflow全局變量來訪問到cli的實例。從而可以訪問cli上的各類屬性,好比config, log和一些helper等。npm

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.register進行註冊,好比:json

feflow.cmd.register('deps', 'Config ivweb dependencies', function(args) {
    console.log(args);
    // Plugin logic here.
});

說明:babel

  • register有3個參數,第一個是子命令名稱,第二個是命令描述說明信息,第三個是對應的子命令執行邏輯函數。
  • feflow會將命令行參數args解析成Object對象,傳遞給插件處理函數

配置

能夠經過feflow.version獲取當前feflow的版本,feflow.baseDir 獲取feflow跟目錄(在用戶目錄下的.feflow),經過feflow.pluginDir 獲取插件目錄架構

日誌

經過feflow.log來進行相關命令行日誌輸出

const log = feflow.log;
log.info()    // 提示日誌,控制檯中顯示綠色
log.debug()   // 調試日誌,  命令行增長--debug能夠開啓,控制檯中顯示灰色
log.warn()    // 警告日誌,控制檯中顯示黃色背景
log.error()   // 錯誤日誌,控制檯中顯示紅色
log.fatal()   // 致命錯誤日誌,,控制檯中顯示紅色

安裝

插件開發完成後,能夠經過 feflow 提供的 install 命令安裝插件。安裝的插件會放置在本地客戶端 ~/.feflow/node_modules 文件夾下,而且寫入到 ~/.feflow/package.json 中

$ feflow install feflow-plugin-xxx   // 安裝某個插件

以後每次運行命令時,便會從本地加載插件所註冊的命令

全量更新和增量更新

當CLI發佈了一個新的版本,可能咱們會廢棄掉某些功能或者提供了新功能。這個時候若是用戶依然使用的是舊版本,因爲某些服務已經廢棄掉了則會報錯。在這種新舊版本不兼容的狀況下,如何強制用戶進行CLI的升級呢?須要在運行命令以前檢查本地的CLI是否和遠程提供的新版本是否兼容。在新舊版本不兼容時,會強制全量更新。如何判斷當前用戶安裝的本地版本和遠程最新版本是否兼容呢?

這裏很是巧妙的運用了一下 npm 的 registry機制,每次發佈新版本,咱們會在 package.json 裏面新增一個自定義字段 compatibleVersion,它的值是一個 semver 的版本號。本地檢查時,會讀取本地已經安裝的版本和遠程最新的版本進行比較,看看是否知足 compatibleVersion 的要求。若是不知足,則會自動運行 npm install feflow-cli 到最新的版本。

"configs": {
    "compatibleVersion": ">=0.13.0"
 },

對於插件,採起的是增量更新機制。每一個發佈到 npm 上的插件的package.json 中一樣會有上面的這個字段,對於本地安裝的不兼容的插件列表,會採起增量更新。

多類型腳手架的架構設計

項目拷貝存在的問題顯而易見,大體有如下三個方面:

  • 容易出錯;一旦某個關鍵文件拷貝丟失或者錯誤,極可能須要耗費半天到一天的時間排查環境問題。
  • 不一樣場景下對目錄結構要求不一樣;平時開發過程當中,工程一般會分爲運營活動、Hybrid業務、入口級別的項目(對性能和體驗有極致和苛刻的要求)。須要基於RN或者Node.js的首屏直出,還有經常使用的業務組件等的開發。
  • 新的Feature和BugFix難以同步;某個同窗開發過程當中增長的新方法或者解決的bug很難傳遞給其它同窗而且沉澱成經驗積累下來。

社區裏面提供了完美的Yeoman解決方案,它是爲了自動化項目的建立而生。Yeoman建立項目包括如下幾個階段:

  • initializing: 初始化一些狀態之類的,一般是和用戶輸入的 options 或者 arguments 打交道
  • prompting: 和用戶交互的時候(命令行問答之類的)調用
  • configuring: 保存配置文件(如 .babelrc 等)
  • writing: 生成模板文件
  • install: 安裝依賴
  • end: 結束部分,初始代碼自動提交

咱們只須要繼承Yeoman的Generator類作模板定製化,基於Yeoman的腳手架設計思路應該以下圖所示:

當開發者輸入 feflow init 命令時,開發者會告訴CLI須要建立哪種類型的項目,CLI收到命令後。從本地已經安裝的Yeoman腳手架裏面選擇某種類型的模板。而後,CLI會調用Gitlab API在遠程建立倉庫而且授予開發者master權限。接下來,會根據實際業務場景須要,自動化申請一些打點信息,常見的如離線包id,監控告警id等等。以後,在本地目錄生成代碼而且安裝項目依賴的npm包,最後將本次初始化生成的全部代碼自動提交到遠程Git倉庫。

多類型主流構建支持

爲了讓feflow 支持多種類型的構建環境,好比 Fis3 和 webpack,或者前不久剛推出的號稱零配置成本的 Parcel 構建。在每一個項目的跟目錄會放置一份配置文件,名稱爲 feflow.json。它的配置多是這樣的:

{
    "builderType": "builder-webpack3",
    "builderOptions": {
        "moduleName": "mobile",
        "bizName": "category",
        "minifyHTML": true,
        "minifyCSS": true,
        "minifyJS": true,
        "usePx2rem": true,
        "remUnit": 100,
        "remPrecision": 8,
        "inject": true,
        "port": 8001
    }
}

builderType爲構建的npm包,builderOptions爲構建的參數配置。

最後

騰訊IVWEB團隊的工程化解決方案feflow已經開源:Github主頁:https://github.com/feflow/feflow

若是對您的團隊或者項目有幫助,請給個Star支持一下哈~

相關文章
相關標籤/搜索