Ask A Question

Notifications

You’re not receiving notifications from this thread.

Extend Sprockets to bundle mustache templates

Alex Musayev asked in Rails

I'm trying to include some Mustache templates into the main JS bundle. The idea is to take /app/templates/*.mustache files, generate a JSON object, and set a window-level variable, like this:

window.Templates = {
  post: "<h2>{{ title }}</h2> <p>{{ body }}</p>",
  comment: "..."
}

This way the templates will be preloaded with application.js and remain available from every Rails view.

I've read this: https://github.com/rails/sprockets/blob/master/guides/extending_sprockets.md, and now I'm trying to create a transformer for new MIME type. Like so:

module Sample
  class Application < Rails::Application

    // ...

    config.assets.configure do |env|
      env.register_mime_type 'text/mustache', extensions: ['.mustache']
      env.register_transformer 'text/mustache', 'application/javascript', -> (input) {
        { data: '// THIS IS SAMPLE JS CODE GENERATED BY A TRANSFORMER' }
      }
    end
  end
end

Adding this directive to app/assets/javascripts/application.js file suppose to inject sample output from this transformer for each file from templates directory:

//= require_tree ../../templates
//               ^ This should point to /app/templates

But I'm getting empty result after Sprockets compiles JS. Any advice?

I just want to understand how to set up Sprockets transformer. Actual JS generation is not a problem, I've added details just for the context.

I know that there are couple of gems that can do this for Mustache and Handlebars templates (like https://github.com/leshill/handlebars_assets), but I don't want to introduce another dependency here. The extension seem to be pretty simple.

Reply

I solved it, LOL.

Transformer lambda was correct. Just needed to add a regexp to Rails.application.config.assets.precompile to enable *.mustache processing. Also had some troubles with overly smart Sprockets caching.

I've also replaced the labda with this class:

module Service
  class MustacheTransformer
    def self.call(input)
      Rails.logger.debug "---> Transforming Mustache: #{input[:filename]}"
      key = input[:name]
      body = Oj.dump(input[:data])
      obj = 'window.MustacheTemplates'
      { data: "#{obj} = #{obj} || {}; #{obj}['#{key}'] = #{body}" }
    end
  end
end

Seem to be working pretty neat.

Reply

This is awesome. I haven't extended sprockets myself before and that looks like it turned out rather nicely. I'm impressed! :D

Reply

Chris, you can create an episode about this. I'll share more detailed code example if you like :)

Reply
Join the discussion
Create an account Log in

Want to stay up-to-date with Ruby on Rails?

Join 81,842+ developers who get early access to new tutorials, screencasts, articles, and more.

    We care about the protection of your data. Read our Privacy Policy.

    Screencast tutorials to help you learn Ruby on Rails, Javascript, Hotwire, Turbo, Stimulus.js, PostgreSQL, MySQL, Ubuntu, and more.

    © 2024 GoRails, LLC. All rights reserved.