0

我正在为我们的内部文档和测试使用 mustache partials - 如另一个 SO question how to have grunt task render mustache partials to static HTML中所述,我现在想使用外部 json 文件驱动部分数据。json 文件将与部分文件命名相同,并将包含将与部分文件一起编译的模拟数据。

关于如何使它工作的任何建议?

4

1 回答 1

3

我更新了 hogan.js 文件以读取与部分同名的 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 -->

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

警报.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}}

让我知道这是否有帮助。

谢谢,布赖恩

于 2012-12-03T04:17:42.103 回答