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

Less4j uses LessSource interface to fetch imported files. Less4j does not care what is behind the LessSource interface as long as its implementation returns data or throws appropriate exceptions.

Default Implementations

Less4j provides following LessSource implementations:

  • 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.
  • 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.
  • 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

Three important methods:

  • relativeSource(relativePath) - get less source referenced by relativePath parameter,
  • String getContent() - importing of css and less,
  • byte[] getBytes() - returns file content in binary form.

The implementation 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

A common need is to add non-relative search paths for import statements. Search path is a directory with less files we would like to import e.g., functionality similar to less.js --include-path option.

Implementation

Create new LessSource type which would search for files in both current directory and in 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;
  }
  
}