1. 程式人生 > >常用gulp外掛介紹(一)

常用gulp外掛介紹(一)

在寫generator-aio-angular的過程中,gulp這一塊發現了很多非常實用的外掛,大大的增加了能自動化的範圍,這篇文章就分門別類的簡單介紹下常用的gulp外掛吧。

util工具類

這個分類下主要介紹一些輔助工具類的外掛。

顧名思義,本外掛的功能就是幫你自動require你在package.json中宣告的依賴。只要一句var $ = require('gulp-load-plugins')(),則package.json中宣告的gulp-gulp.開頭的外掛就會自動被放在變數$下面。如$.util就等於require('gulp-util'),而有兩個連字元的外掛則會自動命名為駝峰格式,如$.taskListing

則等於require('gulp-task-listing')。有了這個外掛,就不用一個一個的require了。這個外掛還有一些常用的引數配置,這裡列幾個常用的:

  • lazyload: true,用到這個外掛的時候再去require,預設為true。
  • rename: {'gulp-task-listing': 'list'},如果有些外掛名字太長,可以使用該引數重新命名。
  • scope: ['dependencies'],本外掛預設會掃描package.json裡的所有dependence,可以使用該引數進行限制。

要使用這些引數只要在require的時候傳入即可,如require('gulp-load-plugins')({lazy: true})

這個外掛的作用也很容易猜,它可以打印出gulpfile.js中定義的所有task,這個外掛我們在重構你的gulpfile這篇文章的最後介紹過,值得一提的是它還可以根據task的名字確定它是不是一個子task,比如帶有:-_的task就被認為是子task。我一般把這個外掛作為預設的task來呼叫,如

12 gulp.task('default', ['help']);gulp.task('help', $.taskListing);

這樣,如果只執行gulp的話就會打印出所有定義好的task,非常實用。

yargs

嚴格的說,yargs不是專門用於gulp的,它是Node中處理命令列引數的通用解決方案。只要一句程式碼var args = require('yargs').argv;

就可以讓命令列的引數都放在變數args上,非常方便。它可以處理的引數型別也是多種多樣的:

  • 單字元的簡單引數,如傳入-m=5-m 5,則可得到args.m = 5
  • 多字元引數(必須使用雙連字元),如傳入--test=5--test 5,則可得到args.test = 5
  • 不帶值的引數,如傳入--mock,則會被認為是布林型別的引數,可得到args.mock = true

除此之外,還支援很多其他型別的傳參方式,具體可參考它的文件

gulp-util帶有很多方便的函式,其中最常用的應該就是log了。$.util.log()支援傳入多個引數,列印結果會將多個引數用空格連線起來。它與console.log的區別就是所有$.util.log的結果會自動帶上時間字首。另外,它還支援顏色,如$.util.log($.util.colors.magenta('123'));打印出來的123是品紅色的。其實$.util.colors就是一個chalk的例項,而chalk是專門用來處理命令列列印著色的一個工具。

del

grunt自身提供一個grunt-contrib-clean用來處理支援glob匹配的刪除,而del就是gulp上對應的工具。del支援和gulp.src引數同樣的匹配,除此之外,它的第二個引數還支援一個回撥函式,當刪除完成以後執行,所以這是一個非同步的刪除。常用的呼叫方法為:del([xxx], callback)

這是一個統計檔案大小變化的工具,通常與壓縮類工具放在一起實用,比如

12345678910111213 gulp.src('**/*.html') .pipe($.bytediff.start()) .pipe($.minifyHtml({empty: true})) .pipe($.bytediff.stop(bytediffFormatter)) .pipe(gulp.dest('dist'));function bytediffFormatter (data) { var difference = (data.savings > 0) ? ' smaller.' : ' larger.'; return data.fileName + ' went from ' + (data.startSize / 1000).toFixed(2) + ' kB to ' + (data.endSize / 1000).toFixed(2) + ' kB and is ' + formatPercent(1 - data.percent, 2) + '%' + difference;}

在壓縮的pipe前後加上$.bytediff.start()$.bytediff.stop(callback),即可統計壓縮前後文件的變化。在callback中傳入的引數data上,可以訪問到很多變數,如檔名,變化前後的大小,變化百分比等等。

這個外掛的作用很簡單,打印出stream裡面的所有檔名,通常除錯的時候比較需要。

這個外掛也可以顧名思義:用來升級版本用的,廢話不說,直接看例子吧:

1234 return gulp .src('package.json') .pipe($.bump(options)) .pipe(gulp.dest('dist'));

重點來看這裡的options,我們可直接傳遞一個具體的version進去,也可以按照Node的版本規範傳遞一個type進去,讓其自己生成對應的version:

  • version,直接傳遞要升級到的版本號,如1.2.3
  • type,可接受的值包括下面四個,倘若現在的版本號為1.2.3,則對應的新版本號為:
    • prerelease:1.2.3-0
    • patch:1.2.4
    • minor:1.3.0
    • major:2.0.0

最終這個升級後的版本號會反映在package.json中,當然,你也可以在gulp.src中傳入更多的檔案(如bower.json)來替換更多的檔案。

這個工具用來在壓縮後的JS、CSS檔案中新增頭部註釋,你可以包含任意想要的資訊,通常就是作者、描述、版本號、license等,比如:

123456789101112131415 function getHeader () { var pkg = require('package.json'); var template = ['/**', ' * <%= pkg.name %> - <%= pkg.description %>', ' * @authors <%= pkg.authors %>', ' * @version v<%= pkg.version %>', ' * @link <%= pkg.homepage %>', ' * @license <%= pkg.license %>', ' */', '' ].join('\n'); return $.header(template, { pkg: pkg });}

這個函式將package.json中的各種資訊提取出來,變成頭部註釋,只要在壓縮的pipe中呼叫.pipe(getHeader())即可。

stream相關

這個部分主要介紹一些跟stream操作有關的外掛。

gulp-filter可以把stream裡的檔案根據一定的規則進行篩選過濾。比如gulp.src中傳入匹配符匹配了很多檔案,可以把這些檔案pipe給gulp-filter作二次篩選,如gulp.src('**/*.js').pipe($.filter(**/a/*.js)),本來選中了所有子檔案下的js檔案,經過篩選後變成名為a的子資料夾下的js檔案。那有人要問了,為什麼不直接將需要的篩選傳入gulp.src,幹嘛要多篩選一步呢?這裡面有兩種情況:

  • gulp.src$.filter中間可能需要別的處理,比如我對所有檔案做了操作1以後,還需要篩選出一部分做操作2。
  • 第二種情況就要談到gulp-filter的另外一個特性:篩選之後還可以restore回去。比如我對所有檔案做了操作1,篩選了一部分做操作2,最後要把所有的檔案都拷貝到最終的位置。程式碼如下:
1234567 var filter = $.filter('**/a/*.js');gulp.src('**/*.js') .pipe(action1()) .pipe(filter) .pipe(action2()) .pipe(filter.restore()) .pipe(gulp.dest('dist'))

可以看到,如果沒有restore這個操作,那麼拷貝到最終位置的檔案將只包含被過濾出來的檔案,這樣一restore,所有的檔案都被拷貝了。

gulp-flatten非常實用,可能知道別的庫中flatten函式的同學已經猜到它是幹嘛的了。比如gulp.src('**/*.js')匹配了很多檔案,包括a/b/c.jsd/e.jsf/g/h/i/j/k.jsl.js,這些檔案的層級都不一樣,一旦我們將這個檔案pipe給$.flatten(),則所有的資料夾層級都會去掉,最終的檔案將是c.jse.jsk.jsl.js,在一些場景下還是非常有用的。

這個外掛的作用簡單來說就是一旦pipe中的某一steam報錯了,保證下面的steam還繼續執行。因為pipe預設的onerror函式會把剩下的stream給unpipe掉,這個外掛阻止了這種行為。那它一般用於哪種場景呢?比如,程式碼每次build之前要跑一遍jshint和jscs來確保所有程式碼都符合規範,但一旦某些程式碼不符合規範,整個build流程就會停止,這個時候就需要gulp-plumber出場了。如:

12345678 gulp.task('build', ['jslint', 'xxxx']);gulp.task('jslint', function () { return gulp .src(config.js.all) .pipe($.plumber()) .pipe($.jshint()) .pipe($.jscs()); });

這樣,一旦jshint或jscs報錯,整個build流程還是可以繼續走下去的,而且gulp-plumber會給出一個報錯提醒我們:

1234 [16:52:36] Plumber found unhandled error: Error in plugin 'gulp-jshint'Message: JSHint failed for: xxxx.js

這個外掛的功能也很簡單,可以條件性的新增stream,如.pipe($.if(flag, action1())),則只會在flag變數為true時才會將action1()新增到stream中去。其實不用這個外掛也可以達到類似的效果,那就是gulp-util裡有一個函式叫做noop(),也就是no operation,這個函式其實是返回一個什麼都不幹的空stream。利用這個函式我們可以這麼寫:.pipe(flag ? action1() : $.util.noop()),與上例的效果是一樣的。

一個gulp的task只能返回一個stream,但有的時候有這麼一種情景:有兩類檔案,它們的原始位置和處理後的位置都是不同的,但它們的處理流程相同。由於gulp.srcgulp.dest的引數不同,我們就需要寫兩個task來分別完成這個任務,一方面略顯重複,另一方面邏輯上來講這兩個task本來就是處理同樣的事情的。這種情況就需要merge-stream登場了,它的作用就是將多個stream合成一個返回。比如下面這個例子:

12345678910111213 var merge = require('merge-stream');gulp.task('jade', function () { var stream1 = jade(src1, dest1); var stream2 = jade(src2, dest2); return merge(stream1, stream2);});function jade (src, dest) { return gulp .src(src) .pipe($.jade()) .pipe(gulp.dest(dest));}

可以看到,處理的流程被提取出來放入一個函式,它接受兩個引數,分別是src和dest。然後在task中直接呼叫這個函式生成兩個stream,然後返回merge-stream合併後的結果。

gulp裡的task都是非同步併發執行的,有的時候我們需要一連串的task按順序執行,這時就需要run-sequence登場了。它的呼叫很簡單:runSequence('task1', 'task2', ['task3', 'task4'], 'task5'),這裡的task都是gulp定義好的task名稱,task1完成後才會執行task2,以此類推。注意到task3和task4被放在中括號裡了,這表明,task3和task4可以併發執行的,但兩個都執行完後才會執行task5。這裡要說明的是,每個task要麼返回一個stream,即return gulp.src().pipe().pipe(),要麼支援回撥函式,即gulp.task('task1', function (done) { action1(done); }),滿足了這兩點才能保證正常的執行順序,因為這是gulp對非同步task的基本要求

inject相關

這個部分主要介紹一些將JS/CSS自動插入到HTML的相關外掛。

wiredep就是wire dependence的意思,它的作用就是把bower.json中宣告的dependence自動的包含到HTML中去。要插入檔案,wiredep需要解決兩個問題:

  • 插入的位置:wiredep通過識別HTML中的註釋來識別插入位置,如
1234 <!-- bower:css --><!-- endbower --><!-- bower:js --><!-- endbower -->

不同型別的檔案被插入到不同的區塊。

  • 插入什麼檔案:要插入的檔案列表自然來自bower.json,每個bower安裝的依賴庫,根目錄下邊都有一個自己的bower.json檔案,其中的main欄位指明瞭使用這個庫需要包含的檔案,wiredep最終包含的檔案列表就來自這個欄位。有些情況下,庫自身的bower.json的main欄位可能會多包含檔案或少包含檔案,如果想要定製這個列表,則可以在自己的bower.json中使用overrides欄位,如下面的程式碼覆蓋了mdi這個庫的main欄位。
1234567 "overrides": { "mdi": { "main": [ "css/materialdesignicons.css" ] }},

wiredep外掛支援很多引數,常用的主要有兩個:

  • bowerJson:指定bower.json的內容,注意這個欄位不是bower.json檔案的位置,這個引數需要使用require後的結果賦值:require('bower.json')
  • directory:指定存放bower安裝後的依賴包的路徑,通常是bower_components。注意最終插入到HTML中的檔案列表的路徑是index.html檔案相對於本資料夾的相對路徑。

使用wiredep也比較簡單,直接把它傳入到stream中即可,如gulp.src('index.html').pipe(wiredep(options))

這個外掛的作用與wiredep類似,不同的是可以自己任意指定需要插入檔案的列表。它同樣是利用註釋來尋找插入的位置,它識別的預設註釋為<!-- inject:js -->,但更加智慧:

  • 支援各種模板語言:可以根據gulp.src指定的原始檔自動識別註釋和插入內容,除了支援HTML外,還支援jade、haml等。若源為jade檔案,則識別的註釋為//- inject:js,插入的內容為:script(src="<filename>.js")
  • 配置非常靈活:
    • name:預設識別的註釋標籤格式為<!-- name:ext -->,這裡的name預設值就是“inject”,而ext的預設值是要插入的檔案的副檔名。那麼name屬性可配置意味著可以新增自定義的插入區塊,如<!-- production:js -->,這個標籤可以只插入生產環境需要包含的JS檔案。
    • starttag和endtag:支援自定義需要識別的註釋內容。
    • addPrefix和addSuffix:支援在插入檔案的路徑上自定義字首、字尾。
    • relative:指定插入檔案的路徑是否為相對路徑。
    • ingorePath:指定插入檔案的路徑前面會忽略掉指定的路徑。
    • read:這個引數通常給false,不需要真正的去讀取檔案。

這個外掛的使用場景通常是,我們需要index裡有多個區塊,比如上面name的例子,只有當為production環境編譯的時候才去包含相關的檔案。

這三個工具之所以放在一起講,是因為它們一般都是一起使用的。它們要解決什麼問題呢?通過上面的wiredep也好,gulp-inject也好,插入了一堆JS、CSS檔案到HTML中,一旦部署到生產環境,這麼多檔案必然是要合併壓縮的。光是壓縮還不夠,為了解決快取問題,每次合併壓縮後要給最終的檔案加hash,這樣每次檔案內容一變動,hash也會跟著變動,就不存在瀏覽器依然使用快取的老檔案的問題。這樣得到最終的檔案以後,肯定還要將這個檔案替換回HTML中去,一大堆的script和link標籤替換成最終合併壓縮帶hash的版本。

前面囉囉嗦嗦的一大堆工作就是這三個外掛要解決的問題了。首先,gulp-useref根據註釋將HTML中需要合併壓縮的區塊找出來,對區塊內的所有檔案進行合併。注意:它只負責合併,不負責壓縮!所以合併出來的檔案我們要自行壓縮,壓縮以後呼叫gulp-rev負責在檔名後追加hash。最後呼叫gulp-rev-replace負責把最終的檔名替換回HTML中去。扯了大半天,還是直接上例子吧。先來看看HTML中的註釋:

12345678910111213141516171819 <!-- build:css static/styles/lib.css --><!-- bower:css --><!-- endbower --><!-- endbuild --><!-- build:css static/styles/app.css --><!-- inject:css --><!-- endinject --><!-- endbuild --><!-- build:js static/js/lib.js --><!-- bower:js --><!-- endbower --><!-- endbuild --><!-- build:js static/js/app.js --><!-- inject:js --><!-- endinject --><!-- endbuild -->

gulp-useref識別的就是build開頭的註釋,build後面首先跟的是型別副檔名,然後後面的路徑就是build區塊中的所有檔案進行合併後的檔案路徑,這個相對路徑是相對於這個HTML的路徑。上面的例子中我們用build區塊把bower和inject進來的檔案包起來,這些檔案就可以被gulp-useref合併了。再來看gulp中useref相關task的定義:

123456789101112131415161718192021222324 var assets = $.useref.assets({searchPath: 'app/src/'});var cssFilter = $.filter('**/*.css');var jsAppFilter = $.filter('**/app.js');var jslibFilter = $.filter('**/lib.js');return gulp .src('index.html') .pipe(assets) .pipe(cssFilter) .pipe($.csso()) .pipe(cssFilter.restore()) .pipe(jsAppFilter) .pipe($.uglify()) .pipe(getHeader()) .pipe(jsAppFilter.restore()) .pipe(jslibFilter) .pipe($.uglify()) .pipe(jslibFilter.restore()) .pipe($.rev()) .pipe(assets.restore()) .pipe($.useref()) .pipe($.revReplace()) .pipe(gulp.dest('dist'));

首先一上來,先呼叫$.useref.assets()函式,這個函式返回一個stream,包含已經合併後的檔案。可以嘗試在第9行後面加上前面介紹過的gulp-print外掛.pipe($.print()),打印出stream裡的檔案,發現就是前面HTML中4個build註釋塊後面的4個檔案。注意這裡呼叫的時候跟了一個searchPath的引數,它的用處就是指定從哪個路徑開始尋找build區塊底下的檔案。比如build區塊底下有這麼一行<script src="static/js/a.js"></script>,那最終gulp-useref將從這個路徑app/src/static/js/a.js找到這個檔案。第3到5行定義了3個filter,這主要是為了後面壓縮準備的。下面正式看stream的pipe流程。先選出要處理的HTML檔案,然後呼叫剛才得到的assets得到合併後的4個檔案,第10到12行篩選出合併後的CSS檔案進行壓縮(壓縮類外掛下篇文章再講),第13到16行篩選出app.js進行壓縮,第17到19行篩選出lib.js進行壓縮。之所以要區別對待app.js和lib.js,是因為app.js是我們自己寫的程式碼,壓縮後要加上header(第15行,使用前面介紹過的gulp-header外掛),而lib.js是第三方的各種庫,直接壓縮即可。後面呼叫gulp-rev給壓縮後的4個檔案加hash,然後呼叫assets.restore()將src源換回HTML檔案,這是為了後面呼叫$.useref(),因為$.useref()做替換的src源是HTML檔案,同樣後面呼叫gulp-rev-replace將帶hash的檔案替換回HTML,它要求的src源也必須是HTML檔案。這裡的順序很重要,因為這幾個外掛接受的源不一樣,gulp-rev接受的是JS、CSS檔案,而gulp-useref和gulp-rev-replace接受的是HTML。還有一個問題:gulp-rev-replace是怎麼知道gulp-rev進行hash前後的檔名對應關係呢?其實gulp-rev會生成一個manifest的檔案,內容是類似下面的JSON:

1234 { "static/styles/lib.css": "static/styles/lib-d41d8cd98f.css" "static/js/lib.js": "static/js/lib-273c2cin3f.js"}

當然這個檔案預設是不會生成在檔案系統裡的,可以通過.pipe($.rev.manifest())將這個檔案儲存到本地。有了這個檔案,gulp-rev-replace甚至可以脫離gulp-rev獨立工作哦!

好了,這篇就到這裡,還有好多工具沒介紹到,留著給下篇吧。

相關推薦

常用gulp外掛介紹()

在寫generator-aio-angular的過程中,gulp這一塊發現了很多非常實用的外掛,大大的增加了能自動化的範圍,這篇文章就分門別類的簡單介紹下常用的gulp外掛吧。 util工具類 這個分類下主要介紹一些輔助工具類的外掛。 顧名思義,本外掛的功能就是幫你自動require你在package

使用gulp常用外掛介紹及用法

可供使用的外掛: 編譯 gulp-sass - 通過 libsass將Sass編譯成 CSS gulp-ruby-sass - 通過 Ruby Sass將Sass編譯成CSS gulp-compass - 通過 Ruby Sass和Compass

Sublime Text 3前端開發常用優秀外掛介紹

Package Control使用方法/安裝Emmet外掛 下面將以安裝Emmet外掛為例,同時介紹如何使用Package Control外掛 在Sublime Text 3中按下快捷鍵Ctrl+Shift+P 在出現的文字框中輸入Install Package(或直接輸入“ip”)選中Instal

常用Maven外掛介紹

一、介紹外掛之間先介紹下Maven的生命週期(lifecycle),因為plugin的使用跟lifecycle有關定義: 生命週期是包含在一個專案構建中的一系列有序的階段舉個例子來說就是maven 對一個工程進行操作的階段:驗證(validate)……編譯原始碼(compil

Maven實戰常用Maven外掛介紹

多年來Maven社群積累了大量的經驗,並隨之形成了一個成熟的外掛生態圈。Maven官方有兩個外掛列表,第一個列表的GroupId為org.apache.maven.plugins,這裡的外掛最為成熟,具體地址為:http://maven.apache.org/plugins

gulp常用外掛介紹

鑑於一開始研究gulp,最頭疼的就是不知道紛繁複雜的gulp外掛的作用,我覺得有必要寫一篇wiki科普一下。 1.gulp-sass 安裝方法:npm install gulp-sass --save-dev 作用:預編譯 sass 檔案為 css 檔案 例子:   'us

Gulp簡介及一些常用外掛介紹

Gulp 是用 nodejs 寫的一個前端構建工具,我現在主要拿來自動編譯 coffee、less 以及壓縮圖片、同步檔案、清理多餘檔案等工作。 gulp 使用 stream 方式處理內容,主要使用的幾個辦置方法如下: npm init命令初始化當前資料夾

常用記憶體資料庫介紹

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

資料庫連線池學習筆記():原理介紹+常用連線池介紹

什麼是連線池 資料庫連線池負責分配、管理和釋放資料庫連線,它允許應用程式重複使用一個現有的資料庫連線,而不是再重新建立一個。 為什麼要使用連線池  資料庫連線是一種關鍵的有限的昂貴的資源,這一點在多使用者的網頁應用程式中體現得尤為突出。  一個數據庫連線物件均對應

Git介紹常用操作演示()--技術流ken

Git介紹及常用操作演示(一)--技術流ken   Git介紹    Git(讀音為/gɪt/。)是一個開源的分散式版本控制系統,可以有效、高速的處理從很小到非常大的專案版本管理。 Git 是 Linus Torvalds 為了幫助管理 Linux 核心

c#窗體學習——常用控制元件介紹

偷懶,轉自若雲流風,原文:https://blog.csdn.net/ruoyunliufeng/article/details/72874691  一.常用控制元件 Lable標籤→僅顯示文字; TextBox文字控制元件→文字框; Button按鈕控制元件

Gulp常用外掛

Gulp 常用外掛 外掛使用注意事項: 1、外掛需要先 npm/cnpm install xx --save-dev 2、gulp taskname,如果 task 已經設定成 default 的依賴,直接 gulp 即可 3、task 中的檔案路徑都是相對 gulpfile.js 的

介紹款Visual Studio下的arduino外掛Visual Micro (Arduino IDE for Visual Studio)

我們都知道,arduino的官方編輯器,沒有程式碼提示功能,很多時候會因為大小寫的錯誤導致呼叫函式無效。Visual Studio 2010後代碼提示功能就比較完善了。所以將Arduino移到VS中去編寫,自然就能借用它的程式碼提示功能了。但需要一個外掛幫忙,這裡我們就介紹這個外掛的使用

、HTML的簡單介紹常用標籤的介紹

(一)、HTML 的簡單介紹 定義:HTML:HyperText Markup language(超文字標記語言),HTML 不是一門程式語言,而是標記語言。 作用:web 瀏覽器用 html 來顯示網頁 當前的標準:當前的 html 遵循 HTML5 標準

idea 使用說明以及常用外掛介紹

一、idea使用說明 匯入idea的配置(如果之前有配置好的idea的配置檔案) 設定idea的預設配置檔案 (1)設定預設的jdk (2)設定預設的Maven倉庫地址 (3)設定預設的Java檔案的頭部格式 (4)設定檔案編碼UTF8格式(重要)

vim外掛介紹)之Tabular

在這裡介紹一些好用的vim外掛,為了自己以後用到時候複習用。 在這裡先介紹tabular。具體怎麼安裝下載可以參照https://github.com/godlygeek/tabular 這裡介紹具體操作 介紹 在書寫資料等情況下,對齊文字就顯得比較

Notepad++前端開發常用外掛介紹

Notepad++除了自身的功能強大之外,更是有許多非常的優秀的外掛,下面就總結一下前端開發過程一些比較常用的外掛。 Emmet Emmet的前身是Zen Coding,一款使用仿CSS選擇器的語法來快速開發HTML和CSS的外掛,是前端開發神器。它無視了編輯器的自動提示和

VS CODE 微軟旗下最好用的前端開發IDE編輯器+常用外掛介紹

安裝完成後自動會顯示中文,如果需要設定字型主題樣式等,請點選左下角的齒輪按鈕,裡面有一個設定,自行選擇自己喜歡的配置。 然後推薦安裝一些基本的外掛,會讓你的開發更便捷,點選左側第五個圖示,進入外掛商店,搜尋以下關鍵字: Atom One

es外掛安裝以及常用外掛介紹

參考:http://www.cnblogs.com/richaaaard/p/5212044.html安裝• 線上安裝 針對ElasticSearch,我們可以直接通過命令列進行線上外掛安裝sudo elasticsearch/bin/plugin install mobz