前端自動化工具
大綱
• Node.Js
• 套件安裝工具: NPM & Bower
• Gulp
• WebPack
Node.Js
• Node.js本身就是伺服器端的JavaScript引擎!
• 主要特性:
• 採用Chrome的JavaScript runtime(V8)
• 可快速開發高延展性的Web Application
• 其開發皆採用Event-Driven 且 non-blocking I/O
• 高度社群支援,現將推出與IO.js合併的分支版本v4
• 跨平台
• 採用CommonJs標準
NPM(Node.js Package Manager)
• NPM本身是一個公開的套件資料庫(npm public registry)
• 主要是用來共享node.js的程式碼
• 主要以套件(Package)或模組(Module)做封裝
• NPM是一套Node.js的套件管理工具
• 用來搜尋、安裝、更新、移除、發行NPM套件的工具
• 管理套件與套件之間的相依性
Node.js的套件很多
Node.js套件的定義
• 套件的組成:
• 一個資料夾(Folder)
• 資料夾中有個package.json檔案
• 用來定義套件的名稱、版本與相關資訊
• 用來定義套件中還有使用到那些其它相依的套件
• 資料夾中有一堆自訂的檔案與其它資料夾
• 專案的組成(也是一個資料夾)
• 透過NPM安裝的套件
• 你自己寫好的程式碼與其它檔案
• 專案本身也可以變成套件
• 可發佈到NPM Public Registry變成公開的套件
NPM常用指令
• 搜尋套件
• npm search [package_namegit url]
• 安裝套件
• 局域: npm install [package_name1] [package_name2] ..
• 全域: npm install –g [package_name1] [package_name2] ..
• 安裝全域的套件會在指定的目錄底下:
• Windows: %APPDATA%npmnode_modules
• OS X: /usr/local/lib/node_modules
• 查詢NPM套件儲存位置: npm config get prefix
• 自動安裝package.json中所定義的所有套件:
• npm install
• 紀錄套件到package.json
• npm install [package_name] –save
• npm install [package_name] –save-dev
Package.json檔案
• 為一純json格式的檔案(註: 它不是js檔案)
• 必要欄位: name 和 version
{
name : “Arthur”,
version : “1.0.0”,
description : “”,
main : “index.js”,
author: “Arthur email@add.ress (https://xxx.xxx)”
}
• 可以使用npm init或npm init –y快速初始化package.json檔
• Package.json不能使用UTF-8 with BOM編碼儲存
套件符號表示法
• ^ : 相容於特定版本
• 1.2.x : 直接指定相容的1.2.X版本
• ~ : 大概等於指定版本
• > : 永遠取得最新版本
• >= : 大於等於特定版本
• <= : 小於等於特定版本
Bower
• 也是一個套件管理工具 - 針對前端套件
• NPM使用package.json紀錄套件資訊;Bower採用bower.json
• Bower本身也是使用Node.js所寫成的,所以需要使用NPM進行全域
安裝:
• npm install –g bower
• Bower本身支援採用git url方式去下載套件,所以在使用bower指令
前,需要先安裝好git並且將git加入環境變數中(env_var)
Bower基本操作
• 安裝套件
• bower install [package_name  git url] 安裝最新版本
• bower install [package_name]#1.11.3 安裝特定版本
• bower info [package_name] 查詢所有可安裝版本
• 更新套件
• bower update
• 建立bower.json檔案
• bower init
可以使用.bowerrc微調Bower設定
• 可手動在專案資料夾中建立.bowerrc檔案
• 常用的屬性設定:
• Diretory : 指定bower套件預設安裝路徑
• cwd : bower工具執行時的工作目錄路徑
• Registry : 指定bower線上資料庫(Registry)位址(Url)
• Timeout : 指定bower執行時的timeout時間(預設為60000ms)
Bower與NPM的差別
• NPM
• Node.js套件管理工具
• 每個套件會自我管理與其它套件之間的相依性
• 自我管理套件相依性會以樹狀結構各自展開
• 由於各自套件會自動安裝各自的相依性套件,因此很占空間
• Node.js(伺服器端Js)沒有Js檔案太大的問題
• Bower
• 前端套件管理工具
• 每個套件會自我管理與其它套件之間的相依性
• 自我管理套件相依性會以扁平結構各自展開
Gulp
• 用於改善前端工作流程,將工作自動化的工具
• 主要特性
• 易於使用 - 以程式碼取代組態檔案
• 效能佳 – 採用Node.js中的stream機制和Pipeline流程
• 高品質 – 每個Registry中的套件都經過嚴格審查
• 易學 – 只懂一點點Node.js就可以
Gulp到底是有多簡單?
• 四個API:
• 定義工作(task)
• gulp.task(name[, deps], fn)
• 定義檔案讀取來源(src)
• gulp.src(globs[ , options])
• 定義檔案寫入的目的地(dest)
• gulp.dest(path[ , options])
• 即時監視檔案變更(watch)
• gulp.watch(glob [, opts], tasks)
• gulp.watch(glob [, opts, callbackFn])
實務的例子
建置任務
• gulp.task(name,[,deps], callback)
• 例1:
gulp.task(‘uglifyScript’,function(){ //處理Js});
• 例2:
gulp.task(‘build’,[‘uglifyScript’],function(){//處理編譯});
• 任務之間可以設置相依性。
• Gulp在底層仍是使用node.js在處理檔案方面的非同步API;因此,當
任務之間有相依性時,很有可能因為非同步處理的是相同的檔案而
造成錯誤。(註: 有時成功有時失敗)
讀取檔案
• gulp.src(globs,[,opt]);
• glob是node.js所使用一種檔案路徑表示法,其功用主要是在以一個
字串同時描述多個檔案的檔案路徑。
• 例: ‘’assets/js/**/*.js“ => assets/js/底下所有副檔名為js的檔案
• 例: !‘’assets/js/**/*.ts“ => 排除assets/js/底下所有副檔名為ts的檔案
• 例: [‘’assets/js/**/*.js“ , !‘’assets/js/vendor/**/*.js“ ] => 取得assets/js/底下
所有的js檔案,但是請排除assets/js/vendor/中的
• gulp.src會將讀取的所有檔案以串流(Stream)的方式處理,可以在其
後以pipe方法接續這些檔案串流的處理:
• gulp.src( ’assets/js/**/*.js“ ,function(){//do})
.pipe(gulp.dest(‘~路徑~’));
寫入檔案
• gulp.dest(path,[,opt]);
• 通常是在所有的處理都結束之後才會呼叫到這個方法將成果寫入
成為檔案。
• Gulp.dest的第一個參數並非是使用globs,而是資料夾相對路徑。
• 例: gulp.src(’assets/js/**/*.ts“)
.pipe(typescript())
.pipe(gulp.dest(‘./build/js’))
.pipe(uglify())
.pipe(gulp.dest(‘./CdnContent/js’));
監控檔案
• gulp.watch(globs,[,dep],function(){ //do something});
• 當監控的檔案在變更且儲存檔案後,就會觸發。
• 通常用在撰寫高階的Js/Html/Css語言,例如: TypeScript/Jade/SCSS時,
會很需要用到這個功能,而一般前端CI流程倒不一定非用到不可。
實務範例
• 以npm安裝所需要的模組
• 創建一個gulpfile.js(名字要對)
• 在gulpfile.js開頭宣告並引入所有需要的模組
• 註冊所需要的任務
Gulp的錯誤處理
• Gulp天生是非同步I/O串流的
檔案操作模式,但不同步驟的
處理是啟用不同的串流
• Stream-combiner套件可將多
個步驟強制使用同一個串流,
如此一來僅需要傾聽一個錯誤
訊息事件。
Gulp V.S. Grunt
Grunt Gulp
特性 • File-based
• Configuration over code
• 檔案處理都是呼叫Node.js的同步API
• 串流-based
• Code over configuration
• 檔案處理都是呼叫Node.js的非同步API
優點 • 發展較早,因此支援的模組較多
• 跨平台
• 易學易用(CP值高)
• 速度較快
• 跨平台
缺點 • 需要編寫較多的設定,入門不易
• File Read/Write頻繁導致檔案數變大
時,會造成效能低落
• 要留意非同步API的弊病
WebPack
• 管理模組相依性的工具
• 其模組包含: html/js/coffe/css/less/png/web fonts….
• 透過產生靜態檔案來代表這些相依的模組
先別管WebPack了,你聽過CommonJs和AMD
嗎?
• CommonJS
• 大多用在Node.js環境
• 採用”同步”的方式載入相依模組
• 可設定module.exports的值來決定對外公開的物件
• 可設定exports變數的屬性值來決定對外公開的物件
• AMD(Asynchronous Module Definition)
• 大多用在瀏覽器環境
• 採用”非同步”的方式載入相依模組
• 備註:
• AMD是一份API規格
• 而RequireJS是實作AMD出來的一個函式庫
CommonJs範例
AMD範例
遺憾….
• 無論CommonJs再怎麼完美,但是瀏覽器就是不支援!
• 如果有一個工具能讓我們自由混搭CommonJs和AMD寫法呢?
再回來WebPack一下
• 在前端開發時,最討厭的就是:
• 要小心Js的載入順序
• 不要注意不要讓Browser開太多連線來要求資源
• 資源擺在前還是後都有講究
• 要做到Load on Demand很麻煩
• WebPacka是怎麼解決上述問題:
• 把所有資源都包裝成模組
• 在Js中決定什麼時候載入那些模組
WebPack的四個元素
Bundle
PlugIn
Loader
Code
Splitting
Bundle
• 過去的問題
• 一次性載入所有需要的資源 – 太耗頻寬
• 個別載入資源 - 開太多Http連線
• WebPack你怎麼做?
• 把資源分組成為多個區塊(Chunk)
Loader
• 原本的前端世界
• Js / Css / Html
• 現在的前端世界
• Sass / Scss / Less / coffeScript / typescript / jade …..
• 一堆自動化工具(Gulp / Grunt)幫你回到原本的前端世界
• WebPack你能做什麼?
• Gulp / Grunt用程式,WebPack用組態設定Loader運作順序
• Loader可以使用?代入參數
PlugIn
• WebPack可以使用PlugIn提供編譯的額外處理
• 當WebPack編譯的過程中,可以藉由PlugIn注入額外的處理功能
Code Splitting
• CommonJs方式:
• require.ensure([“a”], function(require) {
var a = require(“a”)
});
• 等待a模組載入之後,才會呼叫CallBack方法(a模組只是載入還沒引入)
• AMD方式:
• require([“a”, “b”], function(a, b){
// …
});

前端自動化工具