Skip to content
Mária Jurčovičová edited this page Jul 12, 2015 · 10 revisions

Less4j uses LessSource interface to fetch imported sheets, images to be inlined or other referenced data. Its default implementations are able to load them from filesystem, url or a string. They also allow you to add search paths for import statements e.g., functionality similar to less.js --include-path option.

First section describes less source implementations available out of the box. The rest of the page explains how to write your own less source.

Default Implementations

Compiling less sheets stored in a string:

  • StringSource - input less sheet is stored in a string. This class is unable to load imported files. Compiler will be unable to load imported files, less @import statements are compiled into css @import statement instead of being processed.
  • MultiPathStringSource - input less sheet is stored in a string. Allows you to configure additional list of paths which will be used for imports. This source is less4j equivalent of --include-path less.js option.

Compiling less sheets stored on filesystem:

  • FileSource - loads less sheets from filesystem. Import statements are assumed to be relative to that file.
  • MultiPathFileSource - loads less sheets from filesystem. It is useful if you need to configure additional list of paths which will be used for imports. This source is less4j equivalent of --include-path less.js option.

Compiling less sheets specified by its url:

  • URLSource - loads data from URL. It supports http, https, jar, ftp, gopher and mail protocols (e.g. all protocols supported by java.lang.URL). Import statement are assumed to be relative to that url.

Writing Own Less Source

Every LessSource implementation must override three methods:

  • relativeSource(relativePath) - get less source referenced by relativePath parameter,
  • String getContent() - return sheet as string,
  • byte[] getBytes() - return source content binary form.

LessSource implementation may customize two methods:

  • URI getURI() - less source location uri or null. If non-null, last path part must be equal to whatever getName returns. The uri is used in generated source map.
  • String getName() - less source name used for error reporting.

The implementations of equals and hashCode matters. Import uses them to check for multiple imports of the same file and to compile libraries imported as reference. The equals should return true if and only if two less source objects point to the same underlying less resource.

Usage

Custom less source is used via LessCompiler.compile(LessSource inputFile) method:

//create demo less file and compiler
File inputLessFile = createFile("sampleInput.less", "* { margin: 1 1 1 1; }");
LessCompiler compiler = new ThreadUnsafeLessCompiler();

//use custom less source
CompilationResult compilationResult = compiler.compile(new CustomFileSource(inputLessFile));

//print compiled css
System.out.println(compilationResult.getCss());

Example - Customize Import Directory

This section shows custom LessSource type to search for sheets in both current directory and in single custom non-relative paths. The easiest way to do it is to override build-in FileSource.

Custom less source overrides the relativeSource method. Overridden method searches for relative file in all searchPaths:

public class CustomLessSource extends LessSource.FileSource {

  private final List<String> searchPaths;

  /* Skipped remaining constructors for better 
   * readability. They are the similar to those in 
   * FileSource. The only difference is in first 
   * searchPaths parameter. */
  public CustomLessSource(List<String> searchPaths, FileSource parent, File inputFile, String charsetName) {
    super(parent, inputFile, charsetName);
    this.searchPaths= searchPaths;
  }

  /** 
   * Find referenced file in current path or one of
   * search paths. Create new instance of 
   * CustomLessSource. */
  @Override
  public FileSource relativeSource(String filename) {
    // use createRelativeFile method to find referenced file
    return new CustomLessSource(searchPaths, this, createRelativeFile(filename), null);
  }

  /**
   * Looks for relative in current directory. If not 
   * found searches through all searchPaths directories.  */
  protected File createRelativeFile(String filename) {
    File thisFile = getInputFile();
    if (thisFile==null)
      return null;
    
    File thisDirectory = thisFile.getParentFile();
    File inputFile = new File(thisDirectory, filename);
    Iterator<String> cpIterator = searchPaths.iterator();
    while (!inputFile.exists() && cpIterator.hasNext()) {
      inputFile = new File(cpIterator.next(), filename);
    }
    
    return inputFile;
  }
  
}