Delirios de un Informático

Funciones personalizadas para Less mediante Grunt

Less dispone de muchas funciones nativas, pero hay ocasiones en las que resultaría útil disponer de funciones personalizadas porque los mixins tampoco son suficientes. Por ejemplo, puede ser útil comprobar si existe un archivo, leer su contenido o ejecutar una herramienta externa para obtener los valores.

Para estos casos, es posible añadir nuevas funciones a Less mediante Grunt y el plugin grunt-contrib-less mediante la opción customFunctions, con lo que tendremos toda la potencia de Node.js a nuestra disposición para realizar todo que se nos ocurra.

Este sería el contenido de un Gruntfile.js de ejemplo:

module.exports = function(grunt) {
    grunt.loadNpmTasks('grunt-contrib-less');

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        less: {
            options: {
                customFunctions: require('./functions.js'),
                sourceMap: false
            },
            build: {
                src: 'test.less',
                dest: 'test.css'
            }
        }
    });

    grunt.registerTask('default', ['less']);
};

Como se puede ver, utilizo un require('./functions.js') para almacenar en un archivo todas las funciones, que deben exportarse del siguiente modo:

exports.test = function(less, arg1, arg2) {
    // código personalizado
}

Cada función se exporta con un nombre que será el utilizado en Less:

body {
  background-color: test('test.jpg', #FFFFFF);
}

Hay que tener en cuenta los siguientes aspectos:

  • El primer argumento recibido por la función es una instancia del compilador Less
  • El resto de argumentos son los que se especifiquen en Less
  • Cada argumento es un objeto con las siguientes propiedades (entre otras):
    • value: valor especificado en Less
    • quote: entrecomillado usado para convertir el valor
    • escaped: indica si se aplicarán caracteres de escape en el valor
  • Cualquiera de las propiedades puede modificarse para que el compilador las utilice
  • El entrecomillado será el especificado en Less: ‘, ” o ninguno si se usa un color o cualquier otro valor CSS
  • El valor de retorno de la función puede ser un objeto como el recibido como argumento o una cadena que se mostrará tal cual

El único problema que no he logrado solventar es poder acceder a las variables definidas en el punto en el que se llama a la función. Sería muy útil poder acceder a las variables, añadirlas y modificarlas, pero por lo que he podido comprobar la instancia de Less recibida por la función no da acceso a ellas.