使用Grunt从单个Jade模板创建多个HTML文件

时间:2014-07-03 16:52:19

标签: javascript json node.js gruntjs pug

我希望使用Grunt从单个Jade模板创建多个HTML文件。

这就是我正在做的事情:

  1. 从外部文件中抓取JSON数据
  2. 循环播放该对象
  3. 为该JSON对象中的每个值创建一个grunt配置任务
  4. 这是我的代码:

    neighborhoods = grunt.file.readJSON('data/neighborhoods.json');
    
    for(var i = 0; i < Object.keys(neighborhoods).length; i++) {
    
        var neighborhood = {
            "title" : Object.keys(neighborhoods)[i],
            "data"  : neighborhoods[Object.keys(neighborhoods)[i]]
        };
    
        grunt.config(['jade', neighborhood.title], {
            options: {
                data: function() {
                    return {
                        neighborhoods: neighborhood.data
                    }
                }
            },
            files: {
                "build/neighborhoods/<%= neighborhood.title %>.html": "layouts/neighborhood.jade"
            }
        });
    }
    

    我遇到的问题是这个

    Running "jade:Art Museum" (jade) task
    Warning: An error occurred while processing a template (Cannot read property 'title' of undefined). Use --force to continue.
    

    如果我将文件名设为字符串,它运行正常,但显然会创建具有相同文件名的所有文件,因此只创建一个文件。我需要使文件名动态化。

3 个答案:

答案 0 :(得分:1)

我在这里找到了解决方案:

Use Global Variable to Set Build Output Path in Grunt

  

问题是模块在这些全局变量设置之前导出,因此在initConfig()任务中定义的后续任务中都未定义它们。


这就是诀窍!

var neighborhoods = grunt.file.readJSON('data/neighborhoods.json');

for(var i = 0; i < Object.keys(neighborhoods).length; i++) {

    var neighborhood = {
        "title" : Object.keys(neighborhoods)[i],
        "data"  : neighborhoods[Object.keys(neighborhoods)[i]]
    };

    /* 
     * DEFINE VALUE AS GRUNT OPTION
     */

    grunt.option('neighborhood_title', neighborhood.title);

    grunt.config(['jade', neighborhood.title], {
        options: {
            data: function() {
                return {
                    neighborhoods: neighborhood.data,
                    neighborhood_title: neighborhood.title
                }
            }
        },

        /* 
         * OUTPUT GRUNT OPTION AS FILENAME
         */

        files: {
            "build/neighborhoods/<%= grunt.option('neighborhood_title') %>.html": "layouts/neighborhood.jade"
        }
    });
}


这会产生所需的输出:

Running "jade:East Passyunk" (jade) task
File build/neighborhoods/Society Hill.html created.

Running "jade:Fishtown" (jade) task
File build/neighborhoods/Society Hill.html created.

Running "jade:Graduate Hospital" (jade) task
File build/neighborhoods/Society Hill.html created.

Running "jade:Midtown Village" (jade) task
File build/neighborhoods/Society Hill.html created.

Running "jade:Northern Liberties" (jade) task
File build/neighborhoods/Society Hill.html created.

...

答案 1 :(得分:1)

我知道这是一个老帖子,但我一直在回到这里,同时试图解决类似的问题。我想使用for循环从单个jade模板文件输出多个html文件。

我遇到的两个问题是设置输出文件名(一个javascript对象文字KEY),并确保立即运行内联javascript函数,以便循环变量可用。

这是我的完整源代码和评论。我希望这对任何绊倒这篇文章的人都有用。

Gruntfile.js:

module.exports = function(grunt) {

  // Create basic grunt config (e.g. watch files)
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    watch: {
      grunt: { files: ['Gruntfile.js'] },
      jade: {
        files: 'src/*.jade',
        tasks: ['jade']
      }
    }
  });

  // Load json to populate jade templates and build loop
  var json = grunt.file.readJSON('test.json');

  for(var i = 0; i < json.length; i++) {
      var obj = json[i];

      // For each json item create a new jade task with a custom 'target' name.
      // Because a custom target is provided don't nest options/data/file parameters 
      // in another target like 'compile' as grunt wont't be able to find them 
      // Make sure that functions are called using immediate invocation or the variables will be lost
      // http://stackoverflow.com/questions/939386/immediate-function-invocation-syntax      
      grunt.config(['jade', obj.filename], {
        options: {
            // Pass data to the jade template
            data: (function(dest, src) {
                return {
                  myJadeName: obj.myname,
                  from: src,
                  to: dest
                };
            }()) // <-- n.b. using() for immediate invocation
        },
        // Add files using custom function
        files: (function() {
          var files = {};
          files['build/' + obj.filename + '.html'] = 'src/index.jade';
          return files;
        }()) // <-- n.b. using () for immediate invocation
      });
  }

  grunt.loadNpmTasks('grunt-contrib-jade');
  grunt.loadNpmTasks('grunt-contrib-watch');

  // Register all the jade tasks using top level 'jade' task
  // You can also run subtasks using the target name e.g. 'jade:cats'
  grunt.registerTask('default', ['jade', 'watch']);
};

的src / index.jade:

doctype html
html(lang="en")
  head
    title= pageTitle
    script(type='text/javascript').
      if (foo) {
         bar(1 + 5)
      }
  body
    h1 #{myJadeName} - node template engine    
    #container.col
      p.
        Jade is a terse and simple
        templating language with a
        strong focus on performance
        and powerful features.

test.json:

[{
    "id" : "1", 
    "filename"   : "cats",
    "tid" : "2016-01-01 23:35",
    "myname": "Cat Lady"
},
{
    "id" : "2", 
    "filename"   : "dogs",
    "tid" : "2016-01-01 23:45",
    "myname": "Dog Man"
}]

运行'grunt'后,输出应为:

build/cats.html
build/dogs.html

答案 2 :(得分:0)

遇到了我正在进行的项目的类似要求,但无法使其工作。我一直只生成一个文件,因为grunt选项对所有任务都有相同的值(最后一个值)。所以我最终使用<%= grunt.task.current.target %>作为文件名,在您的情况下与neighborhood.title相同。