前端入門->makefile

我第一次見到makefile的時候,是在看js測試的那一塊。簡直,一開始跟風,以爲makefile這麼牛逼,我也想看看。 首先,看了陳老師的跟我一塊兒學習Makefile. 打開了第一章以後,後面就沒有勇氣再打開下去了。 後來瞭解了一下makefile原來是C語言做爲工程化處理的一個必殺技。而後就遷移到其餘平臺上了,可是對於咱們這種,對於C的認知度爲(0)的人,這不是難爲咱們嗎?後來,就在網上游蕩,慢慢找,仍是有點入門的感受,這裏,我想把,一些感悟分享給你們,若是有用,您就拿去,沒用的話,ctrl+w就over了。php

知識 = 學習 + 分享前端

makefile的基本淺析

前端學習makefile的成本仍是蠻大的誒~ 由於好多教程都是用c寫的,這也沒辦法,誰讓這是C的工具,咱們也只是偷師學學。
makefile的基本格式爲:node

target: prerequisities
[TAB]command

target就是你要執行的命令套件,prerequisties就是依賴,而command就是實際執行的命令。(說人話)
上栗子:es6

create: 
    touch newMake.js

makefile的解析的過程:shell

首先makefile會讀取你的makefile文件.
讀取指定的target.
解析後面的依賴是否更新
若是更新則執行command
沒有則do nothing

因爲咱們這裏後面沒有什麼參數,因此,make會直接執行對應的命令。 而後執行:npm

make create

接着你會發現,在當前目錄下(makefile文件夾下)。會生成一個 newMake.js的文件。這時候就說明你已經成功的入門了makefile了.gulp

基本命令

註釋

在makefile中,一般能夠用"#"標識來做爲註釋.ubuntu

run:
        touch a.js #create js file
del:
        rm a.js #delete js file

回聲

在php中有個輸出API echo, 和這個相似,在make中,它會自動打印命令,而後才執行。vim

//makefile
run:
        touch a.js #create js file
//執行make
make run
//結果:
touch a.js #create js file
//這時候,他便會建立a.js文件

固然若是你不想讓make打印出來,能夠在首行加上"@"表示取消回聲.編輯器

run:
        @touch a.js #create js file

以後,你再使用make run。他便不會打印出什麼東西了。

自動變量

$@指代當前構建的目標。 怎麼說呢?

show me the code

a.js b.js:
    touch $@
//等價於:
a.js b.js:
    touch a.js b.js;
//也等價於:
a.js:
    touch a.js;
b.js: 
    touch b.js

這裏至關於你定義了兩個命令(雖然,看起來像一個)
$<指代第一個依賴的條件。(這些都是什麼flag呀~ 寶寶看不懂)
咱們來看一下例子吧:

create:a.js b.js
    touch $<
//等價於
create:a.js b.js
    touch a.js

還有$^指代全部的依賴條件。makefile裏面有不少automatic variable 這裏只列一些比較經常使用的。

變量的使用:

在寫nodeJS測試的時候,變量的做用 super well.
一般咱們須要從node_modules中,引出指定的.bin包。 通常而言就是mocha和istanbul.
使用命令:

npm install mocha istanbul --save-dev

還記得,咱們在運行測試的時候的命令嗎?

istanbul cover _mocha

因爲系統已經把環境變量給配置好了,你執行上面的命令的時候,其實,shell已經從全局中把對應的bin文件提取出來,而且執行了。
而在makefile中,就須要你手動執行進行路徑的配置了.
舉個例子吧,如今咱們處在和node_modules同目錄下。
而後引入mocha和istanbul的路徑,並存入變量中:

MOCHA=./node_modules/.bin/mocha
ISTANBUL=./node_modules/.bin/istanbul

OK,這樣就夠了。 有的同窗,可能會發現node_modules下並無.bin文件夾呀~ 親莫急。你可使用ls -a來查看全部的。相信你必定能找到的。
如今咱們已經定義了變量,接下來要作的就是引用定義的變量了。
在makefile中,使用$(...)進行相關的定義。
像這樣:

MOCHA=./node_modules/.bin/mocha
ISTANBUL=./node_modules/.bin/istanbul
_MOCHA=./node_modules/.bin/_mocha
runTest:
        $(ISTANBUL) cover $(_MOCHA)

而後在另一個zsh中執行:

make runTest;

就能夠達到和istanbul cover _mocha同樣的效果了.
在makefile裏面,變量分爲兩種:

引用式變量

若是es6和commonJS的同窗應該知道,在模塊的書寫上,二者都有本身的一套實現原理。 而es6的實現原理就和引用變量同樣的,即,相互引用的模塊,會持續影響到對方。
舉個栗子唄:

A=$(B);
    B=$(C);
    C=quote

當在編輯器解析時,會有如下的結果:

A=quote;
B=quote;
C=quote;

這樣,其實並無什麼很差,可是若是你不當心寫成了一個死循環,呵呵,你電腦也就崩了。像這樣的:

A=$(B)
B=$(A)

這樣解析器會一直這樣,不斷的解析,只到你的資源被eat up. 而後你就能夠關機重啓了。

直接展開式變量

這個就是用來解決上述問題的。使用的賦值符號不在是=而變成了:=. 看個例子吧:

A=good
B:=$(A) job
A=stupid

最終的解析結果爲:
B=good job
A=stupid
爲何呢? 由於使用":="的使用,他會當即尋找上文引用到的最近的變量,而後放入B中,這時候B的值就已經固定了。若是你後面再去修改A的值是沒有意義的。
若是使用引用變量的話,會有這樣的結果:

A=good
B=$(A) job
A=bad

最後輸出:
B=bad job
A=bad
就是醬汁,你們瞭解就over了。
其實,大部分時候我仍是會選擇引用變量的,由於簡單,靈活性更大。 而直接展開式變量一般寫給leader看的,你們注意一下就沒什麼問題了。
另外變量的定義一共有四種方法

VARIABLE = value
# 在執行時擴展,容許遞歸擴展。

VARIABLE := value
# 在定義時擴展。

VARIABLE ?= value
# 只有在該變量爲空時才設置值。

VARIABLE += value
# 將值追加到變量的尾端。

因爲剩下兩種使用的頻率不是很高,這裏也就不贅述了。

僞目標

一門深邃的語言,首先必需要有一個裝逼的名字。僞目標這個名字好,能一眼讓你不知道他根本是幹什麼的。
意淫完畢~
其實,僞目標就是爲了解決命令和文件名衝突的。
好比,個人makefile是這樣書寫的

clean:
        rm *.jpg
create:
        touch clean

首先,我執行make clean,他會徹底的刪除當前目錄下的jpg文件。
而後我運行make create 生成一個clean文件。可是當我再次使用make clean的時候。 執行的效果並非我預期的那樣,提示jpg文件不存在。而是提示:

make: `clean' is up to date.

那麼問題來了: 是你傻逼,仍是電腦傻逼?
你: 確定是電腦傻逼.
電腦: xxx&&*%^^^^%. 好吧.爲了給你點信心學下去,是我傻逼

這裏,涉及到了GUN make的一條tip: 隱含規則
因爲這個隱含規則主要是針對於C語言的童鞋的。這裏,做爲前端的寶寶,咱們瞭解一下就能夠了。

隱含規則就是指一些約定俗成語句能夠不須要寫出來,make能夠本身去推測,而且執行。(因爲隱含規則大部分是針對C的,我這裏就不列了)。
這樣,像上文同樣,make clean 會首先查找隱含文件,檢查clean的文件,因爲已經存在clean文件,這裏會被認爲是最新的,就不會去執行定義的規則了。(你們若是有興趣能夠去翻閱一下詳細資料). 另外,我以爲這樣咱們前端去理解這個,這是要上天呀~~~ 說白了,就是,若是你的文件下,有和命令同名的文件的話,你的命令是不會被執行的。
因此,咱們須要僞命令,來解決這一衝突.
使用.PHONY:來進行定義:
在makefile中,咱們加上一句:

.PHONY: clean

而後繼續執行make clean
這樣,他就能正常的執行你所定義的command了。
一般狀況下,咱們須要把本身寫的命令都在.PHONY裏面過一遍,有備無患吧~

依賴設置

還記得make的基本格式麼? 就是

target:prerequisties
[TAB]command

沒錯,細心的童鞋會發現,我上面都沒有帶上prerequisties。
這是爲何呢?爲何呢?爲何呢?
由於簡單唄~
那,若是帶上以後會發什麼呢? 若是瞭解gulp的同窗應該知道。gulp.task('name',dependency);
它接收3個參數,這裏咱們着重講解一下第二個--dependency. 當你運行name的時候,他會在context中尋找指定的命令,而後執行.

gulp.task('default', ['sync', 'watch'],function(){
    //...
});
gulp.task('watch', function() {
    //...
});
gulp.task('sync', function() {
    //...
});

當你運行gulp default或者gulp的時候,他會尋找watch和sync命令而且執行,而後在執行default自帶的fn。
同理,makefile也是這樣作的。
好比你有個命令是這樣的:

testDemo:
        mocha 'test/test.js'
testNest:testDemo
        mocha 'test/nested/test1.js'

當你指定make testNest的時候,執行順序會testDemo-> testNest
OK,就是這樣,到後面,你測試的用例越多,組合就會月複雜,這時候加點註釋是頗有必要的。

實例講解

上面的基本知識點已經差很少梳理完了,固然,這僅僅只是makefile的冰山一角,可是對於前端寶寶們來講,已經滿足了。這裏,上個栗子來吃吃。

ISTANBUL=./node_modules/.bin/istanbul
_MOCHA=./node_modules/.bin/_mocha
MOCHA=./node_modules/.bin/mocha
OPTS:=--recursive --reporter nyan --watch
test:
        @$(MOCHA) $(OPTS)
cover:
        $(ISTANBUL) cover $(_MOCHA) -- $(OPTS)
testDemo:
        $(MOCHA) 'test/test.js'
testNest:testDemo
        $(MOCHA) 'test/nested/test1.js'
.PHONY:test cover testDemo testNest

這是,我在測試js文件時候所用到的一個基本的makefile文件。上面包含了上述所說的知識點~由於makefile有這樣一個方便易上手的能力,讓其餘領域的開發者,爭相獻上膝蓋~(GUN make請拿好個人膝蓋)

最後說兩句

前端懂makefile沒壞處寫好makefile更沒壞處

相關文章
相關標籤/搜索