Skip to content
Permalink
Browse files

feat: init inline CSS support

  • Loading branch information...
sparanoid committed Jun 1, 2016
1 parent 1c4c79f commit a8b60d08769829021ffbac5d8167f7fa99c8d6ac
Showing with 129 additions and 99 deletions.
  1. +2 −3 .travis.yml
  2. +12 −5 Gruntfile.js
  3. +19 −18 README.md
  4. +8 −6 package.json
  5. +88 −67 tasks/uncss.js
@@ -1,10 +1,9 @@
sudo: false
language: node_js
node_js:
- "0.12"
- "4"
- "5"
- "iojs"
- "4"
- "0.12"
matrix:
fast_finish: true
cache:
@@ -1,3 +1,10 @@
/*
* grunt-uncss-inline
* https://github.com/sparanoid/grunt-uncss-inline
*
* Copyright (c) 2016 Tunghsiao Liu
* Licensed under the MIT license.
*/
/*
* grunt-uncss
* https://github.com/addyosmani/grunt-uncss
@@ -33,7 +40,7 @@ module.exports = function(grunt) {
tests: ['tmp', 'dist', 'tests/output.css']
},

uncss: {
uncss_inline: {
dist: {
src: ['tests/app/about.html', 'tests/app/contact.html', 'tests/app/index.html'],
dest: 'dist/css/tidy.css'
@@ -126,9 +133,9 @@ module.exports = function(grunt) {

grunt.registerTask('test', [
'jshint',
'uncss:test',
'uncss:testMany',
'uncss:testUncssrc',
'uncss_inline:test',
'uncss_inline:testMany',
'uncss_inline:testUncssrc',
'simplemocha'
]);

@@ -142,7 +149,7 @@ module.exports = function(grunt) {
grunt.registerTask('default', [
'clean',
'copy',
'uncss:dist',
'uncss_inline:dist',
'cssmin',
'processhtml'
]);
@@ -1,10 +1,10 @@
# grunt-uncss [![Built with Grunt](https://cdn.gruntjs.com/builtwith.png)](http://gruntjs.com/)
# grunt-uncss-inline [![Built with Grunt](https://cdn.gruntjs.com/builtwith.png)](http://gruntjs.com/)

[![NPM version](https://img.shields.io/npm/v/grunt-uncss.svg?)](https://www.npmjs.com/package/grunt-uncss)
[![Linux Build Status](https://img.shields.io/travis/addyosmani/grunt-uncss/master.svg?label=Linux%20build)](https://travis-ci.org/addyosmani/grunt-uncss)
[![Windows Build status](https://img.shields.io/appveyor/ci/addyosmani/grunt-uncss/master.svg?label=Windows%20build)](https://ci.appveyor.com/project/addyosmani/grunt-uncss/branch/master)
[![Dependency Status](https://img.shields.io/david/addyosmani/grunt-uncss.svg)](https://david-dm.org/addyosmani/grunt-uncss)
[![devDependency Status](https://img.shields.io/david/dev/addyosmani/grunt-uncss.svg)](https://david-dm.org/addyosmani/grunt-uncss#info=devDependencies)
[![NPM version](https://img.shields.io/npm/v/grunt-uncss-inline.svg?)](https://www.npmjs.com/package/grunt-uncss-inline)
[![Linux Build Status](https://img.shields.io/travis/sparanoid/grunt-uncss-inline/master.svg?label=Linux%20build)](https://travis-ci.org/sparanoid/grunt-uncss-inline)
[![Windows Build status](https://img.shields.io/appveyor/ci/sparanoid/grunt-uncss-inline/master.svg?label=Windows%20build)](https://ci.appveyor.com/project/sparanoid/grunt-uncss-inline/branch/master)
[![Dependency Status](https://img.shields.io/david/sparanoid/grunt-uncss-inline.svg)](https://david-dm.org/sparanoid/grunt-uncss-inline)
[![devDependency Status](https://img.shields.io/david/dev/sparanoid/grunt-uncss-inline.svg)](https://david-dm.org/sparanoid/grunt-uncss-inline#info=devDependencies)

>A grunt task for removing unused CSS from your projects with [UnCSS](https://github.com/giakki/uncss). Works across multiple files and supports dynamically injected CSS via PhantomJS.
@@ -16,13 +16,13 @@ a [Gruntfile](http://gruntjs.com/sample-gruntfile) as well as install and use Gr
Once you're familiar with that process, you may install this plugin with this command:

```shell
npm install grunt-uncss --save-dev
npm install grunt-uncss-inline --save-dev
```

Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript:

```js
grunt.loadNpmTasks('grunt-uncss');
grunt.loadNpmTasks('grunt-uncss-inline');
```

**Issues with the output should be reported on the UnCSS [issue tracker](https://github.com/giakki/uncss/issues).**
@@ -35,7 +35,7 @@ Taking a multi-page project using Bootstrap with >120KB of CSS down to 11KB.

## Uncss task

*Run this task with the `grunt uncss` command.*
*Run this task with the `grunt uncss_inline` command.*

Task targets, files and options may be specified according to the grunt [Configuring tasks](http://gruntjs.com/configuring-tasks) guide.

@@ -53,20 +53,21 @@ This is useful to see exactly how well clean-css is performing but using `'gzip'

## Usage examples

Use the `grunt-uncss` task by specifying a target destination (file) for your cleaned CSS.
Use the `grunt-uncss-inline` task by specifying a target destination (file) for your cleaned CSS.
Below this is `dist/css/tidy.css`.

Along-side, specify the input HTML files you would like scanned for used selectors.
In this case `app/index.html` and `app/about.html` are the two files we would like checked.

```js
uncss: {
dist: {
files: {
'dist/css/tidy.css': ['app/index.html', 'app/about.html']
}
}
}
```coffee
uncss:
dist:
files: [
expand: true
cwd: "dist/"
src: "**/*.html"
dest: "dist/"
]
```

Which you can then use alongside a processor like
@@ -1,19 +1,20 @@
{
"name": "grunt-uncss",
"name": "grunt-uncss-inline",
"description": "A grunt task for generating CSS files containing only those styles used in your project.",
"version": "0.5.1",
"homepage": "https://github.com/addyosmani/grunt-uncss",
"author": "Addy Osmani <addyosmani@gmail.com> (http://addyosmani.com)",
"homepage": "https://github.com/sparanoid/grunt-uncss-inline",
"author": "Tunghsiao Liu <t@sparanoid.com> (https://github.com/sparanoid)",
"maintainers": [
"Addy Osmani <addyosmani@gmail.com> (http://addyosmani.com)",
"XhmikosR <xhmikosr@gmail.com> (https://github.com/XhmikosR)"
"XhmikosR <xhmikosr@gmail.com> (https://github.com/XhmikosR)",
"Tunghsiao Liu <t@sparanoid.com> (https://github.com/sparanoid)"
],
"repository": {
"type": "git",
"url": "git+https://github.com/addyosmani/grunt-uncss.git"
"url": "git+https://github.com/sparanoid/grunt-uncss-inline.git"
},
"bugs": {
"url": "https://github.com/addyosmani/grunt-uncss/issues"
"url": "https://github.com/sparanoid/grunt-uncss-inline/issues"
},
"license": "MIT",
"keywords": [
@@ -35,6 +36,7 @@
"dependencies": {
"async": "^1.5.0",
"chalk": "^1.1.0",
"cheerio": "^0.20.0",
"maxmin": "^2.1.0",
"uncss": "^0.13.0"
},
@@ -1,3 +1,10 @@
/**
* grunt-uncss-inline
* https://github.com/sparanoid/grunt-uncss-inline
*
* Copyright (c) 2016 Tunghsiao Liu
* Licensed under the MIT license.
*/
/**
* grunt-uncss
* https://github.com/addyosmani/grunt-uncss
@@ -6,78 +13,92 @@
* Licensed under the MIT license.
*/

'use strict';
var uncss = require( 'uncss' ),
chalk = require( 'chalk' ),
maxmin = require( 'maxmin' ),
async = require( 'async' );

module.exports = function ( grunt ) {
grunt.registerMultiTask( 'uncss', 'Remove unused CSS', function () {

var done = this.async(),
options = this.options({
report: 'min'
});

options.urls = options.urls || [];

function processFile ( file, done ) {

var src = file.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 ' + chalk.cyan( filepath ) + ' not found.' );
return false;
} else {
return true;
}
});

if ( src.length === 0 && file.src.length === 0 ) {
grunt.fail.warn( 'Destination (' + file.dest + ') not written because src files were empty.' );
}

file.src.forEach(function (source) {
if (/^https?/.test(source)) {
src.push(source);
options.urls.push(source);
}
});

try {
uncss( src, options, function ( error, output, report ) {
if ( error ) {
throw error;
}

grunt.file.write( file.dest, output );
grunt.log.writeln('File ' + chalk.cyan( file.dest ) + ' created: ' + maxmin( report.original, output, options.report === 'gzip' ) );
if (typeof(options.reportFile) !== 'undefined' && options.reportFile.length > 0) {
grunt.file.write(options.reportFile, JSON.stringify(report));
}
done();
});
} catch ( e ) {
var err = new Error( 'Uncss failed.' );
if ( e.msg ) {
err.message += ', ' + e.msg + '.';
}
err.origError = e;
grunt.log.warn( 'Uncssing source "' + src + '" failed.' );
grunt.fail.warn( err );
}

}
'use strict';

var uncss = require( 'uncss' ),
chalk = require( 'chalk' ),
maxmin = require( 'maxmin' ),
async = require( 'async' ),
cheerio = require( 'cheerio' );

grunt.registerMultiTask( 'uncss_inline', 'Remove unused CSS', function () {

var done = this.async();
var options = this.options({
report: 'min'
});

function processFile ( file, done ) {

if (this.files.length === 1) {
processFile( this.files[0], done );
// Get stylesheets from inline <style>
var $ = cheerio.load(grunt.file.read(file.src), {
decodeEntities: false
});

var src = file.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 ' + chalk.cyan( filepath ) + ' not found.' );
return false;
} else {
// Processing multiple files must be done sequentially
// until https://github.com/giakki/uncss/issues/136 is resolved.
async.eachSeries( this.files, processFile, done );
return true;
}
});

});
if ( src.length === 0 && file.src.length === 0 ) {
grunt.fail.warn( 'Destination (' + file.dest + ') not written because src files were empty.' );
}

var styles = [];
$('style').each(function () {
var style = $(this).html();
if (style) {
styles.push(style);
options.raw = styles.join(' ');
}
});

try {
uncss( src, options, function ( error, output, report ) {
if ( error ) {
throw error;
}

// remove all `<style>` tags except the last one
var styleTags = $('style');
styleTags.slice(0, styleTags.length - 1).remove();
$('style').text(output);
var html = $.html();
grunt.file.write( file.dest, html );

grunt.log.writeln('File ' + chalk.cyan( file.dest ) + ' created: ' + maxmin( report.original, output, options.report === 'gzip' ) );
if (typeof(options.reportFile) !== 'undefined' && options.reportFile.length > 0) {
grunt.file.write(options.reportFile, JSON.stringify(report));
}
done();
});
} catch ( e ) {
var err = new Error( 'Uncss failed.' );
if ( e.msg ) {
err.message += ', ' + e.msg + '.';
}
err.origError = e;
grunt.log.warn( 'Uncssing source "' + src + '" failed.' );
grunt.fail.warn( err );
}

}

if (this.files.length === 1) {
processFile( this.files[0], done );
} else {
// Processing multiple files must be done sequentially
// until https://github.com/giakki/uncss/issues/136 is resolved.
async.eachSeries( this.files, processFile, done );
}

});

};

0 comments on commit a8b60d0

Please sign in to comment.
You can’t perform that action at this time.