Consequences for use: coffescript filter inside HAML templates?

So HAML 4 includes a coffeescript filter that allows us to like coffee so people do neat things like this:

- word = "Awesome." :coffeescript $ -> alert "No semicolons! #{word}" 

My question is: for the end user this is slower than using the equivalent filter :javascript ? Using the coffeescript filter means that coffeescript will be compiled into javascript every time the page loads (which, obviously, would be a performance error), or does this only happen once when the application starts?

+10
ruby-on-rails coffeescript haml
Jul 10 '13 at 1:08
source share
2 answers

It depends.

When Haml compiles the filter, it checks to see if the filter text contains any interpolation ( #{...} ). If not, then there will be the same text for conversion for each request, so the conversion is performed once at compile time and the result is included in the template.

If there is interpolation in the filter text, then the actual text for the conversion will change for each request, so Coffeescript will need to be compiled every time.

Here is an example. First without interpolation:

 :coffeescript $ -> alert "No semicolons! Awesome" 

This generates code (use haml -d to see the generated Ruby code):

 _hamlout.buffer << "<script>\n (function() {\n $(function() {\n return alert(\"No semicolons! Awesome\");\n });\n \n }).call(this);\n</script>\n"; 

This code simply adds a line to the buffer, so Coffeescript is not recompiled.

Now with interpolation:

 - word = "Awesome." :coffeescript $ -> alert "No semicolons! #{word}" 

This generates:

  word = "Awesome." _hamlout.buffer << "#{ find_and_preserve(Haml::Filters::Coffee.render_with_options( "$ -> alert \"No semicolons! #{word}\"\n", _hamlout.options)) }\n"; 

Here, since Haml has to wait to find out what the interpolation value is, Coffeescript is recompiled every time.

You can avoid compiling Coffeescript for each request without having interpolation inside the filters :coffeescript .

The :javascript filter behaves similarly, checking if there is any interpolation, but since the :javascript filter only outputs some text to the buffer when it is run, its use is much less. You could combine the filters :javascript and :coffeescript by putting the interpolated data in :javascript and saving :coffeescript static:

 - word = "Awesome" :javascript var message = "No semicolons! #{word}"; :coffeescript alert message 
+15
Jul 10 '13 at
source share
β€” -

The matte answer is clear about what is happening. I made an assistant to add local residents to the filters :coffeescript from the hash. This way you do not need to use global JavaScript variables. As a side note: on Linux, the slowdown is really negligible. However, on Windows, the performance impact is very important (easy to compile more than 100 ms per block).

 module HamlHelper def coffee_with_locals locals={}, &block block_content = capture_haml do block.call end return block_content if locals.blank? javascript_locals = "\nvar " javascript_locals << locals.map{ |key, value| j(key.to_s) + ' = ' + value.to_json.gsub('</', '<\/') }.join(",\n ") javascript_locals << ";\n" content_node = Nokogiri::HTML::DocumentFragment.parse(block_content) content_node.search('script').each do |script_tag| # This will match the '(function() {' at the start of coffeescript compiled code split_coffee = script_tag.content.partition(/\(\s*function\s*\(\s*\)\s*\{/) script_tag.content = split_coffee[0] + split_coffee[1] + javascript_locals + split_coffee[2] end content_node.to_s.html_safe end end 

This allows you to do the following:

 = coffee_with_locals "test" => "hello ", :something => ["monde", "mundo", "world"], :signs => {:interogation => "?", :exclamation => "!"} do :coffeescript alert(test + something[2] + signs['exclamation']) 

Since there is no interpolation, the code is actually compiled as normal.

+4
Oct. 21 '13 at 18:10
source share



All Articles