如何动态生成用于Grunt任务的文件名列表?

时间:2014-04-25 13:40:15

标签: javascript node.js gruntjs

我正在使用load-grunt-configgrunt-prompt,我正在开发一个init任务,它会在两个文件夹之间复制一些php模板。

现在模板文件名是硬编码的,但我宁愿让grunt扫描正确的文件夹并动态提供文件名。

我已尝试使用grunt.file.expand,但我无法让它发挥作用。是否可以扫描文件夹并以grunt-prompt期望的格式返回文件名的数组(或对象,不知道你称之为什么)文件名?

// -------------------------------------
// Grunt prompt
// -------------------------------------

module.exports = {

  // ----- Initialization prompt ----- //

  init: {
    options: {
      questions: [{
        // Set the authors name
        config: 'init.author.name',
        type: 'input',
        message: 'What is your name?'
      }, {
        // Set the name of the project
        config: 'init.project.name',
        type: 'input',
        message: 'What is the name of your project?'
      }, {
        // Select templates to be used
        config: 'init.php.templates',
        type: 'checkbox',
        message: 'Which templates do you want to use?',
        choices: [{
          name: '404.php',
          checked: false
        }, {
          name: 'archive.php',
          checked: false
        }, {
          name: 'comments.php',
          checked: false
        }]
      }]
    }
  }
};

顺便说一句,我找到了这个答案:https://stackoverflow.com/a/22270703/1694077,它与问题有关。但它没有详细说明如何专门解决这个问题。另外,我需要比文件名数组更具体的语法:

[{
  name: '404.php'
}, {
  name: 'archive.php'
}]

3 个答案:

答案 0 :(得分:10)

基本原则

这是一种使用Grunt的文件匹配功能来获取文件列表的方法。以下代码将在名为templates的子目录中搜索模板。您只需将php文件放在那里,脚本就会找到它。注意我省略了load-grunt-config的使用,因为它不是获取文件列表的特定问题的一个因素。

关键是使用grunt.file.expand来获取文件。

module.exports = function (grunt) {

    // List all files in the templates directory.
    var templates = grunt.file.expand({filter: "isFile", cwd: "templates"},
                                      ["*"]);

    // Make actual choices out of them that grunt-prompt can use.
    var choices = templates.map(function (t) {
        return { name: t, checked: false};
    });

    grunt.initConfig({
        prompt: {
            init: {
                options: {
                    questions: [{
                        // Set the authors name
                        config: 'init.author.name',
                        type: 'input',
                        message: 'What is your name?'
                    }, {
                        // Set the name of the project
                        config: 'init.project.name',
                        type: 'input',
                        message: 'What is the name of your project?'
                    }, {
                        // Select templates to be used
                        config: 'init.php.templates',
                        type: 'checkbox',
                        message: 'Which templates do you want to use?',
                        choices: choices
                    }]
                }
            }
        }
    });

    grunt.task.loadNpmTasks("grunt-prompt");
    grunt.registerTask("default", ["prompt"]);
};

你可以使用比"*"更复杂的东西作为模式。例如,如果您要在其中包含其他类型的文件,则表示您不希望列出"*.php"。我还使用isFile作为filter选项以避免列出目录。在列出文件之前,我使用cwd将工作目录更改为templates ,这意味着返回的文件名包括{{1在他们的名字。也可以这样做:

templates/

并获取名称中包含var templates = grunt.file.expand({filter: "isFile"}, ["templates/*"]); 目录的文件列表。

使用templates/

默认情况下,load-grunt-config需要load-grunt-config个文件(因为它调用package.json)。这就是我用过的:

load-grunt-tasks

{ "dependencies": { "load-grunt-config": "^0.8.0", "grunt-prompt": "^1.1.0", "grunt": "^0.4.4" } } 变为:

Gruntfile.js

然后在module.exports = function (grunt) { grunt.registerTask("default", ["prompt"]); require('load-grunt-config')(grunt); }; 中你需要这个:

grunt/prompt.js

答案 1 :(得分:2)

这是一个列出目录中文件的简短代码:

var fs = require("fs")
var files = [];
var list = function (path) {
  fs.readdirSync(path).forEach(function (file) {
    if(fs.lstatSync(path + '/' +file).isDirectory())
      list(path + '/' +file);
    else
      files.push({name: file});
  });
}
list(YOUR_PATH)
console.log(files)

在你的例子中:

var fs = require("fs")
var files = [];
var list = function (path) {
  fs.readdirSync(path).forEach(function (file) {
    if(fs.lstatSync(path + '/' +file).isDirectory())
      list(path + '/' +file);
    else
      files.push({name: file});
  });
}
list(YOUR_PATH)
module.exports = {

  // ----- Initialization prompt ----- //

  init: {
    options: {
      questions: [{
        // Set the authors name
        config: 'init.author.name',
        type: 'input',
        message: 'What is your name?'
      }, {
        // Set the name of the project
        config: 'init.project.name',
        type: 'input',
        message: 'What is the name of your project?'
      }, {
        // Select templates to be used
        config: 'init.php.templates',
        type: 'checkbox',
        message: 'Which templates do you want to use?',
        choices: files
      }]
    }
  }
};

答案 2 :(得分:0)

还有另一种方法可以使用与接受的答案中列出的不同的Grunt实用程序方法。值得一提的是因为它暴露了" glob"的选项对象。 Grunt内部使用的npm包。

有关您的Grunt版本使用的glob版本的详细信息,请参阅README.md(查看其package.json文件)。我首先查看了最新的glob,并对Grunt没有 grunt.file.globSync ()方法这一事实感到困惑。我最终意识到Grunt正在使用早期版本的glob,之后{ sync true }从options对象中删除,并被 globSync ()函数我一直在寻找。

注意: grunt.file.glob ()不会将 src 数组作为 grunt.file.expand (),但是你可以使用大括号来有效地编码数组:

var options = { ... };
var results = 
  grunt.file.glob(
     '{first/path/**/*,second/path/**/*}', 
     options
  );

这是一个示例块,显示我如何在玉器处理中使用它,我似乎记得它由于某种原因本身不处理扩展块。选项:

  • 允许通配符匹配点前缀文件
  • 禁用非通配符glob模式路径节点的不必要的stat调用
  • 禁用排序,因为我不关心输入顺序
  • 禁用重复数据删除,因为我知道我的模式恰好匹配每个文件一次
  • 如果没有匹配的文件,
  • 请求空数组而不是数组

    var filesObj = {}; var configObj = {     构建:{         选项:{             漂亮:是的,             数据:{                 titleStr:'这是来自数据的标题'             }         },         files:filesObj     } };

    //从config获取源代码并构建输出目录根目录 var srcPrefix =     新的RegExp(' ^' + grunt.config.get(' sourceAssets')); var buildPrefix = grunt.config.get(' buildAssets');

    //每个glob匹配调用一次以填充文件对象。 function addJadeFile(srcPath){     //通过denormlalizing path处理Windows上的glob输出。     srcPath = srcPath.replace(/ \ / g,' /');     //提取公共路径后缀并更改文件扩展名     var relPath =         srcPath.replace(srcPrefix,' ..')。replace(/。jade $ /,' .html');     //前置目标路径前缀和属性     //到config对象的文件子对象。     filesObj [buildPath + relPath] = srcPath; }

    grunt.file.glob(     appConfig.source.client +' / ** / * .jade',     {sync:true,stat:false       strict:true,dot:false,       nonull:false,nodir:true,       nosort:true,nounique:true} ).forEach(addJadeFile);

    return configObj;

P.S。 grunt.file.glob ()和 grunt.file.expand ()通常优于 fs 包中的遍历方法,因为glob保持遍历缓存。

如果您正在寻找可能是由之前的构建步骤创建的文件,而不是其他文件,那么了解 glob 的遍历缓存也是很好的任务首先遍历其创建位置并填充该缓存。我还没有碰到这个,但要注意这一点,以防你需要找到如何在这种极端情况下清除或忽略缓存。