├── .editorconfig ├── .gitignore ├── .jshintrc ├── .npmignore ├── .travis.yml ├── LICENSE-MIT ├── README.md ├── index.js ├── package.json └── test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 4 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | tmp 4 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "expr": true, 3 | "strict": true, 4 | "trailing": true, 5 | "undef": true, 6 | "curly": true, 7 | "eqeqeq": true, 8 | "immed": true, 9 | "latedef": true, 10 | "noarg": true, 11 | "node": true, 12 | "noempty": true, 13 | "unused": true, 14 | "indent": 4 15 | } 16 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .editorconfig 2 | .gitignore 3 | .jshintrc 4 | .travis.yml 5 | gulpfile.js 6 | test.js 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '5' 4 | - '4' 5 | - '0.12' 6 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) Ben Briggs (http://beneb.info) 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deprecation Notice 2 | 3 | Since UnCSS is now a PostCSS plugin which can be combined with other CSS 4 | processing steps, there is little incentive to add a separate pass to your 5 | build step. Instead of using gulp-uncss, you can replicate the functionality 6 | by the following gulp task: 7 | 8 | ```js 9 | var gulp = require('gulp'); 10 | var postcss = require('gulp-postcss'); 11 | var uncss = require('postcss-uncss'); 12 | 13 | gulp.task('default', function () { 14 | var plugins = [ 15 | uncss({ 16 | html: ['index.html', 'posts/**/*.html', 'http://example.com'] 17 | }), 18 | ]; 19 | return gulp.src('./src/*.css') 20 | .pipe(postcss(plugins)) 21 | .pipe(gulp.dest('./dest')); 22 | }); 23 | ``` 24 | 25 | Now you can add other plugins to complement UnCSS, such as [cssnano]. 26 | 27 | [cssnano]: https://github.com/ben-eb/cssnano 28 | 29 | # [gulp][gulp]-uncss 30 | 31 | > Remove unused CSS with [UnCSS][orig]. 32 | 33 | *If you have any difficulties with the output of this plugin, please use the 34 | [UnCSS tracker][bugs].* 35 | 36 | ## Install 37 | 38 | With [npm](https://npmjs.org/package/gulp-uncss) do: 39 | 40 | ``` 41 | npm install gulp-uncss --save-dev 42 | ``` 43 | 44 | ## Example 45 | 46 | Single files, globbing patterns and URLs are all supported by gulp-uncss, and 47 | can be mixed and matched: 48 | 49 | ```js 50 | var gulp = require('gulp'); 51 | var uncss = require('gulp-uncss'); 52 | 53 | gulp.task('default', function () { 54 | return gulp.src('site.css') 55 | .pipe(uncss({ 56 | html: ['index.html', 'posts/**/*.html', 'http://example.com'] 57 | })) 58 | .pipe(gulp.dest('./out')); 59 | }); 60 | ``` 61 | 62 | gulp-uncss can also be used in a pipeline that involves CSS pre-processing. 63 | Utilising many transforms on a single file is one of gulp's strengths: 64 | 65 | ```js 66 | var gulp = require('gulp'); 67 | var uncss = require('gulp-uncss'); 68 | var sass = require('gulp-sass'); 69 | var concat = require('gulp-concat'); 70 | var nano = require('gulp-cssnano'); 71 | 72 | gulp.task('default', function () { 73 | return gulp.src('styles/**/*.scss') 74 | .pipe(sass()) 75 | .pipe(concat('main.css')) 76 | .pipe(uncss({ 77 | html: ['index.html', 'posts/**/*.html', 'http://example.com'] 78 | })) 79 | .pipe(nano()) 80 | .pipe(gulp.dest('./out')); 81 | }); 82 | ``` 83 | 84 | In just a few lines, we compiled SCSS source into a single file, removed unused 85 | CSS and minified the output! 86 | 87 | ## Options 88 | 89 | Please see the [UnCSS documentation][docs] for all of the options you can use. 90 | Some of them aren't as necessary when using gulp-uncss, because the CSS to 91 | analyse comes from the stream rather than the HTML files. The main options you 92 | will likely be using are: 93 | 94 | ### html 95 | Type: `Array|String` 96 | *Required value.* 97 | 98 | An array which can contain an array of files relative to your `gulpfile.js`, and 99 | which can also contain URLs. Note that if you are to pass URLs here, then the 100 | task will take much longer to complete. If you want to pass some HTML directly 101 | into the task instead, you can specify it here as a string. 102 | 103 | ### ignore 104 | Type: `Array` 105 | Default value: `undefined` 106 | 107 | Selectors that should be left untouched by UnCSS as it can't detect user 108 | interaction on a page (hover, click, focus, for example). Both literal names and 109 | regex patterns are recognized. 110 | 111 | ### timeout 112 | Type: `Integer` 113 | Default value: `undefined` 114 | 115 | Specify how long to wait for the JS to be loaded. 116 | 117 | Note that `options.ignoreSheets` is *already defined* for you. gulp-uncss will 118 | only process CSS files in the stream. 119 | 120 | ## Contributing 121 | 122 | Pull requests are welcome. If you add functionality, then please add unit tests 123 | to cover it. 124 | 125 | ## License 126 | 127 | MIT © [Ben Briggs](http://beneb.info) 128 | 129 | [bugs]: https://github.com/giakki/uncss/issues 130 | [docs]: https://github.com/giakki/uncss#within-nodejs 131 | [gulp]: https://github.com/gulpjs/gulp 132 | [orig]: https://github.com/giakki/uncss 133 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var uncss = require('uncss'), 4 | gutil = require('gulp-util'), 5 | assign = require('object-assign'), 6 | transform = require('stream').Transform, 7 | 8 | PLUGIN_NAME = 'gulp-uncss'; 9 | 10 | module.exports = function (options) { 11 | var stream = new transform({objectMode: true}); 12 | 13 | // Ignore stylesheets in the HTML files; only use those from the stream 14 | options.ignoreSheets = [/\s*/]; 15 | 16 | stream._transform = function (file, encoding, cb) { 17 | if (file.isStream()) { 18 | var error = 'Streaming not supported'; 19 | return cb(new gutil.PluginError(PLUGIN_NAME, error)); 20 | } else if (file.isBuffer()) { 21 | var contents = String(file.contents); 22 | if (!contents.length) { 23 | // Don't crash on empty files 24 | return cb(null, file); 25 | } 26 | options = assign(options, {raw: contents}); 27 | uncss(options.html, options, function (err, output) { 28 | if (err) { 29 | return cb(new gutil.PluginError(PLUGIN_NAME, err)); 30 | } 31 | file.contents = new Buffer(output); 32 | cb(null, file); 33 | }); 34 | } else { 35 | // Pass through when null 36 | cb(null, file); 37 | } 38 | }; 39 | 40 | return stream; 41 | }; 42 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gulp-uncss", 3 | "version": "1.0.6", 4 | "description": "Remove unused CSS selectors.", 5 | "license": "MIT", 6 | "homepage": "https://github.com/ben-eb/gulp-uncss", 7 | "author": { 8 | "name": "Ben Briggs", 9 | "email": "beneb.info@gmail.com", 10 | "url": "http://beneb.info" 11 | }, 12 | "scripts": { 13 | "test": "tape test.js | tap-spec" 14 | }, 15 | "repository": "ben-eb/gulp-uncss", 16 | "keywords": [ 17 | "unused", 18 | "css", 19 | "gulpplugin" 20 | ], 21 | "dependencies": { 22 | "gulp-util": "~3.0.6", 23 | "object-assign": "^4.0.1", 24 | "uncss": "^0.14.1" 25 | }, 26 | "devDependencies": { 27 | "tap-spec": "^4.1.0", 28 | "tape": "^4.2.0" 29 | }, 30 | "main": "index.js" 31 | } 32 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var test = require('tape'), 4 | gutil = require('gulp-util'), 5 | uncss = require('./'), 6 | Stream = require('stream'), 7 | 8 | html = '

hello

', 9 | css = 'h2 { color:blue; } h1 { color:red }', 10 | output = 'h1 { color:red }'; 11 | 12 | function fixture (contents) { 13 | return new gutil.File({ 14 | contents: contents, 15 | cwd: __dirname, 16 | base: __dirname, 17 | path: __dirname + '/fixture.css' 18 | }); 19 | } 20 | 21 | test('should not throw on an empty file', function (t) { 22 | t.plan(1); 23 | 24 | var stream = uncss({html: html}); 25 | 26 | stream.on('data', function (data) { 27 | t.equal(String(data.contents), ''); 28 | }); 29 | 30 | var file = fixture(new Buffer('')); 31 | 32 | stream.write(file); 33 | }); 34 | 35 | test('should remove unused css selectors', function (t) { 36 | t.plan(1); 37 | 38 | var stream = uncss({html: html}); 39 | 40 | stream.on('data', function (data) { 41 | t.equal(String(data.contents), output); 42 | }); 43 | 44 | var file = fixture(new Buffer(css)); 45 | 46 | stream.write(file); 47 | }); 48 | 49 | test('should throw an error in stream mode', function (t) { 50 | t.plan(1); 51 | 52 | var stream = uncss({html: html}); 53 | 54 | var file = fixture(new Stream()); 55 | 56 | var write = function () { 57 | stream.write(file); 58 | file.contents.write(css); 59 | file.contents.end(); 60 | }; 61 | 62 | t.throws(write, 'should not support streaming contents'); 63 | }); 64 | 65 | test('should let null files pass through', function (t) { 66 | t.plan(1); 67 | 68 | var stream = uncss({html: html}); 69 | 70 | stream.on('data', function (data) { 71 | t.equal(data.contents, null, 'should not transform null in any way'); 72 | }); 73 | 74 | var file = fixture(null); 75 | 76 | stream.write(file); 77 | }); 78 | --------------------------------------------------------------------------------