UNPKG

assemble-less

Version:

Compile LESS to CSS, with options for creating 'bundles', individual UI components and themes.

216 lines (178 loc) 6.48 kB
/* * NOTICE: Most of this code is from grunt-contrib-less * but it has been modified to concat the LESS * files first, then compile them into a CSS * file. This allows for "requiring" LESS files * and also for building out individual component * CSS files instead of building one big CSS file. * * grunt-contrib-less * http://gruntjs.com/ * Copyright (c) 2012 Tyler Kellen, contributors * Licensed under the MIT license. * * assemble-less * http://assemble.github.com/assemble-less * Copyright (c) 2013 Brian Woodward, contributors * Licensed under the MIT license. * */ module.exports = function(grunt) { 'use strict'; var path = require('path'); var fs = require('fs'); var less = false; // var bootstrap = false; var lessOptions = { parse: [ 'paths', 'filename', 'optimization', 'processImports', 'dumpLineNumbers', 'strictImports' ], render: [ 'silent', 'verbose', 'compress', 'yuicompress', 'strictMaths', // enforce maths within parenthesis 'strictUnits', // enforce correct units 'ieCompat' // enforce IE compatibility (IE8 data-uri) ] }; grunt.config.set('bootstrap.base', '<%= less.options.bootstrap %>'); grunt.registerMultiTask('less', 'Compile LESS to CSS using underscore and JSON.', function() { var done = this.async(); var options = this.options({ bootstrap: 'test/less/bootstrap', version: "less", require: [], concat: true }); grunt.verbose.writeln('loading less from ' + options.version); try { less = require(options.version); } catch (err) { var lessPath = path.join(process.cwd(), options.version); grunt.verbose.writeln('lessPath: ', lessPath); less = require(lessPath); } grunt.verbose.writeln('less loaded'); grunt.verbose.writeflags(options, 'Options'); grunt.util.async.forEachSeries(this.files, function(f, nextFileObj) { var destFile = f.dest; var files = f.src.filter(function(filepath) { // Warn on and remove invalid source files (if nonull was set). if (!grunt.file.exists(filepath)) { grunt.log.warn('Source file "' + filepath + '" not found.'); return false; } else { return true; } }); if (files.length === 0) { // No src files, goto next target. Warn would have been issued above. nextFileObj(); } var compiled = []; var dependencies = []; var srcCode = []; var concatCompile = function(file, next) { grunt.log.writeln('calling concatCompile: ' + file.magenta); grunt.util.async.concatSeries(options.require, function(file, next) { if(grunt.util._.contains(dependencies, file) === false) { srcCode.push(grunt.file.read(file)); dependencies.push(file); } next(null); }, function() {}); srcCode.push(grunt.file.read(file)); next(null); }; var concatRender = function() { var lessCode = srcCode.join(grunt.util.normalizelf(grunt.util.linefeed)); grunt.log.writeln('compiling less...'); compileLess(destFile, lessCode, options, function(css, err) { if(!err) { grunt.file.write(destFile, css); grunt.log.writeln('File ' + destFile.cyan + ' created.'); nextFileObj(); } else { nextFileObj(false); } }); }; var singleCompile = function(file, next) { if(fs.existsSync(destFile)) { var dirStats = fs.statSync(destFile); if(dirStats.isDirectory() === false) { grunt.log.warn('Destination must be a directory when compiling to single css files.'); nextFileObj(false); } } var singleSrcCode = []; grunt.util.async.concatSeries(options.require, function(file, next) { singleSrcCode.push(grunt.file.read(file)); next(null); }, function() {}); singleSrcCode.push(grunt.file.read(file)); singleSrcCode = singleSrcCode.join(grunt.util.normalizelf(grunt.util.linefeed)); compileLess(file, singleSrcCode, options, function(css, err) { if(!err) { // write the file out directly var singleDestFile = path.join(destFile, path.basename(file, path.extname(file))) + '.css'; grunt.file.write(singleDestFile, css); grunt.log.ok('File ' + singleDestFile.cyan + ' created.' + ' ok '.green); next(null); } else { nextFileObj(false); } }); }; var singleRender = function() { nextFileObj(); }; if(options.concat) { grunt.util.async.concatSeries(files, concatCompile, concatRender); } else { grunt.util.async.concatSeries(files, singleCompile, singleRender); } }, done); }); // grunt.task.run("grunt-recess"); var compileLess = function(filename, srcCode, options, callback) { options = grunt.util._.extend({filename: filename}, options); options.paths = options.paths || [path.dirname(filename)]; var css; // LESS Parser (parseCopyProperties) var parser = new less.Parser(grunt.util._.pick(options, lessOptions.parse)); grunt.verbose.writeln('before parse'); parser.parse(srcCode, function(parse_err, tree) { if (parse_err) { lessError(parse_err); callback('',true); } try { grunt.verbose.writeln('parsed...'); // LESS evalCopyProperties css = tree.toCSS(grunt.util._.pick(options, lessOptions.render)); grunt.verbose.writeln('rendered...'); callback(css, null); } catch (e) { lessError(e); callback(css, true); } }); }; var formatLessError = function(e) { var pos = '[' + 'L' + e.line + ':' + ('C' + e.column) + ']'; return e.filename + ': ' + pos + ' ' + e.message; }; var lessError = function(e) { var message = less.formatError ? less.formatError(e) : formatLessError(e); grunt.log.error(message); grunt.fail.warn('Error compiling LESS.'); }; };