Google Bazel构建工具可以轻松解释特定目录树中的每个CoffeeScript文件是否需要编译为相应的输出JavaScript文件:
# Runs "coffee" 100 times if there are 100 files:
# will run slowly if most of them need rebuilding.
[genrule(
name = 'compile-' + f,
srcs = [f],
outs = [f.replace('src/', 'static/').replace('.coffee', '.js')],
cmd = 'coffee --compile --map --output $$(dirname $@) $<',
) for f in glob(['src/**/*.coffee'])]
但是,如果给出100个CoffeeScript文件,这将分别调用咖啡工具100,为编译过程增加了几秒钟。
或者,这可以写成一个命令,它将100个文件作为输入并产生100个文件作为输出:
# Runs "coffee" once on all the files:
# very slow in the case that only 1 file was edited.
coffee_files = glob(['src/**/*.coffee'])
genrule(
name = 'compile-coffee-files',
srcs = coffee_files,
outs = [f.replace('src/', 'static/').replace('.coffee', '.js') for f in coffee_files],
cmd = 'coffee --compile --map --output @D $(SRCS)',
)
有没有办法向Bazel解释咖啡可以同时用多个文件调用,如果N个目标已经过时,那么只有N个源文件应该提供给coffee
命令,而不是所有目标的完整列表,是否需要重建?
答案 0 :(得分:4)
coffeescript文件是否彼此独立?如果第一个工作,每个文件分别通过coffee
运行,那么它似乎是这样。在这种情况下,第一个实际上会给你最大的并行性和增量性。
即使运行100次咖啡比使用100个文件运行咖啡要慢一些,您只需在第一次编译所有内容时支付该费用。当您更改1个文件时,将不会重新编译其他99个文件。但是,如果coffee
的启动时间非常长,以至于100个文件实际上可以忽略不计,那么您可以坚持将它们全部编译成一个大的genrule。
在两个极端之间妥协的一种方法是创建一个宏:http://bazel.io/docs/skylark/macros.html
def compile_coffee(name, srcs):
native.genrule(
name = name,
srcs = srcs,
outs = [f.replace('src/', 'static/').replace('.coffee', '.js') for f in srcs],
cmd = 'coffee --compile --map --output @D $(SRCS)',
)
然后您可以在构建文件中使用compile_coffee
宏,将构建组织到适当大小的目标中:
load("//pkg/path/to:coffee.bzl", "compile_coffee")
compile_coffee(
name = "lib",
srcs = glob(["*.coffee"]))
还有完整的云雀规则:http://bazel.io/docs/skylark/rules.html但如果咖啡脚本文件并不真正相互依赖,那么这可能不是必需的。
还有持久的工作人员:http://bazel.io/blog/2015/12/10/java-workers.html,它允许你保持一个正在运行的咖啡实例,这样你就不必支付启动成本,但二进制文件必须表现良好,并且有点更多的投资是因为您通常必须编写包装以便连接所有内容。
答案 1 :(得分:0)
这会一次将20个文件传递给CoffeeScript编译器:
BUILD
:
load(":myrules.bzl", "coffeescript")
coffee_files = glob(["src/*.coffee"])
# 'coffeescript' is a macro, but it will make a target named 'main'
coffeescript(
name = "main",
srcs = coffee_files
)
myrules.bzl
:
def _chunks(l, n):
n = max(1, n)
return [l[i:i+n] for i in range(0, len(l), n)]
def coffeescript(name, srcs):
i = 0
all_outs = []
for chunk in _chunks(srcs, 20):
chunk_name = "{}-{}".format(name, i)
outs = [f.replace('src/', 'static/').replace('.coffee', '.js') for f in chunk] + \
[f.replace('src/', 'static/').replace('.coffee', '.js.map') for f in chunk]
all_outs += outs
native.genrule(
name = chunk_name,
srcs = chunk,
outs = outs,
cmd = "coffee --compile --map --output $(@D)/static $(SRCS)"
)
i += 1
# make a filegroup with the original name that groups together all
# of the output files
native.filegroup(
name = name,
srcs = all_outs,
)
然后,bazel build :main
将构建所有CoffeeScript文件,一次20个。
但这确实有一些缺点:
如果修改了一个CoffeeScript文件,则会重新编译20个文件。不只是一个。
如果添加或删除文件,那么很多文件 - 从那时起直到文件列表的结尾 - 将被重新编译。
我发现最好的方法是做@ahumesky建议的事情:将事情分解成合理大小的Bazel&#34;包&#34;,并让每个包进行一次编译。