背景: 隨着開發團隊規模不斷髮展壯大,在人員增長的同時也帶來了協做成本的增長,業務項目愈來愈多,類型也各不相同。常見的類型有組件類、活動類、基於React+redux的業務項目、RN項目、Node.js項目等等。若是想要對每一個項目進行一些規範的約束好比Git提交規範、Javascript規範簡直難於登天。全部的這些,只由於缺乏一個好用的工程化工具。從項目建立、開發、構建、代碼規範檢查到最終項目上線,經過CLI能夠提高效率,同時保障開發規範的實施。javascript
關鍵點在於package.json裏面的bin字段。模塊全局安裝,對於類unix系統,在/usr/local/bin目錄建立軟連接;對於windows系統,在C:\Users\username\AppData\Roaming\npm目錄建立軟連接。
模塊局部安裝,會在項目內的./node_modules/.bin目錄建立軟連接。前端
隨着前端工程的不斷演進,一方面工程變得日趨複雜,同時對規範和質量的訴求在不斷增長。現代化web工程應該包含如下幾個階段:初始化、開發、構建、檢查、發佈。以下圖所示:java
項目拷貝存在的問題顯而易見,大體有如下三個方面:node
社區裏面提供了完美的Yeoman解決方案,它是爲了自動化項目的建立而生。Yeoman建立項目包括如下幾個階段:react
咱們只須要繼承Yeoman的Generator類作模板定製化,基於Yeoman的腳手架設計思路應該以下圖所示:
git
首先,開發者會和CLI進行交互,開發者會告訴CLI須要建立哪種類型的項目,CLI收到命令後。從本地已經安裝的Yeoman腳手架裏面選擇某種類型的模板。而後,CLI會調用Gitlab API在遠程建立倉庫而且授予開發者master權限。接下來,會根據實際業務場景須要,自動化申請一些打點信息,常見的如離線包id,監控告警id等等。以後,在本地目錄生成代碼而且安裝項目依賴的npm包,最後將本次初始化生成的全部代碼自動提交到遠程Git倉庫。github
基於React+redux組件化開發方式中,一個頁面或者webapp是由多個容器組件拼裝後渲染而成。
web
某個組件一般是由:模板、cgi數據和事件組成。理想狀況下,開發和產品和平共處,你能夠把一個組件寫成下面這個樣子,好比規則組件:npm
render() { return ( <div className="lottery-rule"> <div className="section"> <h3>活動時間:</h3> <p>9月14日~9月30日</p> </div> <div className="section"> <h3>活動規則:</h3> <p>一、活動期間,在NOW app上錄製小視頻,上傳成功後便可參賽。</p> <p>二、根據參賽小視頻得到的點贊數進行排行。</p> <p>三、按照城市評選,分別評選「明日之子」(僅限男性參加)和」閃亮女神「僅限女性參加。</p> </div> </div> ); }
咋一看,上面的寫法沒什麼問題。實際確極可能是七、8次的文案修改,甚至對外入口開放後仍然要修改文案或者圖片等靜態數據。而後,你須要走代碼發佈流程。json
更好的解決思路是:在開發某個業務組件以前,結合以往的經驗,分析哪些靜態數據極可能是須要高頻次的修改。將這些高頻次修改的靜態數據抽離出來,對於萬年不變的數據則沒有必要抽出來。那麼,如何將靜態數據動態化呢?
答案是: Schema First , 開發組件以前先設計Schema,經過schema生成一個form表單,達到靜態數據和模板分離。若是使用React開發,能夠基於react-jsonschema-form定製。靜態數據和模板分離以後應該以下圖:
此處以Git commit規範爲例子進行相關改進介紹。
良好的Git commit規範有如下優點:
此處採用Google angular項目的提交做爲參考,整理出Git commit的解決方案:
具體的提交格式要求以下:
<type>(<scope>): <subject> <BLANK LINE> <body> <BLANK LINE> <footer>
對格式的說明以下:
一鍵生成Changelog版本日誌:
一次血淋淋的生產環境事故:2017年4月13日,騰訊高級工程師小聖在作充值業務時,修改了蘋果iap支付配置,將JSON配置增長了重複的key。代碼發佈後,有小部分使用了vivo手機的用戶反饋充值頁面白屏,沒法在Now app內進行充值。最後問題定位是:vivo手機使用了系統自帶的webview而沒有使用X5內核,解析JSON時遇到重複key報錯,致使頁面白屏。
分析:現代化的瀏覽器對於JSON裏面的重複key會作兼容處理,可是某些老舊的瀏覽器內核並不會,好比此處的vivo手機,致使代碼直接出錯。那麼,如何避免相似問題再次出現呢?
此處不得不說起ESLint,ESLint於2013年6月推出最新版本v4.6.0,是一款適用於Javascript和JSX的代碼規範檢查工具,相比JSLint和JSHint而言,它更加靈活,支持自定義配置、插件擴展和配置錯誤級別。雖然接入ESLint會給團隊的同窗增長很多代碼修改的成本,可是從長遠來看,收益確定是大於付出的。
Javascript規範制定的原則:
爲了更好的定製和維護Javascript規範,咱們建立了eslint的shareable config。一方面,咱們以爲eslint:recommend 裏面的部分配置定義的錯誤級別過於嚴格,好比代碼裏面出現了console會致使校驗錯誤,另外一方面,它沒有包含ESLint的最佳實踐和其它規則。咱們定義的部分規則解釋以下:
規則名稱 | 錯誤級別 | 說明 |
---|---|---|
for-direction | error | for 循環的方向要求必須正確 |
getter-return | error | getter必須有返回值,而且禁止返回值爲undefined, 好比 return; |
no-await-in-loop | off | 容許在循環裏面使用await |
no-console | off | 容許在代碼裏面使用console |
no-prototype-builtins | warn | 直接調用對象原型鏈上的方法 |
valid-jsdoc | off | 函數註釋必定要遵照jsdoc規則 |
no-template-curly-in-string | warn | 在字符串裏面出現{和}進行警告 |
accessor-pairs | warn | getter和setter沒有成對出現時給出警告 |
array-callback-return | error | 對於數據相關操做函數好比reduce, map, filter等,callback必須有return |
block-scoped-var | error | 把var關鍵字當作塊級做用域,防止變量提高致使的bug |
class-methods-use-this | error | 要求在Class裏面合理使用this,若是某個方法沒有使用this,則應該申明爲靜態方法 |
complexity | off | 關閉代碼複雜度限制 |
default-case | error | switch case語句裏面必定須要default分支 |
ESLint的執行能夠接入到PUSH hook裏面,步驟以下:
#1, 安裝husky $ npm install husky --save-dev #2, 集成進npm script { "scripts": { "precommit": "validate-commit-msg", "prepush": "eslint src ./.eslintrc.js --ext '.js,.jsx'" } }
CLI的做用是將工程開發過程當中遇到的一系列痛點問題鏈接起來,提高開發效率,同時保障規範的實施。
這裏有一個很是巧妙的設計,經過使用node提供的module和vm模塊,能夠通注入feflow全局變量來訪問到cli的實例。從而可以訪問cli上的各類屬性,好比config, log和一些helper等。
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進行註冊,好比:
feflow.cmd.register('deps', 'Config ivweb dependencies', function(args) { console.log(args); // Plugin logic here. });
說明:
能夠經過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() // 致命錯誤日誌,,控制檯中顯示紅色
感謝OSC源創匯提供的交流機會,能和廣大開發者分享和交流學習,CLI源代碼託管在Github和碼雲上:
附件:本次分享PPT