2

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

将其弹出到 aGruntfile.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:正如 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'

我不明白他们为什么做出这个设计决定,但我可以很容易地模拟我想要的模板语义,方法是将所有这些包装在一个重复处理字符串直到全部<%=消失的函数中。

4

2 回答 2

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/开发/grunt-test

/用户/andrewtremblay/开发/grunt-test/dev

/用户/andrewtremblay/开发/grunt-test/dev/vendor

/用户/andrewtremblay/开发/grunt-test/dev/vendor/classes

arg1:/用户/andrewtremblay/Development/grunt-test/dev arg2:供应商

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

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

从文档(我强调):

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

If tois not already 绝对from参数以从右到左的顺序添加,直到找到绝对路径。如果使用 all from paths 后仍然没有找到绝对路径,则也使用当前工作目录。生成的路径被规范化,并且尾部斜杠被删除,除非路径被解析为根目录。

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

于 2014-01-14T21:40:21.143 回答
0

当 Grunt 执行 aget时,config如果找到模板模式,它​​会处理这些值。

看起来它会处理模板,直到找到没有模板模式的字符串。因此,您的情况中的每一步都如下所示:

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

除了在运行时手动扩展配置之外,我不知道是否有解决此问题的好方法:

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"))
于 2014-01-14T21:19:02.847 回答