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

Creating multiple HTML files from a single Jade template with Grunt

本文关键字:创建 HTML 文件 Grunt 单个 Jade 使用      更新时间:2023-09-26

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

我是这样做的:

  1. 从外部文件抓取JSON数据
  2. 遍历该对象
  3. 为JSON对象中的每个值创建grunt配置任务

下面是我的代码:

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.

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

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

在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.
...

我知道这是一个旧的帖子,但我一直回到这里,同时试图解决类似的问题。我想使用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

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