Sunday, November 6, 2011

Railo Coldfusion & Less CSS (java implementation)

I just spent the last 4 hours figuring this out. I had to blog this to help someone - and my future self.

I wanted to start using Less and I want to compile it server side only when I need to. I have some url parameters, which can only be run from the admin login, that I use to reset certain caches and things. In this case I want it to recompile my less css only when I want to. So I need to set up a script to trigger and run the less css compiler. Railo is the BEST server wide web engine and it can tap into java like it's butter. I discovered that java has a server-side javascript engine called Rhino. A lot of trendy groups are there are implementing server-side javascript. I don't tend to get trendy, but I love the idea for very specific application uses. Anyway. With this Rhino we can implement the original Less.js compiler server-side. Sweet! Not so fast... People have tried to do this with Coldfusion and I can't get them to work (4 hours worth of attempts).

I finally figure out my own implementation - thanks to railo's native java loader - TWO LINES OF CODE!!!

<cfset variables.javajs = createObject("java","","/jars/js.jar")>
<cfset variables.javaless = createObject("java","com.asual.lesscss.LessEngine","/jars/lesscss-engine-1.1.4.jar")>

I'm going to try to retrace my steps...

From you can get the source and compile your own. Or you can use what thus guy put together That's what I did. Here is his Git repo:

Actually, that's not right, I got it from this guys presentation notes here:
direct link: That's where I got the "lesscss-engine-1.1.4.jar".

From even with the "js.jar" and the "lesscss-engine-1.1.4.jar" I couldn't get things to work. I had forgotten my Java schooling.

I hate the javaloader.JavaLoader crap. And it's old school. Railo can do it - natively. But I could scratch *how*. I googled and googled and I always thoguht it would be so simple. I finally googled and found the class to invoke. Railo's example code only gives you this:

<cfset object = createObject('java','','/path/to/jar/file/on/system')>

and that didn't give me the name of the 'class to invoke'. But the Rhino site '' did. And then from the code samples from Nathan Strutz presentation notes sample code I got the "com.asual.lesscss.LessEngine" class name for the 'js.jar'.

So now we're in business!

Here's how to compile the styles.less code into styles.css:

<!--- get your source styles.less from a cffile read or from in string, whatever, in a variable, say, 'variables.lessSource' --->
<cfset variables.outputcss = variables.javaless.compile(variables.lessSource) />
<!--- Then output the 'variables.outputcss' into <style></style> tags or do a cffile write to styles.css file and link the in the css file --->

That's it.

While I'm writing all this I get some other thoughts. You might even be able to pass in a source file path and write it right back to a cffile write -- but I haven't tested that yet. But in theory, maybe like this:

<cffile action="write" file="/path/to/css/styles.css" output="#variables.javaless.compile('/path/to/source/styles.less')#" />

The above didn't work because it's expecting a java type file stream. This works:
<cffile action="write" file="#expandPath('/')#cssjs/test.css" output="#variables.javaless.compile(CreateObject("java", "").init("#expandPath('/')#cssjs/less/test.less"))#" />

That would be slick - but again, just a theory, untested.

Now, while trying to retrace by steps over the last 4 hours I also discovered from a final note from the blog post mentioned above that there is a low level C implementation of the LESS compiler int he git repo, "lessc". There might had been a simpler implementation via the cfexecute tag to process styles.less files into styles.css files. I'll give that try another day.

This is way more complicated than I expected. It requires nodejs to be installed. I actually tried it and ran into dependency issues. If someone gets this command line lessc to work on ubuntu command line, please drop a comment.

That's a nice wrap! From bloated implementations with tricky dependancies I got it down to three lines of code! Haha!
Here it is again (excluding code to get the less source and write the output css file):

<cfset variables.javajs = createObject("java","","/jars/js.jar")>
<cfset variables.javaless = createObject("java","com.asual.lesscss.LessEngine","/jars/lesscss-engine-1.1.4.jar")>
<cfset variables.outputcss = variables.javaless.compile(variables.lessSource) />

This is proof of concept which I have working successfully.

1 comment:

AJ Mercer said...

Woah! Worked first time :-)

Thanks for the write up and thanks to Nathan Strutz for the JARs