咱們先來設定一個簡單的需求:javascript
一言不合就上圖:css
好,有了這個規劃以後,咱們開始着手來實現它。html
首先新建一個項目文件夾project,接着咱們打開命令行工具,切換到這個目錄下,開始初始化這個項目:前端
cd project npm init
按照提示完成初始化,打開項目咱們會獲得一個package.json文件像這樣:java
// package.json { "name": "project", "version": "1.0.0", "description": "a test project", "main": "index.js", "scripts": { "test": "node ./build/test.js" }, "author": "jack lo", "license": "ISC" }
緊接着咱們先來創造一份源碼,結構以下:node
- project
|- src // 源文件夾
| |- tpl
| | `- index.html | |- css | | `- index.css | |- js | | `- index.js |- dist // 打包文件夾 `- package.json
一切材料就緒,咱們開始安裝工具包,這一次咱們主要使用gulp來構建,不須要用到webpack,同時,爲了實現瀏覽器自動刷新的功能,咱們還須要用到browser-sync。webpack
npm install gulp browser-sync --save-dev
這須要花點時間。git
---------- 虛度光陰中 ---------github
事實上,這裏有個小坑須要咱們提早準備一下,由於咱們接下來會用到gulp的cli,因此這裏咱們須要全局安裝gulp,沒錯,我就是設套讓你裝兩遍!web
這是個好習慣,請務必之後也堅持這麼作。把開發時候用到的全部npm包都記錄在package.json文件中,能夠方便往後本身以及他人的使用。
npm install gulp -g
mac用戶可能還要sudo一下:
sudo npm install gulp -g
回車後按提示輸入密碼,繼續回車,就能夠正常安裝了。
---------- 再一次虛度光陰中 ---------
ok,安裝完後,咱們能夠開始作點有意義的事了。
gulp的用法其實至關簡單,api也就那麼幾個。簡單來講,就是寫好一個配置文件gulpfile.js,而後在命令行裏執行它。
首先在根目錄下新建一個gulpfile.js,而後隨便建一個叫作test的任務:
// gulpfile.js var gulp = require('gulp') // 建立一個名爲test的任務,任務內容只是簡單地在控制檯輸出一段文本 gulp.task('test', function () { return console.log('this is a test') })
ok,保存。而後咱們回到命令行,輸入如下命令而後回車
gulp test
gulp後面跟的是你所要執行的任務名,因而咱們獲得了這樣一個結果
[22:56:35] Using gulpfile ~/project/gulpfile.js [22:56:35] Starting 'test'... this is a test [22:56:35] Finished 'test' after 149 μs
成功輸出文本!恭喜,你已經掌握了gulp一半以上的用法。
如今咱們嘗試着來操做文件,咱們將src/html裏面的html文件給拷貝到dist文件夾(若是不存在則新建)裏面去,怎麼作?
// 建立一個copy的任務 gulp.task('copy', function () { return gulp.src('src/tpl/*.html') .pipe(gulp.dest('dist')) })
這裏的pipe實際上是一種管道,你能夠一直pipe連着pipe下去,也就是這個工做流能夠一直這樣一層層執行下去,隨便你定義多少個處理任務都行,這就是gulp的特色,簡單明瞭的工做流程。不少人不明白gulp究竟是作什麼的,其實到這裏,就能夠有個大概的認識了:
gulp是以定義並執行一個個任務的形式來工做的流程管理工具,它的做用在於提供一套簡單易用的工做方式。
在gulp之前,處理一份sass文件,你可能須要先執行一次編譯的任務,編譯成css以後,再執行一遍壓縮css的任務,壓縮完以後,再手動拷貝到打包文件夾裏。本來須要分三步來操做的一件事情,在gulp裏面就是一個任務的sei而已:
// 建立一個css的處理任務 gulp.task('sass', function () { return gulp.src('src/sass/*.scss') .pipe(sass()) .pipe(minifycss()) .pipe(gulp.dest('dist/static')) })
甚至咱們能夠同時執行多個任務,我能夠定義好coffee、sass、image、html的四個任務,再把他們合併到一個任務當中去,一次性執行完:
// 建立一個build的處理任務 gulp.task('build', ['coffee', 'sass', 'image', 'html'])
我只須要:
gulp build
回車,這酸爽。
好了,介紹了這麼多內容,最後咱們仍是回到最開始那份需求的實現上來。
咱們來建幾個任務,分別處理js、css、html文件,把js和css文件放到dist/static目錄下,把html文件放到dist下:
gulp.task('css', function () { return gulp.src('src/css/*.css') .pipe(gulp.dest('dist/static')) }) gulp.task('js', function () { return gulp.src('src/js/*.js') .pipe(gulp.dest('dist/static')) }) gulp.task('html', function () { return gulp.src('src/tpl/*.html') .pipe(gulp.dest('dist')) }) gulp.task('build', ['css', 'js', 'html'])
命令行gulp build一下,回車!再看看dist文件夾,done!
咋一看,好像沒什麼問題,但好像又有哪裏不太對勁。不對啊,除了複製到dist文件夾,好像沒啥功能啊,說好的壓縮合並呢?說好的處理預編譯呢?嗯,有了這個框架,這些功能咱們想加多少加多少。
這樣簡單的項目,咱們無法玩出花樣,咱們來點預編譯語言,css用sass代替,html用swig代替:
- project
|- src // 源文件夾
| |- tpl
| | `- index.swig | |- sass | | `- index.scss | |- js | | `- index.js |- dist // 打包文件夾 `- package.json
編譯sass須要安裝gulp-sass模塊,編譯swig須要gulp-swig。注意到了嗎?基本上gulp的模塊都以gulp-*
的形式出現,因此若是之後你使用gulp的時候想用什麼模塊,能夠試試在npm搜gulp-模塊名
。
npm install gulp-sass gulp-swig --save-dev
---------- 虛度光陰中 ---------
安裝完後,咱們再來修改一下配置文件gulpfile.js
var gulp = require('gulp') var sass = require('gulp-sass') var swig = require('gulp-swig') gulp.task('sass', function () { return gulp.src('src/sass/*.scss') .pipe(sass({ outputStyle: 'compressed' // 此配置使文件編譯並輸出壓縮過的文件 })) .pipe(gulp.dest('dist/static')) }) gulp.task('js', function () { return gulp.src('src/js/*.js') .pipe(gulp.dest('dist/static')) }) gulp.task('tpl', function () { return gulp.src('src/tpl/*.swig') .pipe(swig({ defaults: { cache: false // 此配置強制編譯文件不緩存 } })) .pipe(gulp.dest('dist')) }) gulp.task('build', ['sass', 'js', 'tpl'])
再接着gulp build一下,編譯結束,能夠看看dist下是否是有index.html,dist/static下是否是有編譯完成且壓縮過的index.css,沒有你找我!這裏就不分別展現源文件和打包後文件的內容了,由於並不重要,想看演示項目內容的朋友,能夠在文章結尾處找到本次演示項目的git倉庫連接。各類預編語言和前端模板你們能夠根據本身的喜愛選擇,筆者只是選擇本身熟悉的幾種來作演示。
到這裏咱們基本上已經完成打包的工做了,咱們來試着搭建開發環境。
前文咱們提到一個工具browser-sync,還記得嗎?如今用得上了!咱們先建立一個開發任務,像gulp build同樣簡單的任務,咱們的目標是:沒有蛀牙 一句話搞定。
gulp.task('dev', ['js:dev', 'sass:dev', 'tpl:dev'], function () { // do something here... })
看着好像稍有不一樣。這一次咱們建立一個叫作dev的任務,這個任務先執行js:dev
、sass:dev
和tpl:dev
三個任務,而後再執行回調裏的內容,咱們的本地服務器就是要在回調裏去定義而且啓動。
在這以前,咱們先來了解一下browser-sync:
Browsersync能讓瀏覽器實時、快速響應您的文件更改(html、js、css、sass、less等)並自動刷新頁面。 ——Browsersync中文網
事實上Browsersync能夠理解爲一個本地服務器,相似於Apache,不一樣的是,Browsersync只提供很簡單的http功能,它的主要功能,是經過搭建一個本地服務器,而且監聽文件的更改,自動刷新瀏覽器,實時地呈現最新內容。
browser-sync的用法:
var browserSync = require('browser-sync').create() browserSync.init({ server: { baseDir: "./" // 設置服務器的根目錄 } })
其實也很簡單,沒有太多內容,如今咱們要將它整合進咱們的gulp任務裏,搗鼓幾下,咱們獲得:
gulp.task('dev', ['js:dev', 'sass:dev', 'tpl:dev'], function () { browserSync.init({ server: { baseDir: "./dist" // 設置服務器的根目錄爲dist目錄 }, notify: false // 開啓靜默模式 }) // 咱們使用gulp的文件監聽功能,來實時編譯修改事後的文件 gulp.watch('src/js/*.js', ['js:dev']) gulp.watch('src/sass/*.scss', ['sass:dev']) gulp.watch('src/tpl/*.swig', ['tpl:dev']) })
這裏的watch行爲能夠簡單理解爲:我(gulp)就這麼盯着你(src/js/*.js文件),只要你被改動了,我就立刻執行js:dev
任務來處理你,產生最新的文件。
那麼,咱們如今還須要補充一下js:dev
、sass:dev
和tpl:dev
這三個任務,與原來的js
、sass
和tpl
三個任務大同小異,這裏籠統地過一遍就好,咱們直接看代碼:
var browserSync = require('browser-sync').create() var reload = browserSync.reload gulp.task('sass:dev', function () { return gulp.src('src/sass/*.scss') .pipe(sass()) .pipe(gulp.dest('dist/static')) .pipe(reload({stream: true})) }) gulp.task('js:dev', function () { return gulp.src('src/js/*.js') .pipe(gulp.dest('dist/static')) .pipe(reload({stream: true})) }) gulp.task('tpl:dev', function () { return gulp.src('src/tpl/*.swig') .pipe(swig({ defaults: { cache: false // 此配置強制編譯文件不緩存 } })) .pipe(gulp.dest('dist')) .pipe(reload({stream: true})) })
這裏的reload
方法,咱們不須要過多瞭解,只要知道,經過執行它就能夠刷新瀏覽器。這裏的stream
用法能夠查閱官方文檔,這裏不重要因此不細講。
值得留意的是:這裏的
sass:dev
任務,咱們並無像sass
任務同樣配置編譯模式爲compressed,也就是不使用壓縮功能,爲何呢?事實上,咱們在開發的時候,並不須要壓縮靜態資源文件,能夠說咱們不在乎它的體積是大一點仍是小一點,咱們在乎的是樣式是否寫得符合指望,咱們在意的是功能是否實現,因此不須要啓用壓縮或者其餘的什麼優化功能,這樣能夠減輕編譯的負擔,加快編譯速度。若是你對js或者圖片也使用了壓縮功能,建議在開發模式下去掉,只在打包模式下使用。
最終咱們整理獲得一份gulpfile.js文件:
var gulp = require('gulp') var sass = require('gulp-sass') var swig = require('gulp-swig') var browserSync = require('browser-sync').create() var reload = browserSync.reload gulp.task('sass', function () { return gulp.src('src/sass/*.scss') .pipe(sass({ outputStyle: 'compressed' // 此配置使文件編譯並輸出壓縮過的文件 })) .pipe(gulp.dest('dist/static')) }) gulp.task('js', function () { return gulp.src('src/js/*.js') .pipe(gulp.dest('dist/static')) }) gulp.task('tpl', function () { return gulp.src('src/tpl/*.swig') .pipe(swig({ defaults: { cache: false // 此配置強制編譯文件不緩存 } })) .pipe(gulp.dest('dist')) }) gulp.task('sass:dev', function () { return gulp.src('src/sass/*.scss') .pipe(sass()) .pipe(gulp.dest('dist/static')) .pipe(reload({stream: true})) }) gulp.task('js:dev', function () { return gulp.src('src/js/*.js') .pipe(gulp.dest('dist/static')) .pipe(reload({stream: true})) }) gulp.task('tpl:dev', function () { return gulp.src('src/tpl/*.swig') .pipe(swig({ defaults: { cache: false // 此配置強制編譯文件不緩存 } })) .pipe(gulp.dest('dist')) .pipe(reload({stream: true})) }) gulp.task('dev', ['js:dev', 'sass:dev', 'tpl:dev'], function () { browserSync.init({ server: { baseDir: "./dist" }, notify: false }) gulp.watch('src/js/*.js', ['js:dev']) gulp.watch('src/sass/*.scss', ['sass:dev']) gulp.watch('src/tpl/*.swig', ['tpl:dev']) }) gulp.task('build', ['sass', 'js', 'tpl'])
嗯,完美,到這一步,咱們這個自動化構建已經基本完成了,並且還算是完整。如今,咱們開發的時候,就執行gulp dev,打包的時候就執行gulp build,是否是很方便?
注意:gulp dev任務啓動之後是一直保持工做狀態的,也就是它不像gulp build同樣一次性執行完,它是keep alive的,因此咱們若是要中止這個任務,須要手動按ctrl+c組合鍵,結束這個任務。
然而事情還沒完,咱們的目標是:裝逼 盡善盡美!
有三個地方其實咱們還沒作到位:
二話不說就開工!
第一點很好解決,咱們能夠把腳本做爲一項配置存放在package.json文件中:
{
"name": "project", "version": "1.0.0", "description": "a test project", "main": "index.js", "scripts": { "dev": "gulp dev", // 開發腳本 "build": "gulp build", // 打包腳本 "test": "node ./build/test.js" }, "author": "jack lo", "license": "ISC", "devDependencies": { "browser-sync": "^2.13.0", "gulp": "^3.9.1", "gulp-sass": "^2.3.2", "gulp-swig": "^0.8.0" } }
注意到了嗎?scripts項就是用來預約義腳本的地方,咱們能夠很方便地把腳本按照上面的形式封裝好,而後執行的方式就變成了:
npm run dev // 執行開發 npm run build // 執行打包
搞定!
咱們接着看第二點,刪除dist文件夾,多簡單的事啊!鼠標右鍵,刪除,搞定!
……
哪有這麼low的事,咱們的目標是:懶癌晚期 能不本身作的事情,毫不本身動手。
有一個叫作rimraf的包,能夠幫咱們作這事,咱們須要用到它的cli,因此跟gulp同樣,咱們全局安裝它:
npm install rimraf -g
安裝完後,咱們再從新修改一下package.json文件中的scripts內容:
{
"name": "project", "version": "1.0.0", "description": "a test project", "main": "index.js", "scripts": { "dev": "gulp dev", // 開發腳本 "build": "rimraf dist && gulp build", // 打包腳本 "test": "node ./build/test.js" }, "author": "jack lo", "license": "ISC", "devDependencies": { "browser-sync": "^2.13.0", "gulp": "^3.9.1", "gulp-sass": "^2.3.2", "gulp-swig": "^0.8.0" } }
ok,如今試試執行npm run build
,dist文件夾是否是先被刪除,而後再從新生成了?
完美。
第三點放到最後才補充,主要是考慮到它並非必要的,由於有些項目並不須要ftp上傳,通常是提交svn,而後再由後端或者運維去部署,筆者是須要將靜態資源上傳到cdn服務器進行加速的,因此須要這樣一個任務,在此咱們簡單介紹一下。
觸類旁通一下,咱們再建立一個upload任務:
var ftp = require('gulp-ftp') var gutil = require('gulp-util') gulp.task('upload', function () { return gulp.src('dist/**') .pipe(ftp({ host: '8.8.8.8', // 遠程主機ip port: 22, // 端口 user: 'username', // 賬號 pass: 'password', // 密碼 remotePath: '/project' // 上傳路徑,不存在則新建 })) .pipe(gutil.noop()) })
自行安裝一下gulp-ftp和gulp-util兩個包,而後在package.json文件中的scripts補充一個腳本npm run upload來執行gulp upload。
筆者一般都是打包以後順便上傳,命令行直接輸入npm run build && npm run upload,回車,而後就能夠愉快地去跟旁邊的妹紙聊天了。
到這裏,咱們已經完整搭完了這一套簡易自動化工具,好像講了不少東西,其實總結起來內容很是少:咱們只不過度別用三個小任務(sass、js、tpl),組成了build和dev這兩個大任務,僅此而已。
因爲時間和篇幅關係,咱們只簡單處理了css、js和html,事實上,你還能夠在這個基礎上繼續完善下去,js能夠由coffeejs編譯獲得,並且還能夠繼續壓縮,甚至能夠把所有js文件合併成一個!html也同樣能夠繼續壓縮。並且,你徹底能夠本身建立一個任務去處理其餘諸如圖片、字體等等。
本次演示項目的git地址:gulp_base