Skip to content
Mária Jurčovičová edited this page Jul 1, 2014 · 48 revisions

Source map links elements from compiled css file back to original less files. They are useful when troubleshooting large complicated less files. If the browser supports source maps, its debug tools works with original less files instead of compiled css version. More about source maps can be read on html5 rocks or tutplus sites.

Source maps are a new technology and are currently supported only by Chrome and nightly builds of Firefox.

This page starts with source mapping basics and then describes how to use LessCompiler interface to generate source maps. The last section describes how to move source maps around file system once they are created. Source map generation via command line is explained on another page.

Basics

Source mapping involves three different kind of files:

  • source map,
  • generated css,
  • original less files.

Source map, generated css and original less files can be either stored in separate files or embedded into each other. First sub-section explains the most common case - separate files. Second sub-section shows source map embedded into css and the last one shows less file embedded into source map.

Separate Files

Source map, generated css and original less files are linked to each other via relative references:

  • compiled css contains relative path to its source map,
  • source map contains relative path to compiled css,
  • source map contains relative path to original less.

Unless told otherwise, less4j assumes that original less, compiled css and generated source map are all stored in the same directory and their names differ only by suffix. It is possible to supply custom name and location for compiled css file, however source map name can not be customized.

If any of these relative paths does not work correctly, source map may not work. Therefore, renaming/moving source map or generated css involves more then just copying files around. If you rename or move any of these files without updating their relative references, source map stops to work.

Compiled css links source map - see the ending comment:

.class {
  margin: 1 1 1 1;
}
/*# sourceMappingURL=sampleInput.css.map */

Source map links both compiled css and original less file:

{
"version":3,
"file":"sampleInput.css", //relative path to compiled css
"lineCount":1,
"mappings":"AAAAA;",
"sources":["sampleInput.less"], //relative path to original less
"sourcesContent":[null],
"names":[".class"]
}

Source Map Inside Css

The sourceMappingURL generated in the end of the file supports the data URL scheme. Whole source map can be stored inside generated css. Such map is sometimes referred to as "inline". Inline source map still contains relative paths to original less files, so if you move them someplace else, you have to update the map too.

Above source map was Base64 encoded and embedded inside css file:

.class {
  margin: 1 1 1 1;
}
/*# sourceMappingURL=data:application/json;base64,ewoidmVyc2lvbiI6MywKImZpbGUiOiJzbS1pbmxpbmUuY3NzIiwKImxpbmVDb3VudCI6MSwKIm1hcHBpbmdzIjoiQUFBQUE7IiwKInNvdXJjZXMiOlsic20taW5saW5lLmxlc3MiXSwKIm5hbWVzIjpbIi5jbGFzcyJdCn0K */

Less Files Inside Source Map

Source map can contain content of compiled less files. This makes source map independent of original files locations. Following source map contains less files:

{
"version":3,
"file":"",
"lineCount":1,
"mappings":"AAAAA;",
"sources":[null],
"sourcesContent":[".class {\n  margin: 1 1 1 1;\n}"], //less file content is here
"names":[".class"]
}

Self-Contained Css With Source Map

Source map containing original source files can be embedded into generated css. Resulting css contains source map, is fully self contained, and can be moved around at wish.

Inline source map contains original less file:

.class {
  margin: 1 1 1 1;
}
/*# sourceMappingURL=data:application/json;base64,ewoidmVyc2lvbiI6MywKImZpbGUiOiIiLAoibGluZUNvdW50IjoxLAoibWFwcGluZ3MiOiJBQUFBQTsiLAoic291cmNlcyI6W251bGxdLAoic291cmNlc0NvbnRlbnQiOlsiLmNsYXNzIHtcbiAgbWFyZ2luOiAxIDEgMSAxO1xufSJdLAoibmFtZXMiOlsiLmNsYXNzIl0KfQo= */

Configuration

LessCompiler always creates source map. Keep in mind that if the compiler does not know .less and .css files locations, generated source map is not valid.

Css And Less Files Locations

Less location uri is known from input LessSource and css location uri is taken from cssResultLocation property of Configuration object. Css result location property is optional. If it is not available, the compiler will assume that generated .css file will be stored at the same location as original less file and will have the same name.

Miscelangous

Remaining source map configuration is stored in SourceMapConfiguration available from Configuration object. Available properties:

  • linkSourceMap
  • If set to false, generated css does not contain link to source map file.
  • Default: true.
  • inline
  • If set to true, whole source map is encoded and embedded into generated css.
  • Default: false.
  • includeSourcesContent
  • If set to true, content of compiled (source) files is included inside source map. Source map is independent of compiled less files locations.
  • Default: false.
  • relativizePaths
  • If set to false, final source map contains unmodified (absolute) paths to original less files. If set to true, generated map contains relative paths. Note that "correct" source map should contain relative paths. Use this option only if you need some kind of post processing on generated map.
  • Default: true.
  • encodingCharset
  • Source map and source map link encoding charset.
  • Default: UTF-8.
  • sourceMapNameGenerator
  • Supply custom generator for the url of the source map file.
  • Some browsers (Chrome (35) and Firefox (30)) are unable to find source map if its name does not correspond perfectly with css file name. If the system mangle sent css file name before sending it to the browser, for example adds version information, automatically generated source map url would not work correctly.
  • Default: the extension of original CSS source (.css) is replaced by .css.map.

Examples

Self-Contained Css With Source Map

Following code compiles src/sampleInput.less file, includes content of that file into source map and embeds everything into generated css:

File lessFile = new File("src/sampleInput.less").getAbsoluteFile();

LessCompiler compiler = new DefaultLessCompiler();
Configuration configuration = new Configuration();
configuration.getSourceMapConfiguration().setInline(true);
configuration.getSourceMapConfiguration().setIncludeSourcesContent(true);

CompilationResult compilationResult = compiler.compile(lessFile, configuration);
System.out.println(compilationResult.getCss());

Css looks like this:

.class {
  margin: 1 1 1 1;
}
/*# sourceMappingURL=data:application/json;base64,ewoidmVyc2lvbiI6MywKImZpbGUiOiIiLAoibGluZUNvdW50IjoxLAoibWFwcGluZ3MiOiJBQUFBQTsiLAoic291cmNlcyI6W251bGxdLAoic291cmNlc0NvbnRlbnQiOlsiLmNsYXNzIHtcbiAgbWFyZ2luOiAxIDEgMSAxO1xufSJdLAoibmFtZXMiOlsiLmNsYXNzIl0KfQo= */

Decoded source map contains original less file:

{
"version":3,
"file":"sampleInput.css",
"lineCount":1,
"mappings":"AAAAA;",
"sources":["sampleInput.less"],
"sourcesContent":[".class {\n  margin: 1 1 1 1;\n}], \\ original less file is stored here
"names":[".class"]
}

Less, Css And Source Map in The Same Directory

Following code compiles content of src/sampleInput.less file without specifying css file location:

File lessFile = new File("src/sampleInput.less").getAbsoluteFile();

LessCompiler compiler = new DefaultLessCompiler();
CompilationResult compilationResult = compiler.compile(lessFile);

System.out.println(compilationResult.getCss());
System.out.println(compilationResult.getSourceMap());

The compiler expects the map to be stored in src/sampleInput.css.map file and generated .css to be stored in src/sampleInput.css. Css looks like this:

.class {
  margin: 1 1 1 1;
}
/*# sourceMappingURL=sampleInput.css.map */

source map contains links to both compiled .css and original less files:

{
"version":3,
"file":"sampleInput.css",
"lineCount":1,
"mappings":"AAAAA;",
"sources":["sampleInput.less"],
"sourcesContent":[null],
"names":[".class"]
}

Inline Source Map, Less in The Same Directory

Following code compiles src/sampleInput.less file and embeds map into generated css:

File lessFile = new File("src/sampleInput.less").getAbsoluteFile();

LessCompiler compiler = new DefaultLessCompiler();
Configuration configuration = new Configuration();
configuration.getSourceMapConfiguration().setInline(true);

CompilationResult compilationResult = compiler.compile(lessFile, configuration);
System.out.println(compilationResult.getCss());

Css looks like this:

.class {
  margin: 1 1 1 1;
}
/*# sourceMappingURL=data:application/json;base64,ewoidmVyc2lvbiI6MywKImZpbGUiOiJzbS1pbmxpbmUuY3NzIiwKImxpbmVDb3VudCI6MSwKIm1hcHBpbmdzIjoiQUFBQUE7IiwKInNvdXJjZXMiOlsic20taW5saW5lLmxlc3MiXSwKIm5hbWVzIjpbIi5jbGFzcyJdCn0K */

Decoded source map is exactly the same as the one in above example:

{
"version":3,
"file":"sampleInput.css",
"lineCount":1,
"mappings":"AAAAA;",
"sources":["sampleInput.less"],
"sourcesContent":[null],
"names":[".class"]
}

All In The Same Directory 2

Using StringSource to supply uri of less file location without having to create the file:

URI uri = (new File("src/sampleInput.less")).toURI();
StringSource lessSource = new StringSource(".class { margin: 1 1 1 1; }", "sampleInput.less", uri);
    
LessCompiler compiler = new DefaultLessCompiler();
CompilationResult compilationResult = compiler.compile(lessSource);

It creates exactly the same .css and .css.map files as previous example.

CSS Will Be Stored Elsewhere

If you want to compile src/sampleInput.less into dist/sampleInput.css, then you can use following code:

File lessFile = new File("src/sampleInput.less").getAbsoluteFile();
File cssFile = new File("dist/sampleInput.css").getAbsoluteFile();
    
Configuration configuration = new Configuration();
configuration.setCssResultLocation(cssFile);
    
LessCompiler compiler = new DefaultLessCompiler();
CompilationResult compilationResult = compiler.compile(lessFile, configuration);

System.out.println(compilationResult.getCss());
System.out.println(compilationResult.getSourceMap());

The compiler expects the map to be stored in dist/sampleInput.css.map file, so the generated css looks like this:

.class {
  margin: 1 1 1 1;
}
/*# sourceMappingURL=sampleInput.css.map */

generated source map contains links to both compiled .css and original less files:

{
"version":3,
"file":"sampleInput.css",
"lineCount":1,
"mappings":"AAAAA;",
"sources":["../src/sampleInput.less"],
"sourcesContent":[null],
"names":[".class"]
}

CSS Will Be Stored Elsewhere 2

Using StringSource to supply uri of less file location without having to create the file:

File cssFile = new File("dist/sampleInput.css").getAbsoluteFile();
Configuration configuration = new Configuration();
configuration.setCssResultLocation(cssFile);

URI uri = (new File("src/sampleInput.less")).toURI();
StringSource lessSource = new StringSource(".class { margin: 1 1 1 1; }", "sampleInput.less", uri);
    
LessCompiler compiler = new DefaultLessCompiler();
CompilationResult compilationResult = compiler.compile(lessSource, configuration);

Moving Source Map

Moving .less, .css and .css.map files is straightforward as long as their relative positions do not change. However, if you move only some of these files or if you change their names, then you have to update their relative paths too:

  • change relative path from css to source map inside /*# sourceMappingURL=<name>.css.map */ comment at the end of css file,
  • change relative path from source map to css file inside file property of source map json,
  • change relative path from source map to less files inside sources property of source map json.