Haml and Sass Extension

Short answer is "Yes".

I’ve been tracking the Development of V3 and have implemented the new SassScript functions in my dev environment. The next step is to implement the parser for the new .scss syntax and it should be good to go. I’ll try to make some time to do this, but no promises as to when. Would you be OK to test some early code and report the bugs - of which there will be many I’m sure :D

Very good Work Yeti, we are planning to use this template engine for our next large web project.

There are a bunch of good php templates out there, but most of them downgrade the performance considerably, do you have any benchmark or performance numbers for this template engine? I mean: phaml vs php.

Another question in relation with this, do you support the ugly haml mode?

http://www.shaldybin…erformance.html

we would be pleased if you could include some benchmark numbers here or in the project wiki.

thanks in advance,

alex

EDIT: Thinking about it a bit more, I guess it precompiles the haml code to php, am I right?

But then, why there are some benchmarks test for haml 2.2 from the owner?

http://nex-3.com/posts/87-haml-benchmark-numbers-for-2-2

What is the real workflow? I mean, who parse, who render, and when?

Another question: does it handle the cache system in anyway? what is the best way to declare those fragment or page cache?

I’m a bit confused, so sorry and thanks again,

Alex

Hi Alex,

Firstly, I am very pleased to hear the extension is getting used in a large project and I’d like to hear how that goes.

As you are asking on the Yii forums I am assuming you are using Yii, so my answers are based on this. Your main concern seems to be performance. The short answer is:

Unless the PHP view file does not exist or is out of date there is no performance hit.

Now the long answer :)

There’s a few points here:

  • I don’t think of Haml as a templating engine; it does not do any processing in the same way that, for example, Smarty does. Haml is just a different (better :) ) way of writing the template, but it ends up as the same thing in that …

  • The Haml parser simply transforms Haml to PHP.

  • Haml does not introduce any performance hit as it is a PHP file that is rendered. The exception is if either the output PHP view file does not exist or the corresponding Haml file is newer, i.e. has been modified; then the Haml file is parsed.

Yes. This is the default rendering.

The performance improvement is not in the parsing of the Haml file, but in reducing the size of the page by removing as much whitespace as it can.

Note that all in rendering modes, including Ugly, inserted markup (from a widget for example) is sent as is.

Benchmark figures are not really relevant - you answered that one below :)

That is exactly what happens.

Why the benchmark figures you mention? Don’t know, perhaps Ruby and or Rails does things differently, but there is one comment that is very relevant: “Much more time can be saved by caching intelligently”.

Because Yii caches the output PHP view file the hit from Haml is one time only other than to decide whether to parse the Haml file or not (very quick).

This is the key as to why there is no real performance hit using Haml.

The Haml file is parsed if the output PHP view file does not exist or is older than the Haml file.

In the extension; the Haml class extends CViewRenderer; this checks to see if the Haml file needs parsing (the output PHP view file does not exist or is older) and calls the HamlParser if so.

The output PHP view file is rendered by Yii in the normal way.

Yii handles the caching.

Your only decision about caching is whether the output PHP view file goes; into Yii’s runtime directory (the default) or into the same directory as the Haml file (declare useRuntimePath=>false in your config for the extension; $useRuntimePath is defined in CViewRenderer). There is no performance difference.

As for page fragments - or anything else for that matter; use them just as you would in a PHP template ('coz that’s what you end up with). The Haml parser does not do anything special here, it just turns Haml into PHP, and anything you can do in PHP can be represented in Haml.

Here’s a Haml snippet to list blog posts:




%h1 Posts

- $this->widget('CLinkPager', compact('pages'))

.hfeed

  - foreach ($posts as $index=>$post)

    - $this->renderPartial('_show', compact('post', 'index', 'tags'))



Here you can see the CLinkPager widget is used to create the paging for the list and a call to CController::renderPartial() to render individual posts.

The partial views can be Haml or PHP files. If Haml they will be parsed the first time they are used, after which the output PHP view file will be rendered.

This is what the PHP output looks like (nested rendering) and it is this that is rendered by Yii.




<h1>

  <?php echo Posts; ?>

</h1>

<?php $this->widget('CLinkPager', compact('pages')); ?>

<div class="hfeed">

  <?php foreach ($posts as $index=>$post) { ?>

    <?php $this->renderPartial('_show', compact('post', 'index', 'tags')); ?>

  <?php }  ?>

</div>



To clarify and summarise:

  • The Haml Parser itself does not perform any caching or check whether the file it is given needs parsing or not; if it is called it will parse the file and return the PHP.

  • Yii handles all of the caching and decisions about what needs to be parsed and does all the rendering using the PHP files generated.

  • A Haml view file is only parsed if the output PHP view file either does not exist or is out of date; making the performance hit of parsing a one time only hit the first time a page is viewed or a partial used.

  • Partials, widgets, etc. etc. are used in exactly the same way as in a Yii PHP template.

I hope this helps.

Chris

Wow Crish! that’s incredible!!

Let me congratulate you again, firstly for your great work, and secondly for your clear and understandables responses (even for Spaniards like me).

So for caching, we should use something like this:




...other HTML content...

- if $this->beginCache()

...content to be cached...

- $this->endCache()

...other HTML content...



Isn’t it?

How is going your work with Haml 3? What are the main benefits?

I read about multiline support, kind of html5 support, etc.

Could we use html/php 2 haml converter?

best regards,

Alex

Exactly. The Haml parser will turn this into PHP and by the time Yii gets to render it it will not know it came from Haml - it only sees the PHP.

And just in case anyone is wondering - this is why even with Ugly rendering markup from widgets, etc. is sent as is; Haml has already done it’s “rendering” to generate the PHP and plays no further part, and the widget (say) is run after this has happened.

Let me do this backwards.

HTML 5 is supported in PHamlP, just declare the “format=>html5” in your config for the extension and declare the doctype as “!!!” in your templates. If by HTML 5 supprt you mean Haml’s custom data elements, then no, these are not supported at the moment. (see the Haml 3 answer below)

PHamlP supports multiline - though do grab the latest version of PHamlP from SVN; I found a bug with multiline support yesterday. I’ll package up a new Yii release towards the end of this week.

Haml 3

Haml 3 has a few additions, but (I think) for the most part what they do can already be done in Haml now, albeit not as elegantly.

The BIG change is in Sass where there are significant changes - not least of which is a new syntax, so this is what I am working on. I will add the new Haml features, probably as break from doing Sass :lol: , but no promises as to exactly when.

Sure

Revision 22 of this extension is now available.

R22 adds Haml helpers and support for HTML 5 custom data attributes and class and id arrays.

Sass is unchanged and is equivalent to Sass 2.2.4

Hello Chris, firstly thank you for your great work,

we are using phamlp extensively in this webpage, by the moment we are not using sass yet, but we will in near future.

Regarding to haml, I have to questions (or requests):

  • When you create your own Helper method, I would like to be able to use it "inline" for example:

    public static function lnk($block,$string) {

      return CHtml::link($block,$string);

    }    

I would like to use it like this:


 =lnk('http://www.siokia.com') www.siokia.com

But it doesn’t show anything. There are many helpers functions that I would like to use it like this, could it be posible to add this feature?

  • Another question (or bug): Whe you do write some sentence starting with "[+]" it complains, for example:

%h4

    [+] Opción Extra Hosting Professional

  • Las question: At least in my code (with last phamlp version),

.class#div

it’s not the same as


#div.class

, the former works but the later doesn’t. So I always have to put .class#div to create a div with class, and it’s a bit less readable.

Thanks a lot,

alex

Hi Alex,

Glad you like PHamlP and hope you find the Sass part of it useful as well.

To answer your questions (can I ask that you also raise tickets if there are any further issues - just helps me a bit to keep it all in one place :) )

I have made a change to support this. I guess the example you give is just that - an example - but I’ll say this anyway; a helper function for a link seems to be overkill. The following produce exactly the same result:




%a(href="http://www.siokia.com") www.siokia.com


=CHtml::link('www.siokia.com', 'http://www.siokia.com')


=lnk('http://www.siokia.com') www.siokia.com



The first is the preferred method as it does not require any function calls, and by using code interpolation you can easily parameterise the address.

This is a bug; I’ll fix it.

This is a "feature" in PHamlP. The Haml is passed through a regex to parse the lines, and the regex looks for class before id. I have no plans to fix this one - sorry.

Regards,

Chris

Fixes are in SVN

Wow Chrish, many thanks for your quick answer!! I’ll try your new version and will report the test comments.

I would like aks a question in relation with sass (I’m not using it yet). Is it possible to pass variables from php (controller or view files) to the sass files using sass variables? In such a case could you give me a short example?

By the moment, I’m using style files like “mycss.php” with text/css header (you know, the old trick) with some php variables for colour and such things inside.

Off topic:

What kind of human being could even think in understand this regexp?:


[b][b]const REGEX_HAML = '/(?m)^([ \x09]*)((?:<img src='http://www.yiiframework.com/forum/public/style_emoticons/default/sad.gif' class='bbc_emoticon' alt=':(' />\w*))?(?:%(\w*))?(?:\.((?<img src='http://www.yiiframework.com/forum/public/style_emoticons/default/sad.gif' class='bbc_emoticon' alt=':(' />?:[-_:a-zA-Z]|#\{.+?\})+(?:[-:\w]|#\{.+?\})*(?:\.?))*))?(?:#((?:[_:a-zA-Z]|#\{.+?\})+(?:[-:\w]|#\{.+?\})*))?(?:\[(.+)\])?(?<img src='http://www.yiiframework.com/forum/public/style_emoticons/default/sad.gif' class='bbc_emoticon' alt=':(' />\()((?<img src='http://www.yiiframework.com/forum/public/style_emoticons/default/sad.gif' class='bbc_emoticon' alt=':(' />?:html_attrs\(.*?\)|data[\t ]*=[\t ]*\{.+?\}|(?:[_:a-zA-Z]+[-:\w]*)[\t ]*=[\t ]*.+)[\t ]*)+\)))?(?<img src='http://www.yiiframework.com/forum/public/style_emoticons/default/sad.gif' class='bbc_emoticon' alt=':(' />\{)((?:<img src='http://www.yiiframework.com/forum/public/style_emoticons/default/sad.gif' class='bbc_emoticon' alt=':(' />?:html_attrs\(.*?\)|data[\t ]*=>[\t ]*\{.+?\}|(?:[_:a-zA-Z]+[-:\w]*)[\t ]*=>?[\t ]*.+)(?:,?[\t ]*)?)+\}))?(\|?>?\|?<?) *((?:\?#)|!!!|\/\/|\/|-#|!=|&=|!|&|=|-|~|\\\\\\\\)? *(.*?)(?:\s(\|)?)?)$/'; [/b][/b]

Are you sure u are human? Not robot? :P

Many thanks again,

Alex

First bug I encountered:

Whatever the reason, if I have a helper function like this:


public static function lnk_img($block, $alt, $url) {

            $image = CHtml::image($block, $alt);

            return CHtml::link($image, $url);

    }

I can use it as:


=lnk_img('Alt Text', 'site/contact') image.png

But if I use it with an array like this:


=lnk_img('Alt Text', array('site/contact')) image.png

It complains saying: Parse error: syntax error, unexpected ‘;’ in …

And in deed it is generating something like this:




<?php echo HamlHelpers::lnk_img('image.png','Alt Text', array('site/contact'); ?>

So it’s not inserting the last “)” parenthesis due to the helper function already has some parenthesis im $image variable. I think it’s something related with parsing the regexp of helpers. (I have another helper function not using parenthesis and it works fine passing arrays).

Regards,

Alex

Hello Chrish, could you check this issue with the helper functions?

Thanks in advance, Alex

Just back, so I’ll take a look at this.

Can I ask that bugs are reported through the project page http://code.google.com/p/phamlp/issues - it helps to have all the issues in one place. TIA

Fix in SVN

How to use compass? Nothing helps.

In you application configuration (usually main.php in app.config) you need something like:




'components'=>array(

  'assetManager'=>array(

    'class'=>'common.extensions.phamlp.PBMAssetManager',

    'parsers'=>array(

      'scss'=>array(

        'class'=>'common.extensions.phamlp.Sass',

        'output'=>'css',

        'options'=>array(

             .... // other options - looking at extensions here

          'extensions'=>array(

            'compass'=>array(

              // adjust the paths to suit and see Compass docs for all options

              'project_path'=>realpath(dirname(__FILE__).DIRECTORY_SEPARATOR.'..'),

              'images_path'=>realpath(dirname(__FILE__).'/../assets/images'),

              'http_images_path'=>'/images/image/path',

              'relative_assets'=>false // relative assets has a bug

            )

          )

        )

      ),

    )

  ),

  .... // other components

);



Then in your sccs file import compass;




@import compass



Hello,

great extension :slight_smile: I try to figure out how to work with asset manager and @import in scss files. How do you manage many scss files? For example i would like to have one scss file per widget (And only one css file in production), but my experiments with main.scss and @import rules wasn’t successful.

Thanks

Question is: why do you need this extension?

Using Sass/Compass is just a matter of installing Ruby and the Compass gem and run ‘compass watch’ - the css output will automatically update when the source files (scss/sass) changes.

IMO, you should only use phamlp when there is no other option.

Extak: Your question is best answered elsewhere, like the Sass homepage, or by means of a Google search for Sass tutorials.

You need to make sure the load_paths directive is set up in the extension config - which is in assetManager[‘parsers’][‘sass’][‘options’] in the main config file.

Hi,

This is a great extension, I’m currently using it to convert all of my views and styles to haml and sass.

One issue I’ve come across is that css files generated by this can get cached locally on individual users browsers. This is good as it speeds thing up a little, however we regularly release new code to production. This cacheing is causing a headache as users fail to receive the new versions. Is there anyway to add a version number/letter to the name of generated css files?

Regards

Andy