使用 Make 構建網站

jopen 9年前發布 | 12K 次閱讀 Make 項目構建

原文  http://www.ruanyifeng.com/blog/2015/03/build-website-with-make.html


網站開發正變得越來越專業,涉及到各種各樣的工具和流程,迫切需要構建自動化。

所謂"構建自動化",就是指使用構建工具,自動實現"從源碼到網頁"的開發流程。這有利于提高開發效率、改善代碼質量。

本文介紹如何使用make命令,作為網站的構建工具。以下內容既是make語法的實例,也是網站構建的實戰教程。你完全可以將代碼略作修改,拷貝到自己的項目。

使用 Make 構建網站

(題圖:國家考古博物館,西班牙,攝于2014年8月)

一、Make的優點

首先解釋一下,為什么要用Make。

目前,網站項目(尤其是Node.js項目)有三種構建方案。

我覺得,make是大型項目的首選方案。npm run可以認為是make的簡化形式,只適用于簡單項目,而Grunt、Gulp那樣的工具,有很多問題。

(1)插件問題

Grunt和Gulp的操作,都由插件完成。即使是文件改名這樣簡單的任務,都要寫插件,相當麻煩。而Make是直接調用命令行,根本不用擔心找不到插件。

(2)兼容性問題

插件的版本,必須與Grunt和Gulp的版本匹配,還必須與對應的命令行程序匹配。比如, grunt-contrib-jshint插件 現在是0.11.0版,對應Grunt 0.4.5版和JSHint 2.6.0版。萬一Grunt和JSHint升級,而插件沒有升級,就有可能出現兼容性問題。Make是直接調用JSHint,不存在這個問題。

(3)語法問題

Grunt和Gulp都有自己的語法,并不容易學,尤其是Grunt,語法很羅嗦,很難一眼看出來代碼的意圖。當然,make也不容易學,但它有復用性,學會了還可以用在其他場合。

(4)功能問題

make已經使用了幾十年,全世界無數的大項目都用它構建,早就證明非常可靠,各種情況都有辦法解決,前人累積的經驗和資料也非常豐富。相比之下,Grunt和Gulp的歷史都不長,使用范圍有限,目前還沒有出現它們能做、而make做不到的任務。

基于以上理由,我看好make。

二、常見的構建任務

下面是一些常見的網站構建任務。

  • 檢查語法
  • 編譯模板
  • 轉碼
  • 合并
  • 壓縮
  • 測試
  • 刪除

這些任務用到 JSHinthandlebarsCoffeeScriptuglifyjsmocha 等工具。對應的package.json文件如下。

"devDependencies": {
  "coffee-script": "~1.9.1",
  "handlebars": "~3.0.0",
  "jshint": "^2.6.3",
  "mocha": "~2.2.1",
  "uglify-js": "~2.4.17"
}

我們來看看,Make 命令怎么完成這些構建任務。

三、Makefile的通用配置

開始構建之前,要編寫Makefile文件。它是make命令的配置文件。所有任務的構建規則,都寫在這個文件(參見《Make 命令教程》)。

首先,寫入兩行通用配置。

PATH  := node_modules/.bin:$(PATH)
SHELL := /bin/bash

上面代碼的PATH和SHELL都是BASH變量。它們被重新賦值。

PATH變量重新賦值為,優先在 node modules/.bin 目錄尋找命令。這是因為(當前項目的)node模塊,會在 node modules/.bin 目錄設置一個符號鏈接。PATH變量指向這個目錄以后,調用各種命令就不用寫路徑了。比如,調用JSHint,就不用寫 ~/node_modules/.bin/jshint ,只寫 jshint 就行了。

SHELL變量指定構建環境使用BASH。

四、檢查語法錯誤

第一個任務是,檢查源碼有沒有語法錯誤。

js_files = $(shell find ./lib -name '*.js')

lint: $(js_files) jshint $?</pre>

上面代碼中,shell函數調用find命令,找出lib目錄下所有js文件,保存在變量js_files。然后,就可以用jshint檢查這些文件。

使用時調用下面的命令。

$ make lint

五、模板編譯

第二個任務是編譯模板。假定模板都在templates目錄,需要編譯為build目錄下的templates.js文件。

build/templates.js: templates/*.handlebars mkdir -p $(dir $@)
    handlebars templates/*.handlebars > $@ template: build/templates.js

上面代碼查看build目錄是否存在,如果不存在就新建一個。dir函數用于取出構建目標的路徑名(build),內置變量$@代表構建目標(build/templates.js)。

使用時調用下面的命令。

$ make template

六、Coffee腳本轉碼

第三個任務是,將CofferScript腳本轉為JavaScript腳本。

source_files := $(wildcard lib/*.coffee)
build_files  := $(source_files:lib/%.coffee=build/%.js)

build/%.js: lib/%.coffee coffee -co $(dir <span>$@</span>) $< coffee: $(build_files)</pre>

上面代碼中,首先獲取所有的Coffee腳本文件,存放在變量source files,函數wildcard用來擴展通配符。然后,將變量source files中的coffee文件名,替換成js文件名,即 lib/x.coffee 替換成 build/x.js 。

使用時調用下面的命令。

$ make coffee

七、合并文件

使用cat命令,合并多個文件。

JS_FILES := $(wildcard build/*.js)
OUTPUT := build/bundle.js

concat: $(JS_FILES) cat $^ > $(OUTPUT) </span></pre>

使用時調用下面的命令。

$ make concat

八、壓縮JavaScript腳本

將所有JavaScript腳本,壓縮為build目錄下的app.js。

app_bundle := build/app.js $(app_bundle): $(build_files) $(template_js)
    uglifyjs -cmo $@ $^ min: $(app_bundle)

使用時調用下面的命令。

$ make min

還有另一種寫法,可以另行指定壓縮工具。

UGLIFY ?= uglify $(app_bundle): $(build_files) $(template_js) $(UGLIFY) -cmo $@ $^ 

上面代碼將壓縮工具uglify放在變量UGLIFY。注意,變量的賦值符是 ?= ,表示這個變量可以被命令行參數覆蓋。

調用時這樣寫。

$ make UGLIFY=node_modules/.bin/jsmin min

上面代碼,將jsmin命令給變量UGLIFY,壓縮時就會使用jsmin命令。

九、刪除臨時文件

構建結束前,刪除所有臨時文件。

clean:
    rm -rf build

使用時調用下面的命令。

$ make clean

十、測試

假定測試工具是mocha,所有測試用例放在test目錄下。

test: $(app_bundle) $(test_js)
    mocha

當腳本和測試用例都存在,上面代碼就會執行mocha。

使用時調用下面的命令。

$ make test

十一、多任務執行

構建過程需要一次性執行多個任務,可以指定一個多任務目標。

build: template concat min clean 

上面代碼將build指定為執行模板編譯、文件合并、腳本壓縮、刪除臨時文件四個任務。

使用時調用下面的命令。

$ make build

如果這行規則在Makefile的最前面,執行時可以省略目標名。

$ make

通常情況下,make一次執行一個任務。如果任務都是獨立的,互相沒有依賴關系,可以用參數 -j 指定同時執行多個任務。

$ make -j build

十二、聲明偽文件

最后,為了防止目標名與現有文件沖突,顯式聲明哪些目標是偽文件。

.PHONY: lint template coffee concat min test clean build

十三、Makefile文件示例

下面是兩個簡單的Makefile文件,用來補充make命令的其他構建任務。

實例一。

PROJECT = "My Fancy Node.js project"
all: install test server
test: ;@echo "Testing ${PROJECT}....."; \
  export NODE_PATH=.; \
  ./node_modules/mocha/bin/mocha;
install: ;@echo "Installing ${PROJECT}....."; \
  npm install
update: ;@echo "Updating ${PROJECT}....."; \
  git pull --rebase; \
  npm install
clean : ;
  rm -rf node_modules
.PHONY: test server install clean update

實例二。

all: build-js build-css

build-js: browserify -t brfs src/app.js > site/app.js

build-css: stylus src/style.styl > site/style.css

.PHONY build-js build-css</pre>

十四、參考鏈接

(完)

</div> </div>

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!