【问题标题】:Creating multiple HTML files from a single Jade template with Grunt使用 Grunt 从单个 Jade 模板创建多个 HTML 文件
【发布时间】:2014-08-24 21:54:06
【问题描述】:

我希望使用 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.

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

【问题讨论】:

    标签: javascript json node.js gruntjs pug


    【解决方案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.
    
    ...
    

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

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

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

        这是我使用 cmets 的完整源代码。我希望这对其他偶然发现这篇文章的人有用。

        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
        

        【讨论】:

          猜你喜欢
          • 2013-05-05
          • 2013-08-06
          • 1970-01-01
          • 2016-09-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-10-23
          • 2015-04-27
          相关资源
          最近更新 更多