LESS in XWiki, Post Mortem of an integration

Last modified by Guillaume Delhumeau on 2023/03/09 11:37

Jun 29 2015

LESS is a language that extends CSS by adding new features such as variables, mix-ins (kind of functions), etc... It makes CSS development more efficient and maintainable and is used by one of the major CSS frameworks available: Bootstrap.

Last year, we have integrated the LESS compiler in XWiki. At first, the purpose was to create a new look & feel based on Bootstrap, compatible with existing color themes. Quickly, we have encountered the need to execute some LESS code on-the-fly, and proposing a LESS compiler in XWiki was the unique solution.

Rhino

At the time we started, there were no many alternatives. Since LESS was written in JavaScript, the first idea was to execute it through Rhino, the JavaScript interpretor for Java. We used a fork of the official LESS CSS Compiler for Java to achieve this.

The first issue was that an important feature of LESS was not working on the Rhino version. We have fixed it locally by patching our own version of less-rhino.js, waiting for the LESS team to fix it properly.

An other limitation was the fact that it only compiles files. So for each LESS document stored in the database, a file is created in the temporary directory before the compilation. Which becomes costly when you have LESS documents that includes some others.

The second issue, is that the performances were really bad, compared to the NodeJs version. We have minimized this problem by putting a cache (we only execute LESS when the input has changed), but it was still slowing down the startup for at least 10 seconds!

Cache

Moreover, caching the results was not that simple. The cache key should contain different variables, such as the skin name, the theme used, the file compiled but also the URL serializer used to generated the resources URLs. To avoid having the same LESS resource computed twice in the same time, we had also introduced a mutex based on the resource identity.

But because of the cache, we had an other issue: the breakage of the HTML export feature. This action creates a ZIP file containing the wiki page and all the related resources (CSS files, images used in the content, etc...). Some of the resources exported are identified during the CSS generation, that triggers some events to mark which resources are used. But because of the cache, these events were no longer triggered and the resources were not exported in the Zip. So for each HTML export, we had to trigger these events, without recompiling the whole LESS file that would be too costly.

As you can see, designing this cache was more complex than predicted.

Less4J

Fortunately, a full java version of LESS had appeared: Less4J. Its performances are really better than the official rhino version.

But the project had some bugs and we failed to have it in XWiki 6.4, which was the last version of the 6.x cycle.

Its author, Mária Jurčovičová, that I thank warmly, fixed all these bugs quickly. We finally were able to integrate Less4J in XWiki 7.0!

An other great thing was the ability to create a custom InputSource. So we could give to the compiler some InputStream to read LESS documents from the database without copying them on the file system first.

Note that even if the LESS compilation is faster with Less4J, we still need the cache system. 

A risky choice ?

Depending on a project like Less4J where there is actually... only one maintainer is risky. On the other hand, this maintainer is very active and friendly, and the project is so much better than the rhino version that it is the best choice for now. Let's see how it evolves in the future.

Conclusion

I would not have imagined that integrating LESS in XWiki would be so complex. Since it was done for the purpose of creating the new Flamingo skin, it explains why the development of this new skin was a bit long.

Now I can only hope that a new CSS preprocessor will not emerge and become the new standard, and that the work invested in the LESS integration will be re-used for new skins! ...