2014-01-14 77 views
2

我是Grunt的新手,我在递归模板方面遇到了一些问题。这里有一个具体的,小例子:Grunt:递归模板如何工作?

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")); 
    }); 
}; 

波普说成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 

这是怎么回事?从test配置属性,显然path.resolve应该收到vendor_dir属性的正确参数 - 即它将解析为path.resolve("/Users/jvilk/Code/grunt-test/dev", "vendor") - 但我完全困惑于为什么它预先将build.root_dir的值与一个额外的正斜杠财产。

任何帮助或指导将不胜感激我和我的努力Gruntfile。谢谢!

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

EDIT2:由于安德鲁指出,模板工程扩建对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' 

我不理解他们为什么做出这个设计决定,但是我可以通过将所有这些包含在一个重复处理字符串的函数中,直到所有<%=都消失为止,轻松地模拟我想要的模板语义。

回答

2

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

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 /开发/咕噜测试

/用户/ andrewtremblay /开发/咕噜,测试/开发

/Users/andrewtremblay/Development/grunt-test/dev/vendor

/Users/andrewtremblay/Development/grunt-test/dev/vendor/cl驴

ARG1:/用户/ andrewtremblay /开发/咕噜,测试/开发ARG2:供应商

我测试这个时候与我ResolvePath函数传递给from的值不被人注意处理。 (而不是使用的config.get('build.build_dir')输出是使用config.getRaw('build.build_dir')结果)

我不知道这是否是一个错误或没有,但我认为答案在于path.resolve以及如何通过它处理的变量会导致不确定的行为。

From the docs(我的重点):

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

如果to是不是已经绝对from参数在右前置到 左的顺序,直到绝对路径中找到。 如果在使用全部 路径之后仍然没有找到绝对路径,那么也使用当前工作目录 。生成的路径被标准化,除非路径被解析到根目录 目录,否则将删除尾部 斜杠。

这(加上path.resolve没有处理你的配置对象的事实)可以解释为什么你的工作目录不断被预置。

+0

就是这样。我向argPrint添加了arg1的调试打印,并注意到它正在使用原始模板进行调用。我的模板思维模式不正确;我认为它立即替换了所有的配置变量,但是它会在一个层次上处理模板,并将其转发,然后递归处理所有其他模板直至完成。 –

0

当Grunt从config中执行get时,它会在找到模板模式时处理这些值。

它看起来像它处理模板,直到它找到一个没有模板模式的字符串。因此,在您的情况每一步的样子:

__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' 

我不知道是否有解决这个除了在运行时手动扩展您的configs一个好办法:

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")) 
+0

这个模板扩展没有意义......'vendor_dir'和'test'是相同的 - *除了*他们调用不同的函数! 膨胀这种形式将产生以下为'test': '/用户/ jvilk /代码/咕噜测试/ ARG1:/用户/ jvilk /代码/咕噜-测试/开发ARG2:vendor' 此外,外部正斜杠从哪里来? 'root_dir'是'/ Users/jvilk/Code/grunt-test',而不是'/ Users/jvilk/Code/grunt-test /'...是Grunt进行奇怪的基本名提取,因为它看起来像一个文件路径... ? 谢谢你的回应,但。 –

+1

我没有注意到argPrint中的差异。我认为@安德鲁的答案解释了它。 – doowb