前端入门->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更没坏处

相关文章
相关标签/搜索