Thursday,
5 Nov 2009
LESS for Java
LESS is a cool project that has been around for a while and extends CSS with a few nice features like variables, mixins, operations and nested rules. The best thing about it is the syntax that feels very natural and easy to learn. I was eager to play with LESS but the main stopper for me was the fact that it is written in Ruby and I'm mostly involved in pure Java projects. It seems that my desire to try it was really strong because I sat down and lost almost a weekend in learning how JRuby works and finally produced a working prototype that only requires the Java 5 Virtual Machine. Over the last two months I was able to totally reorganize, extend and test the code base and I'm now finally glad to release it officially.
LESS for Java is a set of 2 modules that primarily target Maven 2 compatible projects but can also be used in any Java enabled environment:
- LESS Engine contains the original LESS codebase and provides a straightforward access to the underlying API. It has been designed as a core module that can be used various scenarios.
- LESS Servlet automatically compiles and serves LESS sources but also supports other resources like image and script files. It optimizes the server response by adding appropriate headers and applying the YUI Compressor for both CSS and JavaScript requests.
Both modules are already available on the official Maven 2 repository and you can start playing with them immediately. The current 1.2.11 version matches the snapshot of the original LESS distribution that has been used. The project has been successfully utilized on this website as well as in a bigger project built around Spring MVC and JSF. The source is available on GitHub where we're planning to put all our new open source stuff. Comments and feedback are welcome.
Comments:
The initialization of the JRuby engine is slow but after that you can compile CSS at fairly good speed. Have you tried that? I'm also processing files at runtime and I have put various optimization efforts in the LESS Servlet module. You can get some more info from this thread.
It's great to see the dependency on the original Ruby project rather than trying to write it from scratch ... makes it a lot easier.
Be well.
I have integrated your library into wro4j (an open source project used for web resource optimization for java): http://code.google.com/p/wro4j/ . The latest release (1.2.6) integrates your library! Keep up a good work!
* avalon-framework-4.1.3.jar
* commons-logging-1.1.jar
* commons-logging-api-1.1.jar
* jruby-complete-1.4.0RC1.jar
* lesscss-engine-1.2.11.jar
* lesscss-servlet-1.2.11.jar
* log4j-1.2.12.jar
* logkit-1.0.1.jar
* slf4j-api-1.5.6.jar
* slf4j-simple-1.5.6.jar
* yuicompressor-2.3.6.jar
However my Tomcat still gives a non-standard 404 message for any css files (I have '/*.css' mapped to the servlet), and there is absolutely nothing in the logs. Any ideas?
Can you please try downloading the latest version from GitHub. It contains lots of improvements and uses the new less.js codebase that requires Rhino instead of JRuby.
You can easily see what's going wrong with a little debugging. This website runs version 1.2.8 and I don't have the following in my lib folder:
* avalon-framework-4.1.3.jar
* commons-logging-api-1.1.jar
* logkit-1.0.1.jar
* slf4j-api-1.5.6.jar
* slf4j-simple-1.5.6.jar
Excellent, thanks, I'll do that straight away as I think we've had bad experiences with JRuby reliability in the past, so using Rhino will keep everyone much happier at the company. As it happens, in the meantime, I managed to figure out what the problem was anyway: I had to turn off the GZip compression we run here even though I didn't have compression enabled in LessCss (I think!); I'd removed this config from my servlet config, but the only thing that helped was disabling our main GZip compression filter:
<init-param>
<param-name>compress</param-name>
<param-value>true</param-value>
</init-param>
Anyway, thanks loads for your help here!!!
I've switched to 2.0 and Rhino, and not only does it work, but it delivers the first result much much faster. I couldn't get 'mvn install' for 'less-engine' or 'less-servlet' to run though. Thinking this was just some Maven problems, I ignored this and built it myself with Eclipse, but then started running into problems with the @import statement not working, and also the reload never working even though the CSS file has been edited. So, I just tried to run 'mvn install' again, in case I built it wrong, and I now immediately see that the Maven errors were genuine problems:
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.asual.lesscss.LessEngineTest
INFO : com.asual.lesscss.LessEngine - Initializing LESS Engine
INFO : com.asual.lesscss.LessEngine - The compilation of 'div { width: 1 + 1 }' took 32 ms.
INFO : com.asual.lesscss.LessEngine - The compilation of 'file:/D:/Development/DHTML/main/lesscss-engine/target/test-classes/META-INF/test.css' took 47 ms.
ERROR: com.asual.lesscss.LessEngine - Wrapped java.net.MalformedURLException: no protocol: import.css (/D:/Development/DHTML/main/lesscss-engine/target/classes/META-INF/engine.js#12)
ERROR: com.asual.lesscss.LessEngine - org.mozilla.javascript.WrappedException: Wrapped java.net.MalformedURLException: no protocol: import.css (/D:/Development/DHTML/main/lesscss-engine/target/classes/META-INF/engine.js#12)
Tests run: 3, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.922 sec <<< FAILURE!
Results :
Tests in error:
compileToFile(com.asual.lesscss.LessEngineTest)
Tests run: 3, Failures: 0, Errors: 1, Skipped: 0
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] There are test failures.
Please refer to D:\Development\DHTML\main\lesscss-engine\target\surefire-reports for the individual test results.
Any ideas why this might be happenning?
Thanks in advance, Dominic.
It seems that there is a problem with the @import code on Windows. I will investigate it in the next few days.
The reload is not working because by default the library settings are optimized for production. The servlet can be configured using init parameters or JNDI. Check the ResourceServlet source and see how the "cache" and "compress" properties are initialized.
I finnally got a chance to look into this again. I'm not going to be able to test it till tomorrow morning, but I finally got both the maven builds to pass by changing this line in 'engine.js':
var result, charset = 'UTF-8', dirname = file.replace(/[^\/]+$/, '');
to this instead:
var result, charset = 'UTF-8', dirname = file.replace(/[^\/\\]+$/, '');
Will let you know tomorrow if there are any further problems.
Sorry, I patched this yesterday but didn't mentioned it here. You can get the latest copy from GitHub.