Grunt:recursion模板如何工作?

我是Grunt的新手,并且在recursion模板方面遇到了一些问题。 下面是一个具体的例子:

var path = require('path'); module.exports = function(grunt) { grunt.initConfig({ // Stash path here so we can reference it from templates. path: path, argPrint: function(arg1, arg2) { return "arg1: " + arg1 + " arg2: " + arg2; }, build: { root_dir: __dirname, build_dir: '<%= path.resolve(build.root_dir, "dev") %>', vendor_dir: '<%= path.resolve(build.build_dir, "vendor") %>', classes_dir: '<%= path.resolve(build.vendor_dir, "classes") %>', test: '<%= argPrint(build.build_dir, "vendor") %>' } }); grunt.registerTask('print_build_dir', 'Prints the build directory.', function() { grunt.log.writeln(grunt.config("build.root_dir")); grunt.log.writeln(grunt.config("build.build_dir")); grunt.log.writeln(grunt.config("build.vendor_dir")); grunt.log.writeln(grunt.config("build.classes_dir")); grunt.log.writeln(grunt.config("build.test")); }); }; 

将它popup到Gruntfile.js ,运行npm install grunt ,然后运行grunt print_build_dir

如果你在/Users/jvilk/Code/grunt-test ,我会希望输出结果是:

 $ grunt print_build_dir /Users/jvilk/Code/grunt-test /Users/jvilk/Code/grunt-test/dev /Users/jvilk/Code/grunt-test/dev/vendor /Users/jvilk/Code/grunt-test/dev/vendor/classes arg1: /Users/jvilk/Code/grunt-test/dev arg2: vendor 

相反,输出是:

 $ grunt print_build_dir /Users/jvilk/Code/grunt-test /Users/jvilk/Code/grunt-test/dev /Users/jvilk/Code/grunt-test//Users/jvilk/Code/grunt-test/dev/vendor /Users/jvilk/Code/grunt-test//Users/jvilk/Code/grunt-test//Users/jvilk/Code/grunt-test/dev/vendor/classes arg1: /Users/jvilk/Code/grunt-test/dev arg2: vendor 

这里发生了什么? 从testconfiguration属性来看,显然path.resolve应该接收vendor_dir属性的正确参数 – 即,它将parsing为path.resolve("/Users/jvilk/Code/grunt-test/dev", "vendor") – 但是我完全build.root_dir不清楚为什么它会在build.root_dir前面添加一个额外的正斜杠。

任何帮助或指导,将不胜感激我和我挣扎的Gruntfile 。 谢谢!

编辑:作为一个先发制人的附录,我意识到我不需要使用模板来实现这个特殊的例子 – 我可以直接使用path.resolve 。 但是,在我的非示例GruntfileGruntfile中的一个目录名是一个dynamic设置的属性,需要使用模板。

EDIT2:正如Andrew所指出的,模板扩展在vendor_dir上的工作方式如下:

 '<%= path.resolve(build.build_dir, "vendor") %>' -> path.resolve('<%= path.resolve(build.root_dir, "dev") %>', "vendor") -> '/Users/jvilk/Code/grunt-test/<%= path.resolve(build.root_dir, "dev") %>/vendor' -> '/Users/jvilk/Code/grunt-test//Users/jvilk/Code/grunt-test/vendor' 

我的test属性工作,因为它扩展如下:

 '<%= argPrint(build.build_dir, "vendor") %>' -> argPrint('<%= path.resolve(build.root_dir, "dev") %>', "vendor") -> 'arg1: <%= path.resolve(build.root_dir, "dev") %> arg2: vendor' -> 'arg1: /Users/jvilk/Code/grunt-test arg2: vendor' 

我不明白他们为什么做这个devise决定,但我可以轻松地模拟我想要的模板语义,把所有这些都包含在一个重复处理string的函数中,直到所有的<%=消失。

首先让我从一个工作样本开始。

  grunt.initConfig({ path: path, argPrint: function(arg1, arg2) { return "arg1: " + arg1 + " arg2: " + arg2; }, resolvePath: function(from, to) { return path.resolve(grunt.config.process(from), to); }, build: { root_dir: __dirname, build_dir: "<%= resolvePath(build.root_dir, 'dev')%>", vendor_dir: "<%= resolvePath(build.build_dir, 'vendor') %>", classes_dir: "<%= resolvePath(build.vendor_dir, 'classes') %>", test: "<%= argPrint(build.build_dir, 'vendor') %>" } }); grunt.registerTask('print_build_dir', 'Prints the build directory.', function() { grunt.log.writeln(grunt.config.get("build.root_dir")); grunt.log.writeln(grunt.config.get("build.build_dir")); grunt.log.writeln(grunt.config.get("build.vendor_dir")); grunt.log.writeln(grunt.config.get("build.classes_dir")); grunt.log.writeln(grunt.config.get("build.test")); }); }; 

这输出你所期望的:

/用户/ andrewtremblay /开发/咕噜testing

/用户/ andrewtremblay /开发/咕噜,testing/开发

/用户/ andrewtremblay /开发/咕噜,testing/开发/销售商

/用户/ andrewtremblay /开发/咕噜testing的/ dev /供应商/类

arg1:/ Users / andrewtremblay / Development / grunt-test / dev arg2:vendor

当我使用ResolvePath函数进行testing时,注意到传递给它的值没有被处理。 (而不是使用config.get('build.build_dir')的输出,它使用了config.getRaw('build.build_dir')

我不知道这是否是一个错误,但我认为答案在于path.resolve以及如何传递可处理variables导致未定义的行为。

从文档 (我的重点):

path.resolve([from ...], to)

如果不是from参数的绝对值from则按从右到左的顺序,直到find绝对path。 如果在使用path中的所有path之后仍然没有find绝对path,那么也使用当前的工作目录。 生成的path被标准化,除非path被parsing到根目录,否则将删除结尾的斜线。

这(加上path.resolve不处理你的configuration对象)可以解释为什么你的工作目录不断前置。

当Grunt从config get ,如果它find了模板模式,它​​将处理这些值。

它看起来像处理模板,直到find一个没有模板模式的string。 所以你的情况每一步都是这样的:

 __dirname => '/Users/jvilk/Code/grunt-test' build.build_dir => '<%= path.resolve(build.root_dir, "dev") %> => __dirname + "dev" => '/Users/jvilk/Code/grunt-test/dev' build.vendor_dir => '<%= path.resolve(build.build_dir, "vendor") %>' => '/Users/jvilk/Code/grunt-test/<%= path.resolve(build.root_dir, "dev") %>/vendor' => '/Users/jvilk/Code/grunt-test//Users/jvilk/Code/grunt-test/dev/vendor' build.classes_dir => '<%= path.resolve(build.vendor_dir, "classes") %>' => '/Users/jvilk/Code/grunt-test/<%= path.resolve(build.build_dir, "vendor") %>'/classes' => '/Users/jvilk/Code/grunt-test//Users/jvilk/Code/grunt-test/<%= path.resolve(build.root_dir, "dev") %>/vendor/classes' => '/Users/jvilk/Code/grunt-test//Users/jvilk/Code/grunt-test//Users/jvilk/Code/grunt-test/dev/vendor/classes' 

我不知道是否有一个很好的解决办法,除了在运行时手动扩展你的configuration:

 grunt.config("build.build_dir", grunt.config("build.build_dir")) grunt.config("build.vendor_dir", grunt.config("build.vendor_dir")) grunt.config("build.classes_dir", grunt.config("build.classes_dir"))