简体   繁体   English

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

[英]Creating multiple HTML files from a single Jade template with Grunt

I'm looking to create multiple HTML files from a single Jade template using Grunt. 我正在寻找使用Grunt从一个Jade模板创建多个HTML文件。

Here's what I'm doing: 这是我在做什么:

  1. Grabbing the JSON data from an external file 从外部文件获取JSON数据
  2. Looping through that object 遍历该对象
  3. Creating a grunt config task for each value in that JSON object 为该JSON对象中的每个值创建一个grunt配置任务

Here's my code: 这是我的代码:

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

The problem that I'm running in to is this 我遇到的问题是

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

If I make the filename a string, it runs fine but obviously creates all the files with the same filename, thus only creating one file. 如果我将文件名设为字符串,则可以正常运行,但显然可以使用相同的文件名创建所有文件,因此只能创建一个文件。 I need to make that filename dynamic. 我需要使该文件名动态。

I found the solution here: 我在这里找到解决方案:

Use Global Variable to Set Build Output Path in Grunt 使用全局变量在Grunt中设置构建输出路径

The issue is that the module exports before those global variables get set, so they are all undefined in subsequent tasks defined within the initConfig() task. 问题在于模块会在设置这些全局变量之前导出,因此它们在initConfig()任务中定义的后续任务中都未定义。


This did the trick! 这成功了!

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


This results in the desired output: 这将产生所需的输出:

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.

...

I know this is an old post but I kept coming back here whilst trying to solve a similar problem. 我知道这是一篇旧文章,但在尝试解决类似问题的同时,我一直回到这里。 I wanted to output multiple html files from a single jade template file using a for-loop. 我想使用for循环从单个jade模板文件中输出多个html文件。

The two problems I came across was setting the output filename (a javascript object literal KEY) and making sure inline javascript functions are run immediately so that the loop variables are available. 我遇到的两个问题是设置输出文件名(JavaScript对象文字KEY)并确保立即运行内联javascript函数,以便循环变量可用。

Here is my full source code with comments. 这是我完整的带有注释的源代码。 I hope this is of use to anyone else stumbling across this post. 我希望这对在这篇文章中遇到麻烦的其他人有用。

Gruntfile.js: 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: 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: 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"
}]

After running 'grunt' the output should be: 运行“ grunt”后,输出应为:

build/cats.html
build/dogs.html

Came across a similar requirement for a project I'm working on but couldn't get this to work. 遇到了我正在从事的项目的类似要求,但无法使其正常工作。 I kept getting only one file generated since the grunt option had same value for all tasks (the last value). 由于grunt选项对所有任务都具有相同的值(最后一个值),因此我一直只生成一个文件。 So I ended up using <%= grunt.task.current.target %> for the file name which in your case would be same as neighborhood.title . 因此,我最终使用<%= grunt.task.current.target %>作为文件名,在您的情况下,该文件名与neighborhood.title相同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM