how to have grunt task render mustache partials to static HTML

十年热恋 提交于 2019-12-05 06:00:16

问题


Background

I've been using grunt.js with a hogan.js task to build the static HTML for our internal docs. I'm learning JavaScript as I go, but I've gotten the task to work well enough for layouts and pages, but it would really help our workflow to have the hogan task render mustache partials to HTML, as in the example in this gist: https://gist.github.com/4132781

Current Setup and what I want to accomplish

All of our mustache partials are in a folder called "partials". Ideally when the grunt build is run, the hogan task will grab any partials from the partials folder and insert them into the HTML wherever they are referenced (also, shown in gist).

What I DON'T want

I don't want to have to define each partial in the task or task configuration. This won't work, we have ~200 partials and growing, so we need to have the task scan a folder and grab partials based on either file name or something. I also don't want to use a different language or build tool. We've used Jade, some markdown-based docs builders, a number of others. If we can just get partials to render as described we'll be in great shape!

Is it possible to accomplish this? Thanks in advance for any feedback


回答1:


I was looking at your code in the gist and some of the options don't match with the filenames you're referencing.

Here is my stab at updating the code you provided to allow rendering partials:

grunt.js

The src is the list of pages you're building that might contain partials In this case, components.mustache would be located at 'docs/components/templates/pages/components.mustache'

Updating the layout option to layout.mustache which is used for all the pages (including components.mustache)

Adding a paths object to options which has a path to the partials folder. All these partials will be read and compiled and stored in options.partials for later use in the grunt task.

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

Updating this task to read in all the partials and compile them.

The helper is being updated to add the 'body' partial (which is the compiled page) to the options.partials list.

The options.partials is then passed into the hogan.render method so all the partials are available to all the pages.

/*
 * 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
    }
  })
};

One thing to note, if you're going to pass data into the partials, you'll need to add that to the context object in the file layout.render call.

Hope this all make sense and helps you out.



来源:https://stackoverflow.com/questions/13521608/how-to-have-grunt-task-render-mustache-partials-to-static-html

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!