文章同步在:github.com/hoperyy/blo…前端
微店前端工程化起步於一個內部產品 vbuilder,對外咱們有一個開源版本 bio-cli。vue
去年咱們也寫過一篇文章介紹該產品: bio: 一站式前端開發工具。react
這麼長時間過去了,咱們在前端工程化方面有了哪些變化、遇到了哪些問題、用怎樣的方案解決這些問題等等,值得爲你們再分享。webpack
這裏也就是介紹下背景,爲何咱們會開發 vbuilder。git
整體思路就是:將重複性工做集成化。es6
當時,團隊面臨幾個問題:github
packge.json
中的依賴既有腳手架的依賴,也有業務依賴,難以區分總結爲下圖:web
基於以上問題,咱們開始了 vbuilder 的研發。chrome
最終產品以命令行的形式發佈。json
此時的 vbuilder 爲 V0.0 狀態。
vbuilder V1.0 提供瞭如下能力:
mock / update / help
等vue / react / angular / weex
等),開放接入不一樣技術棧vbuilder 的不斷推動下,咱們欣喜地看到,團隊發生了一些變化:
weex / vms / 後臺管理 / serverside project
等總結爲下圖:
V1.0 出現後,推動的很順利,在推動過程當中秉持以下原則:
V1.0 基本解決了如下角色的痛點:
封閉性
高度定製化的工程配置需求實現難度增大
腳手架配置的主題被隱藏,雖然仍然開放給開發者一些配置性文件,對於高度定製化的配置需求而言依然杯水車薪。
此時,就必須新開一個腳手架,從新接入 vbuilder 體系。
在 「開放性」 來講,打了折扣。
插件開發的衝突
因爲 vbuilder 是基於命令行開發,插件開發者擴展自定義命令式,依然是自定義命令行,團隊規模不斷擴大的狀態下,很容易出現不一樣插件使用同一個命令,被同時安裝的狀態下,重複執行該命令。
V2.0 至少要解決 V1.0 存在的問題,同時須要有更明確的發展方向。
不過,V2.0 依然基於命令行。
V1.0 的思路是 「閉合」,雖然有必定的開放性,但仍然不夠。
V2.0 新增 「開放」 的能力,腳手架配置能夠被隱藏,也能夠隨時在須要的時候暴露在工程配置中,進行定製化開發。
固然,會遇到腳手架難以統一管理的問題,這一點仍然有辦法能夠解決。
由於被暴露的工程配置是 vbuilder 提供的,vbuilder 得以方便地統計哪些項目使用了自定義的腳手架,將通用型工具包下發給該工程。
問題 1:插件間的衝突
舉個例子,有兩個插件中,都有一個命令 run
。若是用戶安裝了這兩個插件,在執行 run
命令的時候,兩個插件的邏輯均會觸發。
在某些狀況下,這不是用戶但願看到的場景,可能 TA 但願的只是運行插件 A 的命令 run
。
問題 2:插件命令集與內置命令的衝突
例如,內置命令集中有命令 init
,而某個插件也有 init
。
那麼在用戶執行 init
命令時,依然會執行兩遍邏輯。
怎樣解決?
咱們組合使用瞭如下方案:
vbuilder 檢測是否有重複命令,若有,提示用戶是都運行、仍是選擇運行某一個插件中的命令
爲命令圈定生效條件
vbuilder 的命令行基於 commander
。咱們基於 commander
擴展了一些方法。
假如咱們但願,插件中的命令 show
只在工程目錄中 xx.show
文件存在的狀況下生效,那麼代碼以下:
commander
.command('show [param]')
.effect(cwd => fs.existsSync(path.join(cwd, 'xx.show'))) ---- 這是咱們擴展的命令
.description('個人自定義命令')
.action((param, options) => {
console.log('my show');
});
複製代碼
爲內置命令集聲明其爲「內置命令」,插件命令能夠阻止內置命令執行
假如插件中有個命令 init
,而 vbuilder 內置命令中也有 init
,咱們但願插件中的 init
命令生效,內置命令不生效,該怎麼作呢?
咱們擴展了 commander
的 2 個方法:declareDefault
聲明內置命令、preventDefault
阻止內置命令執行。
定義內置命令時,代碼以下:
commander
.command('init [param]')
.declareDefault() --- 聲明內置命令
.description('內置的 init 命令')
.action((param, options) => {
console.log('init inside');
});
複製代碼
開發插件命令時,代碼以下:
commander
.command('init [param]')
.preventDefault() --- 阻止內置命令執行
.description('內置的 init 命令')
.action((param, options) => {
console.log('init inside');
});
複製代碼
Commander
的源碼只有 1000 行左右,邏輯仍是很清晰的,擴展起來很是方便,這裏再也不列舉實現。
在命令行這個場景下,咱們把 vbuilder 定義爲公司內部開發的一個「水電煤」性質的基礎設施。
經過 vbuilder,咱們新增瞭如下場景:
得益於插件化,經過充分調動開發者積極性,咱們能夠將其能力無限延展。
咱們目前尚未進入 3.0 的開發,但有一些方向是咱們能夠嘗試的:
這是目前咱們在微店前端工程化領域的一些實踐和思考,但願對你們有幫助。