如何让grunt任务渲染胡子部分到静态HTML

时间:2012-11-23 00:08:01

标签: node.js handlebars.js mustache gruntjs hogan.js

背景

我一直在使用带有hogan.js任务的grunt.js来为我们的内部文档构建静态HTML。我正在学习JavaScript,但是我已经完成了布局和页面工作的任务,但它确实有助于我们的工作流程让hogan任务渲染胡须部分到HTML,如本例中的示例:https://gist.github.com/4132781

当前设置和我想要完成的任务

我们所有的胡子部分都在名为“partials”的文件夹中。理想情况下,当运行grunt构建时,hogan任务将从partials文件夹中获取任何部分,并将它们插入HTML中的任何位置(也在gist中显示)。

我不想要什么

我不想在任务或任务配置中定义每个部分。这不起作用,我们有~200个部分并且在增长,所以我们需要让任务扫描一个文件夹并根据文件名或其他东西获取部分内容。我也不想使用其他语言或构建工具。我们使用过Jade,一些基于markdown的文档构建器,以及其他一些。如果我们可以按照描述得到部分渲染,那么我们将处于良好状态!

有可能做到这一点吗?提前感谢您的任何反馈

1 个答案:

答案 0 :(得分:5)

我在gist中查看了您的代码,其中一些选项与您引用的文件名不匹配。

这是我更新您提供的代码以允许渲染部分内容:

grunt.js

src是您正在构建的可能包含部分内容的页面列表 在这种情况下,components.mustache将位于'docs / components / templates / pages / components.mustache'

将layout选项更新为layout.mustache,用于所有页面(包括components.mustache)

将路径对象添加到具有partials文件夹路径的选项。所有这些部分内容都将被读取和编译并存储在options.partials中,以便以后在grunt任务中使用。

module.exports = function(grunt) {

  'use strict';

  // Project configuration
  grunt.initConfig({
    pkg: '<json:package.json>',
    meta: {
      banner:
      '/**\n' +
      '* <%= pkg.name %>.js v<%= pkg.version %> by @fat & @mdo\n' +
      '* Copyright <%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' +
      '* http://www.apache.org/licenses/LICENSE-2.0.txt\n' +
      '*/'
    },

    // Build HTML docs from .mustache files
    hogan: {
      production: {
        src: 'docs/components/templates/pages/*.mustache',
        dest: 'docs/components/FILE.html',
        options: {
          title:      'Sellside',
          url:        'docs',
          setAccount: 'NA',
          setSiteId:  'NA',
          layout:     'docs/components/templates/layout.mustache',
          dev:        true,
          docs:       true,
          app:        false,
          website:    false,
          paths: {
            partials: 'docs/components/templates/partials/*.mustache'
          }
        }
      }
    }
  });

  // Load npm tasks.
  grunt.loadNpmTasks('grunt-contrib');

  // Load local tasks.
  grunt.loadTasks('tasks');

  grunt.registerTask('default', 'hogan');

};

hogan.js

更新此任务以读入所有部分并编译它们。

正在更新帮助程序,以将“body”部分(已编译的页面)添加到options.partials列表中。

然后将options.partials传递给hogan.render方法,以便所有部分都可用于所有页面。

/*
 * Build HTML from mustache files
 * https://github.com/sellside/ui/grunt.js
 *
 * Copyright (c) 2012 Sellside
 * Authored by Jon Schlinkert
 */

module.exports = function(grunt) {

  // Grunt utilities.
  var task   = grunt.task,
    file     = grunt.file,
    utils    = grunt.util,
    log      = grunt.log,
    verbose  = grunt.verbose,
    fail     = grunt.fail,
    option   = grunt.option,
    config   = grunt.config,
    template = grunt.template,
    _        = utils._

  // external dependencies
  var fs   = require('fs'),
    hogan  = require('hogan');


  // ==========================================================================
  // TASKS
  // ==========================================================================
  grunt.registerMultiTask('hogan', 'Compile mustache files to HTML with hogan.js', function() {

    var data     = this.data,
      src        = grunt.file.expandFiles(this.file.src),
      dest       = grunt.template.process(data.dest),

      // Options are set in gruntfile
      defaults   = {
        production:  false,
        docs:        false,
        title:      'Sellside',
        setAccount: 'NA',
        setSiteId:  'NA',
        layout:     'docs/templates/layout.mustache',
        paths: {},
        partials: {}
      },

      options = _.extend(defaults, this.data.options || {})

      !src && grunt.warn('Missing src property.')
      if(!src) return false

      !dest && grunt.warn('Missing dest property')
      if(!dest) return false

    var done         = this.async()
    var srcFiles     = file.expandFiles(src)

    if(options.paths.partials) {

      var partials = grunt.file.expandFiles(options.paths.partials);
      log.writeln('Compiling Partials...');
      partials.forEach(function(filepath) {
        var filename = _.first(filepath.match(/[^\\\/:*?"<>|\r\n]+$/i)).replace(/\.mustache$/, '');
        log.writeln(filename.magenta);

        var partial = fs.readFileSync(filepath, 'utf8');
        options.partials[filename] = hogan.compile(partial);

      });
      log.writeln();
}

    try {
      options.layout   = fs.readFileSync(options.layout, 'utf8')
      options.layout   = hogan.compile(options.layout, {
        sectionTags: [{
          o: '_i',
          c: 'i'
        }]
      })
    } catch(err) {
      grunt.warn(err) && done(false)
      return
    }

    srcFiles.forEach(function(filepath) {
      var filename = _.first(filepath.match(/[^\\\/:*?"<>|\r\n]+$/i)).replace(/\.mustache$/, '')

      grunt.helper('hogan', filepath, filename, options, function(err, result) {
        err && grunt.warn(err) && done(false)
        if(err) return

        file.write(dest.replace('FILE', filename), result)
      })
    })

    done()
  })

  // ==========================================================================
  // HELPERS
  // ==========================================================================
  grunt.registerHelper('hogan', function(src, filename, options, callback) {
    log.writeln('Compiling ' + filename.magenta);

    var page                = fs.readFileSync(src, 'utf8'),
        html                = null,
        layout              = options.layout,
        context             = {};

        context[filename]   = 'active';
        context._i          = true;
        context.production  = options.production;
        context.docs        = options.docs;
        context.setAccount  = options.setAccount;
        context.setSiteId   = options.setSiteId;

    var title               = _.template("<%= page == 'Index' ? site : page + ' · ' + site %>")
    context.title           = title({
      page: _(filename).humanize().replace('css', 'CSS'),
      site: options.title
    })
    try {
      page = hogan.compile(page, {
        sectionTags: [{
          o: '_i',
          c: 'i'
        }]
      })

      options.partials.body = page;
      page = layout.render(context, options.partials)

      callback(null, page)
    } catch(err) {
      callback(err)
      return
    }
  })
};

有一点需要注意,如果您要将数据传递给partials,则需要将其添加到文件layout.render调用中的上下文对象中。

希望这一切都有意义并帮助你。