less.js is a css
templating language with a javascript file to convert templates into
a CSS file.
The less.js
distribution includes a Rhino patch to run less.js from the command
line using rhino. less.js no longer produces a Rhino
version, but the patch remains available in the master branch.
less.js 1.3.0 uses
ECMA-5 and will attempt to upgrade the Object and Array prototypes if
run in a non-ECMA-5 environment. This prevents the script running in
many ECMA environments that ship with jdk6.
There are two
popular jars available that provide a Java API for less.js. Both of
them use Rhino to run the script in the JVM.
Asual`s has been
around longer and hacks the rhino patch to run as a library. Asual
requires the latest version of Rhino.
lesscss-java
claims to be the official java version and includes envjs (mimic a
browser's script environment for running html apps offline). This
allows the library to run less.js just as it would run in the
browser. Envjs requires the latest version of rhino.
If you try and run
less.js using the ECMA script in jdk6, you may find that the core
object/prototypes are sealed and cannot be extended.
The version of ECMA
script on Mac jvms seems to be only ECMA-3.1 or JavaScript 1.5. To
run less.js you have to patch it to use utility functions instead of
ECMA-5 functions. less.js also requires window and document objects to function. However, you can get away with the following environment.
var window = {};
var location = {port:0};
var document = {
getElementsByTagName: function(){return []},
getElementById: function(){return null}
};
var require = function(arg) {
return window.less[arg.split('/')[1]];
};
var window = {};
var location = {port:0};
var document = {
getElementsByTagName: function(){return []},
getElementById: function(){return null}
};
var require = function(arg) {
return window.less[arg.split('/')[1]];
};
less.js uses XMLHttpRequest to import referenced documents. If you want to load other files yourself, best to override the window.less.Parser.importer function.
The function takes (path, paths, callback, env), where path is the import url, paths is an array (passed in from the constructor options), callback is a function to send the results, and env is the constructor options. The callback takes (e, root, content), where e is a thrown error, root is the parse tree and content is the file's contents (for error reporting). Here is a skeleton of the code you would need to run on jdk6.
var contents = {};
window.less.Parser.importer = function(path, paths, callback, env) {
if (path != null) {
var uri = new java.net.URI(paths[0]).resolve(path).normalize();
var content = ... // TODO read the uri content as a string
var dir = uri.resolve(".").normalize();
var file = dir.relativize(uri).toASCIIString();
contents[file] = content;
var parser = new window.less.Parser({
optimization: 3,
filename: file,
opaque: true,
paths: [dir.toASCIIString()]
});
parser.imports.contents = contents;
parser.parse(content, function (e, root) {
if (e) throw e;
callback(e, root, content);
});
}
};
To help debug less.js errors the above has a fix for issue 592. All new window.less.Parser have a imports.contents map and this map needs to have the basename of any imported file to resolve error locations. If the map does not contain the basename, a charAt error is thrown.
If running server
side you may also be interested in this patch to inline both less and
CSS files. The opaque flag above turns this on.