Skip to content
Randy Merrill edited this page Jul 5, 2016 · 20 revisions

Examples of the Less Middleware

The Less middleware is designed to allow for many different types of uses. Herein are some of the more common uses or methods for achieving awesomeness with Less.

Different src and dest

By default, the compiled css files are stored in the same directory as the source files. A dest option specifies that the compiled css will be stored in a different directory.

var lessMiddleware = require('less-middleware');

var app = express();
app.use(lessMiddleware(path.join(__dirname, 'source', 'less'), {
  dest: path.join(__dirname, 'public')
}));
app.use(express.static(path.join(__dirname, 'public')));

Requests for static assets (like stylesheets) made to the express server use a pathname to look up the file. So if the request is for http://example.com/stylesheets/styles.css the pathname will be /stylesheets/styles.css.

The Less middleware uses that pathname to determine where to look for Less files. In the example it looks for the Less file at /source/less/stylesheets/styles.less and compiles it to /public/stylesheets/styles.css to be served by the static middleware.

Using a different source and dest options causes for more complex directories structures unless you do some preprocessing on the less path. In our example all the less files would need to be under /source/less/stylesheets/ when you really just want to have all your Less files in /source/less. To make this work you can add a preprocess option for the path:

var lessMiddleware = require('less-middleware');

var app = express();
app.use(lessMiddleware(path.join(__dirname, 'source', 'less'), {
  dest: path.join(__dirname, 'public'),
  preprocess: {
    path: function(pathname, req) {
      return pathname.replace(path.sep + 'stylesheets' + path.sep, path.sep);
    }
  }
}));
app.use(express.static(path.join(__dirname, 'public')));

Shared Paths for source and dest

Another way of organizing your Less files is to use a shared path and use separate directories for the Less and CSS files. From this shared root, you would specify a URI style path to the appropriate source and destination sub directories:

var lessMiddleware = require('less-middleware');

var app = express();
app.use(lessMiddleware('/less', {
  dest: '/css',
  pathRoot: path.join(__dirname, 'public')
}));
app.use(express.static(path.join(__dirname, 'public')));

This will use Less files from the /public/less path to be compiled to /public/css.

Modifying the less path

Normally the less path reflects the css path exactly. We have shown how to separate the directories of the less and css but sometimes you just need more control over that separation. This is where the path preprocessing is really helpful.

For this example, we want our styles served from the /public/styles path but the less files to be stored in /less.

Without preprocessing, this would make a request for example.com/styles/myStyles.css look for /less/styles/myStyle.less. With preprocesssing, a request for example.com/styles/myStyles.css will instead look for /less/myStyle.less.

var lessMiddleware = require('less-middleware');

var app = express();
app.use(lessMiddleware(path.join(__dirname, 'less'), {
    preprocess: {
        path: function(pathname, req) {
            return pathname.replace(/\/styles\//, '/');
        }
    },
    dest: path.join(__dirname, 'public')
});
app.use(express.static(path.join(__dirname, 'public')));

Using a temp directory for dest

Since less middleware relies on static content to be served by express.static, using temp directories requires that you inform the static middleware about the location of the generated files:

var lessMiddleware = require('less-middleware');

var app = express();
var tempDir = path.join(os.tmpDir(), 'css-cache');
app.use(lessMiddleware(path.join(__dirname, 'source', 'less'), {
  dest: tempDir
}));
app.use(express.static(tempDir));

Using a temp directory is useful for read-only file systems, such as a Heroku deployment. By using a temp directory the css files can still be written and served.

Security warning: Make certain that you use a subfolder within the temp directory so the entire temp directory is not publicly serving.

Importing less

By default the directory in which the compiled files lives in is already set as an import directive:

file1.less

@import 'file2.less';

body {
  color: @bodyColor;
}

file2.less

@bodyColor: #333333;

However, you can use the paths option if you need to specify other directories in which to search for importable less files.

var lessMiddleware = require('less-middleware');

var app = express();
app.use(lessMiddleware(path.join(__dirname, 'public'), {
  render: {
    paths: [ path.join(__dirname, 'module', 'less') ]
  }
}));
app.use(express.static(path.join(__dirname, 'public')));

public/base.less

@import 'colors';

body {
  color: @bodyColor;
}

module/less/colors.less

@bodyColor: #333333;

Using bootstrap

Here's an example on how to use Twitter's bootstrap within an Express.js set-up:

lessMiddleware = require('less-middleware');

var app = express();
var bootstrapPath = path.join(__dirname, 'node_modules', 'bootstrap');
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use('/img', express.static(path.join(bootstrapPath, 'img')));
app.use(app.router);
app.use(lessMiddleware(path.join(__dirname, 'source', 'less'), {
  dest: path.join(__dirname, 'public'),
  render: {
    paths: [path.join(bootstrapPath, 'less')],
  }
}));
app.use(express.static(path.join(__dirname, 'public')));

assets/less/base.less

@import 'bootstrap';
@import 'responsive';

@bodyBackground: #FAF7EC;
@navbarBrandColor: #989CAE;

.brand {
  font-family: @monoFontFamily;
}

Adding variables at runtime

If you want to set @variables in your LESS that are dependent on your environment or other factors that can only be determined at runtime, use the preprocess.less option to prepend a variable string to your source:

// this example will set @someColor and @someSize
var runtimeVars = {
  someColor : process.env.PRODUCTION ? '#f0f0f0' : '#0f0f0f',
  someSize : process.env.PRODUCTION ? '12px' : '20em'
};

app.use(lessMiddleware(__dirname + '/my/path', {
  preprocess : {
    less : function(src, req){
      var varString = '';
      for (var key in runtimeVars){
        if (runtimeVars.hasOwnProperty(key)){
          varString += '@' + key + ':' + runtimeVars[key] + ';';
        }
      }
      return varString + src;
    }
  }
}));

Extending Less

See the page on extending Less for details on adding behavior to the Less library for use with the Less middleware.