使用外部json数据编译胡子部分

时间:2012-12-03 03:42:26

标签: json partial mustache gruntjs

我正在为我们的内部文档和测试使用胡子部分 - 正如其他SO问题how to have grunt task render mustache partials to static HTML中所述,我现在想要使用外部json文件驱动部分数据。 json文件的名称与partials相同,并且将包含将使用partials编译的模拟数据。

有关如何使其正常工作的任何建议?

1 个答案:

答案 0 :(得分:3)

我已更新hogan.js文件以读取与partials同名的data.json文件:

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: {},
        partialsData: {},
      },

      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 dataFilepath = filepath.replace(/\.mustache$/, '.json');

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

        // if a data file exists, read in the data
        if(fs.existsSync(dataFilepath)) {
          options.partialsData[filename] = grunt.file.readJSON(dataFilepath);
        }

      });
      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'
        }]
      })

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

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

alert.json文件的一个简单示例:

{
  "modifier": "alert-warning",
  "alertType": "Warning!",
  "message": "Best check yo self, you're not looking too good."
}

alert.mustache

           

的警报

  <div class="row-fluid">
    <div class="alert {{alert.modifier}}">
      <button type="button" class="close" data-dismiss="alert">&times;</button>
      <strong>{{alert.alertType}}</strong>
      {{alert.message}}
    </div>
  </div>

</div><!-- /container -->

我更喜欢下一个示例,因为您可以创建不同的数据来使用 在相同的部分:

alert.json

{
  "default": {
    "modifier": "alert-warning",
    "alertType": "Warning!",
    "message": "Best check yo self, you're not looking too good.!"
  },
  "error": {
    "modifier": "alert-error",
    "alertType": "Error!!!",
    "message": "You did something horribily wrong!!!"
  },
  "success": {
    "modifier": "alert-success",
    "alertyType": "Success!!!",
    "message": "The record has been successfully saved..."
  }
}

alert.mustache

<!-- partial -->
<div class="container">
  <h1>alerts</h1>

  <div class="row-fluid">
    <div class="alert {{modifier}}">
      <button type="button" class="close" data-dismiss="alert">&times;</button>
      <strong>{{alertType}}</strong>
      {{message}}
    </div>
  </div>

</div><!-- /container -->

partials.mustache ---这是引用警报部分的地方

  {{#alert.default}}
    {{> alert }}
  {{/alert.default}}

  {{#alert.error}}
    {{> alert }}
  {{/alert.error}}

  {{#alert.success}}
    {{> alert }}
  {{/alert.success}}

如果有帮助,请告诉我。

谢谢, 布赖恩