[EXTENSION] LESS

Hello All,

This is the discussion thread for my LESS extension.

The extension allows you to use Agar’s amazing less.php compiler to compile LESS into CSS in your Yii-application. It also allows for compiling the LESS before each request, which is very handy in development environments.

What is LESS?

LESS is a dynamic stylesheet language which supports variables, mixins, nested rules, functions, etc. If you haven’t tried LESS you should definitely give it a go, you won’t be disappointed.

Download the extension here:

http://www.yiiframework.com/extension/less/

Fork me on Bitbucket:

https://bitbucket.org/Crisu83/yii-less/

More about LESS here:

http://www.lesscss.org

hi Chris,

Thanks for this extention , it’s exactly what i need for working whith your other amazing extention (bootstrap).

But i’m a newbie in yii so i did not succeed to combine the two extentions .

Did i must tu configure less extention to generate the style.css in folder generated by bootstrap extention /assets/95f7a8b8/css/bootstrap.min.css ?

thanks for your help

Hey yiiesss,

I use both extensions together on multiple projects and my setup is as follows:

I don’t call Yii::app()->boostrap->registerBootstrap(); in my main layout (because I don’t want to include the bootstrap css file). Instead I’ve configured the less compiler to compile less/styles.less to css/styles.css and include styles.css in my main layout. On the first line in my styles.less file I include the bootstrap.less:




@import "../protected/extensions/bootstrap/vendors/bootstrap/lib/bootstrap.less";



However, there is still a minor issue in the less.php compiler so you will need to remove the following comment from the bootstrap/lib/reset.less file:




/* Reset.less

 * Props to Eric Meyer (meyerweb.com) for his CSS reset file. We're using an adapted version here	that cuts out some of the reset HTML elements we will never need here (i.e., dfn, samp, etc).

 * ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */



This is because the compiler has an issue with parsing long comments so you won’t be able to compile Bootstrap. I’ve reported this issue and the author should fix this soon.

Hopefully this helps. Please don’t hesitate to ask if you have further questions.

thank you very much , that work for me ;)

New version available!

What’s new

  • Added support for checking if recompiling is necessary

  • Added support for compressing compiled CSS

  • Added support for enabling compiler debugging mode

  • Removed LessCompilationBehavior (redundant)

Get the new version here:

http://www.yiiframework.com/extension/less/files/yii-less-0.9.1.r17.zip

Hi,

There are a few issues with the current twitter bootstrap version.

This is because of an outdated version of the less/less.php library. The last update of the library was 4 month ago so i don’t think that there will be an update?

Can’t load ext form me. Whats wrong?


config/main.php


	'preload'=>array

	(

		'less',

		'log',

		'bootstrap',

	),

	'components'=>array

	(

		'lessComplier'=>array(

			'autoCompile'=>true,

			'class'=>'ext.less.components.LessCompiler',

			'paths'=>array(

				'/less/styles.less'=>'/css/style.css',

			)

		),

                [....]


[code]

16:15:21.978339 	trace 	system.CModule 	


Loading "log" application component

in C:\Users\User\www\z3usproject\index.php (13)


16:15:21.983776 	trace 	system.CModule 	


Loading "bootstrap" application component

in C:\Users\User\www\z3usproject\index.php (13)

Hey,

I tried to use this extension but I can’t get it to work.

That’s what I did:

  1. copy files into /protected/extensions/less

  2. edit main.php | config





'preload'=>array(

    'less', // preload the component to allow for automatic compilation

),

'components'=>array(

    'lessCompiler'=>array(

        'class'=>'ext.less.components.LessCompiler',

        'forceCompile'=>false, // indicates whether to force compiling

        'compress'=>false, // indicates whether to compress compiled CSS

        'debug'=>false, // indicates whether to enable compiler debugging mode

        'paths'=>array(

            'less/style.less'=>'css/style.css',

        ),

    ),

),




create a style.less file in my css directory and last including the styles.less in my main layout:


<link rel="stylesheet/less" type="text/css" href="<?php echo Yii::app()->request->baseUrl; ?>/css/styles.less" />

is there anything wrong with it? Have I missed something?

Cheers

-Seb

Hmm this issue still isn’t been solved. I just wanted to start using the bootstrap extension with the less php class. How do you solving this issue? i tried to compile the less code with simpleless but this doesn’t work at all.

@sebako look if you have the correct names

you are using

/css/style(s).less

and ‘less/style.less’=>‘css/style.css’, in your config without the (s).

I am using the LESS extension with Bootstrap-2.0.1, which works fine.

Hey dude. I did what was told on setup instructions but i can’t make it work. There is another setup action to do besides those described on extension page?

Hey Chris, thank you for extension. Cold u help me? I got this error

Less\Exception\CompilerException

#grid > .core is undefined

D:\Development\xampp\htdocs\vivaterra2.com.br\protected\extensions\less\lib\lessphp\lib\Less\Node\Mixin\Call.php(56)

44 return $rules;

45 } else {

46 throw new \Less\Exception\CompilerException(‘No matching definition was found for `’.

47 trim($this->selector->toCSS($env)) . ‘(’ .

48 implode(’, ', array_map(function ($a) use($env) {

49 return $a->toCss($env);

50 }, $this->arguments)) . ‘)`’,

51 $this->index);

52 }

53 }

54 }

55

56 throw new \Less\Exception\CompilerException(trim($this->selector->toCSS($env)) . " is undefined", $this->index);

57 }

58 }

Hi thiagovidal,

I got the same problem, the current phpless version can not parse the LESS used in Bootstrap 2.0.2, you have to use 2.0.1 with the current lessCompiler.

@Chris: Where did you get the phpless from http://leafo.net/lessphp/ ?

Best regards,

schmunk

ok. thank you dude. i’m using crunch instead. when someone solves the problem i will try again.

So I tried to integrate lessphp by leafo, but with my very limited exposure to Yii I guess it’s not great - it works.

I don’t yet understand caching in Yii so I’m not sure if it could be done better that way. Also as I understand it, the protected folder isn’t writeable so writing .less.cache files and compiling .less from extensions etc wouldn’t work with lessphp’s inbuilt caching.

The only method I could come up with by myself was to use the webroot/css directory to store the compiled css and cache files. I added lessc.in.php and my LessCss.php to extensions/less and used Yii’s method to hash the names so extensions wouldn’t clash. I’d love to know how what I’ve done should be done if anyone has the time?




public static function compile( $lessPath )

    {

        $cssDir = Yii::getPathOfAlias('webroot') . '/css/';

        $cacheDir = $cssDir . 'cache/';


        // generate hashed filename clashes don't occur in webroot/css

        $assetName = sprintf( '%x', crc32($lessPath) );


        $cssPath = $cssDir . $assetName . '.css';

        $cachePath = $cacheDir . $assetName . '.less.cache';


        if ( !file_exists($cacheDir) ) {

            mkdir( $cacheDir );

            chmod( $cacheDir, 0755);

        }


        // get previously cached .less or use input .less

        if ( file_exists($cachePath) )

            $cache = unserialize( file_get_contents($cachePath) );

        else

            $cache = $lessPath;


        // try compile .less

        try {

            require_once( dirname(__FILE__) . '/lessc.inc.php' );


            $newCache = lessc::cexecute( $cache );

        } catch ( exception $e ) {

            Yii::log( 'Failed to compile .less file, reason: ' . $e->getMessage(), 'error', '{LESS}' );

            return false;

        }


        // create new .less and .less.cache files if updated

        if ( !is_array($cache) || $newCache['updated'] > $cache['updated'] ) {

            Yii::trace( 'Passed and cached .less file: ' . $lessPath, '{LESS}' );

            file_put_contents( $cachePath, serialize($newCache) );

            file_put_contents( $cssPath, $newCache['compiled'] );

        } else

            Yii::trace('No modifications to .less file (since last cached): ' . $lessPath, '{LESS}' );


        // return compiled .css location

        return Yii::app()->baseUrl . '/css/' . $assetName . '.css';

    }

}



Then I can just use it like this, e.g:




Yii::app()->clientScript->registerCSSFile(

    LessCss::compile( Yii::getPathOfAlias('webroot') . '/css/normalize.less' )

);



Hi,

Thanks for taking the time of putting this together.

Quick question, how do you specify the paths for a less/css file living inside a theme? I’ve tried the following with no luck




...

'basePath'=> Yii:getPathOfAlias('webroot.themes.mytheme'),

'paths'=>array(

            'less/style.less'=>'css/style.css',

        ),



Thanks

Just define an alias




Yii::setPathOfAlias('themes', dirname(__FILE__).'/../../themes');



then declare the component as follows




'less'=>array(

            'class'=>'ext.less.components.LessCompiler',            

            'basePath' => Yii::getPathOfAlias('themes.new'),

            'forceCompile'=>true, // indicates whether to force compiling

            'paths'=>array(

                'less/main.less'=>'css/main.css',

            ),

        ),



Hi

I’ve changed a couple of things just to make it work like I want with Bootstrap, and since the extension (well, the lessCompiler.php) didn’t look correctly for files in the directory recursively (or it didn’t work for me)

In main.php, path option I have the files wrapper of Bootstrap:


protected/extensions/bootstrap/lib/bootstrap/less/bootstrap.less=>protected/extensions/bootstrap/assets/css/bootstrap.min.css

I wanted to compile de bootstrap.less whenever I edit any of the .less files in the directory that bootstrap.less imports.

To do this I had to modify the lessCompiler.php of the extension these two methods which I believe were wrong:




/**

	 * Returns whether any of files configured to be compiled has changed.

	 * @return boolean the result.

	 */

	protected function hasChanges()

	{

		$dirs = array();

		foreach ($this->paths as $source => $destination)

		{

			$compiled = $this->getLastModified($destination);

			if (!isset($lastCompiled) || $compiled > $lastCompiled)

				$lastCompiled = $compiled;


			if (!in_array(dirname($source), $dirs))

				$dirs[] = dirname($source);

		}


		foreach ($dirs as $dir) {                    

			$modified = $this->getLastModified($dir);                        

			if (!isset($lastModified) || $modified > $lastModified)

				$lastModified = $modified;

		}

                //ChromePhp::log(array(date("Y-m-d H:i:s",$lastModified),date("Y-m-d H:i:s",$lastCompiled)));

		return isset($lastCompiled) && isset($lastModified) && $lastModified > $lastCompiled;

	}


	/**

	 * Returns the last modified for a specific path.

	 * @param string $path the path.

	 * @return integer the last modified (as a timestamp).

	 */

	protected function getLastModified($path)

	{

		if (!file_exists($path))

			return 0;

		else

		{

			if (is_file($path))

			{

				$stat = stat($path);                                

				return $stat['mtime'];

			}

			else

			{

				$lastModified = null;


				/** @var Directory $dir */

				$dir = dir($path);

				while ($entry = $dir->read())

				{

					if (strpos($entry, '.') === 0)

						continue;


					$ruta = $path. '/'.$entry;


					if (is_dir($ruta))

						$modified = $this->getLastModified($ruta);

					else

					{

						$stat = stat($ruta);

						$modified = $stat['mtime'];

					}


					if (!isset($lastModified) || $modified > $lastModified)

						$lastModified = $modified;

				}


				return $lastModified;

			}

		}

	}



Good luck, and thanks for the great extensions anyway ;)

Hi - I’m sure I’m missing something simple but I’ve been working on this for hours and not even sure if I’m approaching it the correct way.

I want to make changes to bootstrap and hacking the css doesn’t seem like a smart idea as versions will change often. I’m using your bootstrap extension and have just now implemented your less extension.

To start with I just want to modify the navigation bar but eventually will edit more.

The less compiler is working correctly but I’m pretty sure I’m not putting the right things in the style.less file. I basically added the variables.less and navbar.less . When I compile it I see the style.css and it looks correct to me but when I refresh the page it 's exactly the same and nothing has changed.

I guess the extension includes the bootstrap.css and I should force it to use mine instead of maybe as well as? Not to sure how to progress now so any help would be appreciated.

Thanks

Lux

PS: Something else I’m sure is obvious but I’m missing is how is this making things more efficient? I guess I still have to include the bootstrap.css and now it looks like I have to also include the style.css which just duplicates much of the bootstrap.css with some modifications. What’s the point? What am I missing?

UPDATE: I just noticed the comment from Chris about not including bootstrap core with bootstrap by setting it to false in the bootstrap config which I’ve done so now everything is included in styles.css and my navigation changes are showing. Still not seeing the point other than I was able to use variables to change style sheet values easily.

Chris,

do you use only less/styles.less for design styles? On bootstrap site there is also docs.css

Your extension yii-bootstrap create

<link rel="stylesheet" type="text/css" href="/assets/9a4eed2/css/bootstrap.min.css" />

<link rel="stylesheet" type="text/css" href="/assets/9a4eed2/css/bootstrap-responsive.min.css" />

<link rel="stylesheet" type="text/css" href="/assets/9a4eed2/css/bootstrap-yii.css" />

but there is no docs.css

So I need insert styles from docs.css into styles.less?