Less.js: less.render is not working with @import files which are in different directories in nodejs

Created on 17 Dec 2014  ·  2Comments  ·  Source: less/less.js

I have used LESS to implement theming in my application and using nodejs less module to compiling less files to CSS but its not working in one particular scenario.

I am also using Bootstrap for my application and using Bootstrap less source code I am compiling only that css which I want in my application.

I can also override Bootstrap variables and mixins in my various themes. So, while compiling Bootstrap I need to consider particular theme variables and mixins as well.

So, differentiate Bootstrap variables/mixins and CSS rules I have created 2 different files,

  • application_variables.less - It contains all required Bootstrap variables and mixins
  • application.less - It contains all required Bootstrap CSS Rules

Directory structure For the application

|--sample_application
    |--resources
    |   |--libraries
    |      |--bootstrap
    |           |--css
    |           |   |--application.less
    |           |--less
    |           |   |--application_variables.less    
    |--themes
        |--red
        |   |--mixins
        |   |   |--mixins.less
        |   |--variables
        |   |   |--variables.less    
        |   |--red.less    
        |--blue
        |   |--mixins
        |   |   |--mixins.less
        |   |--variables
        |   |   |--variables.less    
        |   |--blue.less    
        |--themes.less

Explanation of which file contains what?

1. /sample_application/themes/<-theme_name->/mixins/mixins.less
This file contains all application specific mixins and overridden bootstrap mixins.

.my-hover-mixin(@color) {
   &:hover {
       border: 2px solid @color;
    }
}
/*Other theme specific mixins*/

2. /sample_application/themes/<-theme_name->/variables/variables.less
This file contains all application specific variables and overridden bootstrap variables.

@text-color:#333333;
@border-color:#999999;
@body-bg-color:red;
/*Other theme specific variables*/

3. /sample_application/themes/<-theme_name->/<-theme_name->.less
This file contains file imports of mixins and variables for that particular theme.

@import "./variables/variables.less";
@import "./mixins/mixins.less";

4. /sample_application/themes/theme.less
This file contains two file imports. First one for Bootstrap variables which is application_variables.less and second one for particular themes' base file imports for eg. red.less/blue.less

@import "application_variables.less";
@import "red/red.less";

5. /sample_application/resources/libraries/bootstrap/css/application.less
This file contains one file import which is /themes/themes.less and all required Bootstrap CSS Rules.

@import "theme.less";
/*Bootstrap CSS rules*/

6. /sample_application/resources/libraries/bootstrap/less/application_variables.less
This file contains all required Bootstrap variables and mixins.

/*Bootstrap variables and mixins*/

Now I have one node script file which dose the bootstrap less compilation which is compile-bootstrap.js

var fs = require("fs");
var less = require('less');

(function() {
    var bsLessContent = fs.readFileSync("sample_application/resources/libraries/bootstrap/css/application.less");
    less.render(bsLessContent.toString(), {
        paths : [ "sample_application/themes/", "sample_application/resources/libraries/bootstrap/less/"],
        compress : true
    }, function(e, output) {
        fs.writeFileSync("sample_application/resources/libraries/bootstrap/css/application.css", output);
    });
})();

But when I run this script I am getting following error

{ [Error: 'application_variables.less' wasn't found]
   type: 'File',
   message: '\'application_variables.less\' wasn\'t found',
   filename: 'sample_application\\themes\\theme.less',
   index: 18,
   line: 2,
   callLine: NaN,
   callExtract: undefined,
   column: 0,
   extract:
    [ '@import "application_variables.less";',
      '@import "red/red.less";' ] }

Then I tried using relative paths as well but still its giving the same error

{ [Error: './../resources/libraries/bootstrap/less/application_variables.less' wasn't found]
   type: 'File',
   message: '\'./../resources/libraries/bootstrap/less/application_variables.less\' wasn\'t found',
   filename: 'sample_application\\themes\\theme.less',
   index: 18,
   line: 2,
   callLine: NaN,
   callExtract: undefined,
   column: 0,
   extract:
    [ '@import "./../resources/libraries/bootstrap/less/application_variables.less";',
      '@import "red/red.less";' ] }

Most helpful comment

Note that since the source is supplied to the compiler as a string you need to explicitly set the original file path so the compiler can use it as the base one for imports and so, otherwise it just can't know what are all those paths you specify are relative to (most likely it will use just cwd but it's pretty much "random" at the time it actually comes to imports and it does not necessary point to your project root anymore...). E.g.:

var fs   = require('fs'),
    path = require('path'),
    less = require('less');

(function() {
    var src = "foo/bar/baz.less";
    less.render(fs.readFileSync(src).toString(), {
        filename: path.resolve(src), // <- here we go
    }, function(e, output) {
        console.log(output.css);
    });
})();

The same goes for the paths option, if I'm not mistaken in this case they should be either absolute or relative to the filename. In general it's a good idea to learn how lessc itself handles these things.

All 2 comments

Note that since the source is supplied to the compiler as a string you need to explicitly set the original file path so the compiler can use it as the base one for imports and so, otherwise it just can't know what are all those paths you specify are relative to (most likely it will use just cwd but it's pretty much "random" at the time it actually comes to imports and it does not necessary point to your project root anymore...). E.g.:

var fs   = require('fs'),
    path = require('path'),
    less = require('less');

(function() {
    var src = "foo/bar/baz.less";
    less.render(fs.readFileSync(src).toString(), {
        filename: path.resolve(src), // <- here we go
    }, function(e, output) {
        console.log(output.css);
    });
})();

The same goes for the paths option, if I'm not mistaken in this case they should be either absolute or relative to the filename. In general it's a good idea to learn how lessc itself handles these things.

Thanks seven-phases-max. This solution is working fine hence closing the issue.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

heavyk picture heavyk  ·  3Comments

briandipalma picture briandipalma  ·  6Comments

BrianMulhall picture BrianMulhall  ·  4Comments

seven-phases-max picture seven-phases-max  ·  6Comments

pknepper picture pknepper  ·  3Comments