Makefile构建前端项目
Make是GNU下的构建自动化工具,用于从源文件构建可执行程序和程序库。 由Makefile定义构建依赖关系,运行Make时这些依赖会递归地展开。 可以说Make和Shell是Linux下生存的必备技能,当然还需要一款你热爱的编辑器。
Make还会检查文件修改时间来判断是否需要执行某条依赖。 因此除了程序库外,Make也常常用于自动更新存在文件间依赖的项目。 比如:批量更新网站缩略图
Harttle曾使用过上百个Grunt/Gulp插件,尝试着去体会它们所承诺的那些优雅。 而今Harttle决定重新回到Make的怀抱,在前端为什么需要构建工具? 一文中详述了这一选择的全部理由。
Make能否满足前端的构建需求?
make是通用构建工具,能满足一切构建需求。
而且比其他任何构建工具都更高效和简洁,下文中Harttle将从实际需求出发来证实这一点。
合并文件
是不是有一个叫做grunt-contrib-concat的Grunt插件? 是不是有一个叫做gulp-concat的Gulp插件? 它们有着相当的代码和文档,每月数百万的下载量。 下面的代码足以让你怀疑这一切的必要性:
out.js: src/*.js
cat $^ > $@
如果你不了解上述代码的确切含义,Harttle推荐这篇文章:Makefile 入门
make与Unix STDIN/STDOUT有着天然的亲和, 上述代码甚至比grunt-contrib-concat的配置还简洁。
拷贝文件
拷贝文件仍然不许任何插件,但支持通配:
build/foo.js: src/foo.js
除了合并文件外,make还会检查文件的修改日期以避免不必要的重复构建。
压缩静态文件
dist/out.min.js: out.js lib/jquery.js
@mkdir -p $(@D)
uglifyjs $? >> $@
这个
$(@D)
自动化变量确实费解不过挺有用,它指目标文件所在目录。 这里有全部22个自动化变量的文档。
首先创建目标目录所在目录(即/dist
),然后只将比目标新的依赖($?
)压缩,
追加到目标文件(dist/out.min.js
)中。
最后一条命令如果是uglifyjs $^ > $@
同样可行,只是会多处理一些文件。
从这里可以看到Make在表达更多逻辑的同时并未增加代码量。
批量处理
在JavaScript世界中我们通过Glob来批量选择文件,在Make中则需要借助于Shell通配符和命令。
SOURCES = src/*.js
# 或者干脆find
# SOURCES = $(shell find ./src \
# ! -name "*.md" \
# ! -name "*.log")
# 生成目标列表
TARGETS = $(SOURCES:src/%=build/%)
$(TARGETS): build/%: src/%
cp $< $@
%
的用法称为静态模式,用来定义批量的依赖规则。
上述代码的意图是将src/
下的源文件拷贝到build/
下。
强制执行
Make默认会检查文件的新旧,这会导致有时我们运行make
相关的命令并未执行,
例如:
build: foo
cp foo build/bar
连续两次执行make out.js
,第二次执行时make发现当前的build/
文件夹比foo
要新,
于是不执行任何操作。但我们的build
指的并非文件夹而是构建的语义,
我们可以将build
设置为伪目标来禁止Make的文件检查,clean
是一个更常见的伪目标:
.PHONY build clean
build: foo
cp foo build/bar
clean:
rm -rf build
替换静态资源
因为在Web站点发布后需要使用与源码中不同的静态资源地址,
通常是经过合并压缩,并且CDN化的。
这意味着要找出所有HMTL中对JavaScript的引用,并将其替换为生产环境脚本
(比如叫site.min.js
)。
如果你配置过类似usemin这样的工具,可能会发现这里面巨大的坑。 我们用一段Shell脚本来简单实现一下:
VIEWS = $(shell find src/views -name "*.html")
VIEW_OBJS = $(VIEWS:src/%=build/%)
JS = $(shell cat $(VIEWS) | grep '<script ' | awk -F '"' '{print substr($$2,2)}')
JS_TAG = <script src="\/static\/site.min.js"><\/script>
static/site.min.js: $(JS)
cat $^ > $@
$(VIEW_OBJS): build/%: src/%
grep -vE '<script ' $< | \
sed 's/<\/body>/$(JS_TAG)<\/body>/' > $@
由于Make中
$
有特殊的含义,$$2
是转义后的$2
。
VIEWS
保存HTML源码列表,而VIEW_OBJS
保存构建后的HTML源码列表。JS
变量中保存着所有被引用到的脚本列表,我们需要这个列表来生成site.min.js
。- 生成
$(VIEW_OBJS)
的逻辑是:先移除所有的<script>
标签,再在<body>
尾添加site.min.js
。
生成MD5
对于MD5我们需要的只是cksum
工具,而它在1995年就进入了BSD Unix。
几乎所有的Linux和Mac都可用。下面这段脚本用来生成CSS/JS的MD5并写入.manifest
:
DIST := ./assets/
$(DIST)/.manifest: $(shell find $(DIST) -type f -name '*.css' -or -name '*.js')
find $(DIST) -type f -exec cksum {} \; | sed -e "s#$(DIST)/##" | cut -f1,3 -d" " > $@
这段脚本来自于:https://www.sitepoint.com/using-gnu-make-front-end-development-build-tool/
本文采用 知识共享署名 4.0 国际许可协议(CC-BY 4.0)进行许可,转载注明来源即可: https://harttle.land/2016/09/21/make-frontend.html。如有疏漏、谬误、侵权请通过评论或 邮件 指出。