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","org.mozilla.javascript.tools.shell.Main","/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 https://github.com/cloudhead/less.js you can get the source and compile your own. Or you can use what thus guy put together http://www.asual.com/blog/lesscss/2009/11/05/less-for-java.html. That's what I did. Here is his Git repo: https://github.com/asual/lesscss-engine.

Actually, that's not right, I got it from this guys presentation notes here: http://dopefly.com/techblog/entry.cfm?entry=359
direct link: https://github.com/NathanStrutz/Write-LESS-CSS-Presentation-Material. 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.package.classtoinvoke','/path/to/jar/file/on/system')>

and that didn't give me the name of the 'class to invoke'. But the Rhino site 'http://www.mozilla.org/rhino/scriptjava.html' 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')#" />

UPDATE:
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", "java.io.File").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 dopyfly.com 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.

UPDATE:
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","org.mozilla.javascript.tools.shell.Main","/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