The Dopefly Tech Blog

<< The Dopefly Tech Blog Main page

LESS in Java: Running LESS CSS on the JVM

posted under category: CSS on September 13, 2011 at 10:23 pm by MrNate

Foreword: I am giving a LESS CSS talk at the Adobe MAX 2011 ColdFusion Unconference. Blogging about LESS is just one of my stepping stones to presenting. If you want the really good stuff, you should come to my session!


I recently blogged about LESS ports to other platforms, and I thought about mentioning Java there, but this is not a port so much as just reusing the native implementation. Let me break it down like this: Yes, LESS runs on the Java Virtual Machine. It's not even that hard. How you may ask? Like this...

Mozilla makes browsers and Javascript engines. One of their Javascript engines is called Rhino, a JSR 223 compliant Javascript engine for the JVM. You can run any Javascript in Rhino, except that there is no browser, no window, no document and no DOM (I know, it sounds like a dream come true). The conflict comes where LESS.js relies on browser constructs to get its job of compiling and preprocessing LESS CSS into plain CSS, so we have to defeat that.

Lucky for us, we live in the future, and along with our flying cars, we also have Google and GitHub, which pointed me to Asual's project, lesscss-engine. Asual is a software company in Bulgaria, and their GitHub projects are run by Rostislav Hristov.

The easiest method of setting up Asual's solution is to download his browser.js and engine.js, then from Rhino, within Java, include them in the order of browser.js, less.js, then engine.js - the order is important. I did this in an Ant build file like this:

<script language="JavaScript" src="browser.js" />
<script language="JavaScript" src="less.js" />
<script language="JavaScript" src="engine.js" />


From there it's just a matter of calling the engine methods to load LESS CSS code, convert it to CSS and output to a file. Here is how I did it, this is my code that is directly after the script loading:

<script language="JavaScript"><![CDATA[
var inputFile = readFile('input.less');
var css = compileString(inputFile);
writeFile('output.css', css);

function writeFile(filename, content) {
var fstream = new java.io.FileWriter(filename);
var out = new java.io.BufferedWriter(fstream);
out.write(content);
out.close();
}
]]></script>

The engine.js has a number of good helper methods (readFile, writeFile, compileString, etc.), I did it this way in case there were more LESS files to compile and I wanted to add it to the same css output string. When you do this, make sure you have the Rhino file, js.jar, in your Ant classpath. In Eclipse I loaded the external jar by adding it to the 'Run as...' dialog when you right-click on your build.xml file. Also make sure you are on Java 1.6+ to support JSR 223 Java Scripting.

You aren't limited to compiling LESS when you do this, you know. You can actually do anything you want in Javascript from right inside your Ant build file. It's fantastic.

There are other methods of accomplishing the same goal. Erwan Loisant did something similar by altering the core LESS.js files (including the proper pull request). While he calls his release LESS for Rhino, it's really more of LESS for Ant. Even still, it works great as a rhino-javascript-ant all-in-one solution. I especially like his use of an Ant macrodef to create a <lessjs> tag. His examples work straight across from his blog, perfectly.


Not content to rest on my laurels, I went back to the Asual's LESS Engine project to see if I could make a jar and see what I could do with it. I cloned the GitHub repository locally over http, then I added it as a project to Eclipse. I had to install Maven, which was simple with Eclipse's software installer, and running it is almost exactly like running an Ant build. When you build the project you get a few jars in the target/ folder. I recommend using the lesscss-engine-1.1.4-jar-with-dependencies.jar file, as it's the most likely to work anywhere you need it.

When I checked the LessEngine class, I noticed a main method that was added recently, which means we can call it from the command line, like so:

java -jar lesscss-engine-1.1.4-jar-with-dependencies.jar input.less output.css


Incidentally, if Asual (or someone) were to add a -w command line switch to watch the input file for changes, this would essentially make it identical to the Ruby LESS compiler, lessc. Except, of course, it would be much faster. Just a thought.

So we can call it from the command line. The next, most obvious step, is to put this in an Ant build. This was so simple. Here is what I did:

<java jar="lesscss-engine-1.1.4-jar-with-dependencies.jar" fork="true" dir="${basedir}">
<arg value="input.less" />
<arg value="output.css" />
</java>


Copy and paste that, with the jar, and it will all work as advertised.


To summarize, You can compile LESS on Java. It's fun and easy to do!

If you want to get all the files, or want to see it in action, I'm doing this talk September 28, 2011 at the AZCFUG in Tempe, AZ, then at Adobe Max on October 5th, then again October 12th at the Tucson CFUG. Look forward to more of this kind of chatter here on this blog.

Post A Comment!
On Sep 18, 2011 at 11:46 AM Your name is required. (This.is.not@aol.com or @valid.address.com) said:
So is that JAR downloadable from somewhere?

On Sep 26, 2011 at 7:42 AM Marcel Overdijk (marceloverdijk@example.com who would have preferred an address at gmail.com) said:
Why do you think Erwan's pull request is more LESS for Ant than Less for Rhino? This statement is completely wrong!

You have nice blog entry explaining everything in details. To bad the information is incorrect.

On Sep 26, 2011 at 8:28 AM Nathan Strutz (www.dopefly.com) said:
Marcel, I tried it out, I really do like what he did, but I had trouble running it outside of the Ant context. I exchanged a few emails with Erwan, he conceded that it was only meant for Ant, and needs a little work before it works for Rhino universally. Did you try it yourself? I'd like to be proven wrong, but leaving inflating comments on a random blog is not helpful. Show me the code.

On Sep 27, 2011 at 11:45 AM Marcel Overdijk (marceloverdijk at the endearing gmail.com) said:
Yes, for me it worked partially.

I did:

File lessJs = new File(LessRhinoTest.class.getClassLoader().getResource("less/less-rhino-1.1.3.js").toURI());
File input = new File(LessRhinoTest.class.getClassLoader().getResource("less/test.less").toURI());

FileOutputStream fos = new FileOutputStream(new File("C:/test/test.css"));
PrintStream ps = new PrintStream(fos);

org.mozilla.javascript.tools.shell.Main.setOut(ps);
org.mozilla.javascript.tools.shell.Main.main(new String[] { lessJs.getAbsolutePath(), input.getAbsolutePath() }) ;

which generated the css successfully (without any use of Ant).

However it seems not to be working with less @import statements, but neither does the Ant macrodef.

Erwan tried it himself and it worked form him so it might be related to (Windows) environment. Erwan was looking into this.

Cheers,
Marcel
Post A Comment!