├── .babelrc
├── .eslintrc
├── .github
├── CODE_OF_CONDUCT.md
├── ISSUE_TEMPLATE.md
└── PULL_REQUEST_TEMPLATE.md
├── .gitignore
├── .npmrc
├── .travis.yml
├── LICENSE
├── README.md
├── __tests__
├── buffer.test.js
└── test.html
├── circle.yml
├── example
└── simple
│ ├── build
│ └── css
│ │ ├── main.css
│ │ └── navigation.css
│ ├── gulpfile.js
│ ├── package.json
│ └── src
│ ├── css
│ ├── main.css
│ └── navigation.css
│ └── index.html
├── greenkeeper.json
├── jest.config.js
├── lib
├── gulpPurgecss.es.js
└── gulpPurgecss.js
├── package.json
├── rollup.config.js
└── src
└── index.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "test": {
4 | "presets": [
5 | "@babel/preset-env"
6 | ]
7 | },
8 | "development": {
9 | "presets": [
10 | [
11 | "@babel/preset-env",
12 | {
13 | "targets": {
14 | "browsers": [
15 | "last 2 versions"
16 | ]
17 | },
18 | "modules": false
19 | }
20 | ]
21 | ]
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "eslint:recommended",
3 | "parserOptions": {
4 | "ecmaVersion": 6,
5 | "sourceType": "module"
6 | },
7 | "env": {
8 | "browser": true,
9 | "commonjs": true,
10 | "node": true,
11 | "es6": true
12 | }
13 | }
--------------------------------------------------------------------------------
/.github/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6 |
7 | ## Our Standards
8 |
9 | Examples of behavior that contributes to creating a positive environment include:
10 |
11 | * Using welcoming and inclusive language
12 | * Being respectful of differing viewpoints and experiences
13 | * Gracefully accepting constructive criticism
14 | * Focusing on what is best for the community
15 | * Showing empathy towards other community members
16 |
17 | Examples of unacceptable behavior by participants include:
18 |
19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances
20 | * Trolling, insulting/derogatory comments, and personal or political attacks
21 | * Public or private harassment
22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission
23 | * Other conduct which could reasonably be considered inappropriate in a professional setting
24 |
25 | ## Our Responsibilities
26 |
27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28 |
29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30 |
31 | ## Scope
32 |
33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34 |
35 | ## Enforcement
36 |
37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at florielfedry@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38 |
39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40 |
41 | ## Attribution
42 |
43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
44 |
45 | [homepage]: http://contributor-covenant.org
46 | [version]: http://contributor-covenant.org/version/1/4/
47 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | Before you open an issue, please check if a similar issue already exists or has been closed before.
2 |
3 | ### When reporting a bug, please be sure to include the following:
4 | - [ ] A descriptive title
5 | - [ ] An *isolated* way to reproduce the behavior (example: GitHub repository with code isolated to the issue that anyone can clone to observe the problem)
6 | - [ ] What version of `gulp-purgecss` you're using, and the platform(s) you're running it on
7 | - [ ] The behavior you expect to see, and the actual behavior
8 |
9 | ### When you open an issue for a feature request, please add as much detail as possible:
10 | - [ ] A descriptive title
11 | - [ ] A description of the problem you're trying to solve, including *why* you think this is a problem
12 | - [ ] An overview of the suggested solution
13 | - [ ] If the feature changes current behavior, reasons why your solution is better
14 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## Proposed changes
2 |
3 | Describe the big picture of your changes here to communicate to the maintainers why we should accept this pull request. If it fixes a bug or resolves a feature request, be sure to link to that issue.
4 |
5 | ## Types of changes
6 |
7 | What types of changes does your code introduce to gulp-purgecss?
8 | _Put an `x` in the boxes that apply_
9 |
10 | - [ ] Bugfix (non-breaking change which fixes an issue)
11 | - [ ] New feature (non-breaking change which adds functionality)
12 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
13 |
14 | ## Checklist
15 |
16 | _Put an `x` in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code._
17 |
18 | - [ ] Lint and unit tests pass locally with my changes
19 | - [ ] I have added tests that prove my fix is effective or that my feature works
20 | - [ ] I have added necessary documentation (if appropriate)
21 |
22 | ## Further comments
23 |
24 | If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution you did and what alternatives you considered, etc...
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | package-lock.json
2 |
3 | # Logs
4 | logs
5 | *.log
6 | npm-debug.log*
7 | yarn-debug.log*
8 | yarn-error.log*
9 |
10 | # Runtime data
11 | pids
12 | *.pid
13 | *.seed
14 | *.pid.lock
15 |
16 | # Directory for instrumented libs generated by jscoverage/JSCover
17 | lib-cov
18 |
19 | # Coverage directory used by tools like istanbul
20 | coverage
21 |
22 | # nyc test coverage
23 | .nyc_output
24 |
25 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
26 | .grunt
27 |
28 | # Bower dependency directory (https://bower.io/)
29 | bower_components
30 |
31 | # node-waf configuration
32 | .lock-wscript
33 |
34 | # Compiled binary addons (http://nodejs.org/api/addons.html)
35 | build/Release
36 |
37 | # Dependency directories
38 | node_modules/
39 | jspm_packages/
40 |
41 | # Typescript v1 declaration files
42 | typings/
43 |
44 | # Optional npm cache directory
45 | .npm
46 |
47 | # Optional eslint cache
48 | .eslintcache
49 |
50 | # Optional REPL history
51 | .node_repl_history
52 |
53 | # Output of 'npm pack'
54 | *.tgz
55 |
56 | # Yarn Integrity file
57 | .yarn-integrity
58 |
59 | # dotenv environment variables file
60 | .env
61 |
62 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=false
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "7"
4 | before_install:
5 | - npm i -g npm@5.3.0
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Full Human
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Gulp Purgecss
2 |
3 | The contents of this repository were moved into the
4 | [PurgeCSS](https://github.com/FullHuman/purgecss) repository. The source code can be
5 | found in [packages/gulp-purgecss](https://github.com/FullHuman/purgecss/tree/master/packages/gulp-purgecss).
6 |
7 | ```
8 | npm i -D gulp-purgecss
9 | ```
10 |
--------------------------------------------------------------------------------
/__tests__/buffer.test.js:
--------------------------------------------------------------------------------
1 | import gulpPurgecss from "./../src/index.js"
2 | import File from "vinyl"
3 |
4 |
5 | describe('gulp-purgecss with buffer', () => {
6 | let myGulpPurgecss
7 | let fileTest
8 | beforeEach(() => {
9 | fileTest = new File({
10 | contents: new Buffer('.unused, .used, a { color: blue; }')
11 | })
12 |
13 | myGulpPurgecss = gulpPurgecss({
14 | content: ["./__tests__/test.html"]
15 | })
16 | })
17 |
18 | it('returns a buffer', done => {
19 | myGulpPurgecss.write(fileTest)
20 | myGulpPurgecss.once('data', file => {
21 | expect(file.isBuffer()).toBe(true)
22 | done()
23 | })
24 | })
25 |
26 | it('returns a purified css buffer', done => {
27 | myGulpPurgecss.write(fileTest)
28 | myGulpPurgecss.once('data', file => {
29 | const result = file.contents.toString('utf8')
30 | expect(result.includes('used')).toBe(true)
31 | expect(result.includes('unused')).toBe(false)
32 | expect(result.includes('a')).toBe(true)
33 | done()
34 | })
35 | })
36 |
37 | })
--------------------------------------------------------------------------------
/__tests__/test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/circle.yml:
--------------------------------------------------------------------------------
1 | machine:
2 | node:
3 | version: 6.11.0
4 | dependencies:
5 | override:
6 | - npm i npm
7 | - npm i
8 |
--------------------------------------------------------------------------------
/example/simple/build/css/main.css:
--------------------------------------------------------------------------------
1 | .title-page {
2 | color: rebeccapurple;
3 | }
4 |
--------------------------------------------------------------------------------
/example/simple/build/css/navigation.css:
--------------------------------------------------------------------------------
1 | .bg-blue {
2 | background: blue;
3 | }
4 |
--------------------------------------------------------------------------------
/example/simple/gulpfile.js:
--------------------------------------------------------------------------------
1 | const gulp = require('gulp')
2 | const purgecss = require('gulp-purgecss')
3 |
4 | gulp.task('default', () => {
5 | return gulp
6 | .src('src/**/*.css')
7 | .pipe(
8 | purgecss({
9 | content: ['src/*.html']
10 | })
11 | )
12 | .pipe(gulp.dest('build'))
13 | })
14 |
--------------------------------------------------------------------------------
/example/simple/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example-gulp-purgecss",
3 | "version": "1.0.0",
4 | "description": "example gulp-purgecss",
5 | "scripts": {
6 | "build": "npx gulp",
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "devDependencies": {
12 | "gulp": "^4.0.2",
13 | "gulp-purgecss": "^1.0.0"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/example/simple/src/css/main.css:
--------------------------------------------------------------------------------
1 | .title-page {
2 | color: rebeccapurple;
3 | }
4 |
--------------------------------------------------------------------------------
/example/simple/src/css/navigation.css:
--------------------------------------------------------------------------------
1 | .bg-blue {
2 | background: blue;
3 | }
4 |
5 | .unused {
6 | color: green;
7 | }
8 |
9 | .shouldberemoved {
10 | width: 45px;
11 | height: 60px;
12 | }
13 |
14 | .shouldberemoved p {
15 | font-size: 2rem;
16 | }
17 |
--------------------------------------------------------------------------------
/example/simple/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | The HTML5 Herald
9 |
10 |
11 |
12 |
13 |
14 |
15 | Hello World
16 |
17 | Hover over this element
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/greenkeeper.json:
--------------------------------------------------------------------------------
1 | {
2 | "groups": {
3 | "default": {
4 | "packages": [
5 | "example/simple/package.json",
6 | "package.json"
7 | ]
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | // For a detailed explanation regarding each configuration property, visit:
2 | // https://jestjs.io/docs/en/configuration.html
3 |
4 | module.exports = {
5 | // All imported modules in your tests should be mocked automatically
6 | // automock: false,
7 |
8 | // Stop running tests after the first failure
9 | // bail: false,
10 |
11 | // Respect "browser" field in package.json when resolving modules
12 | // browser: false,
13 |
14 | // The directory where Jest should store its cached dependency information
15 | // cacheDirectory: "/var/folders/sk/zystdgkn6bzdyp6f8kcvjdnr0000gn/T/jest_dx",
16 |
17 | // Automatically clear mock calls and instances between every test
18 | clearMocks: true,
19 |
20 | // Indicates whether the coverage information should be collected while executing the test
21 | // collectCoverage: false,
22 |
23 | // An array of glob patterns indicating a set of files for which coverage information should be collected
24 | // collectCoverageFrom: null,
25 |
26 | // The directory where Jest should output its coverage files
27 | coverageDirectory: "coverage",
28 |
29 | // An array of regexp pattern strings used to skip coverage collection
30 | // coveragePathIgnorePatterns: [
31 | // "/node_modules/"
32 | // ],
33 |
34 | // A list of reporter names that Jest uses when writing coverage reports
35 | // coverageReporters: [
36 | // "json",
37 | // "text",
38 | // "lcov",
39 | // "clover"
40 | // ],
41 |
42 | // An object that configures minimum threshold enforcement for coverage results
43 | // coverageThreshold: null,
44 |
45 | // Make calling deprecated APIs throw helpful error messages
46 | // errorOnDeprecated: false,
47 |
48 | // Force coverage collection from ignored files usin a array of glob patterns
49 | // forceCoverageMatch: [],
50 |
51 | // A path to a module which exports an async function that is triggered once before all test suites
52 | // globalSetup: null,
53 |
54 | // A path to a module which exports an async function that is triggered once after all test suites
55 | // globalTeardown: null,
56 |
57 | // A set of global variables that need to be available in all test environments
58 | // globals: {},
59 |
60 | // An array of directory names to be searched recursively up from the requiring module's location
61 | // moduleDirectories: [
62 | // "node_modules"
63 | // ],
64 |
65 | // An array of file extensions your modules use
66 | // moduleFileExtensions: [
67 | // "js",
68 | // "json",
69 | // "jsx",
70 | // "node"
71 | // ],
72 |
73 | // A map from regular expressions to module names that allow to stub out resources with a single module
74 | // moduleNameMapper: {},
75 |
76 | // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
77 | // modulePathIgnorePatterns: [],
78 |
79 | // Activates notifications for test results
80 | // notify: false,
81 |
82 | // An enum that specifies notification mode. Requires { notify: true }
83 | // notifyMode: "always",
84 |
85 | // A preset that is used as a base for Jest's configuration
86 | // preset: null,
87 |
88 | // Run tests from one or more projects
89 | // projects: null,
90 |
91 | // Use this configuration option to add custom reporters to Jest
92 | // reporters: undefined,
93 |
94 | // Automatically reset mock state between every test
95 | // resetMocks: false,
96 |
97 | // Reset the module registry before running each individual test
98 | // resetModules: false,
99 |
100 | // A path to a custom resolver
101 | // resolver: null,
102 |
103 | // Automatically restore mock state between every test
104 | // restoreMocks: false,
105 |
106 | // The root directory that Jest should scan for tests and modules within
107 | // rootDir: null,
108 |
109 | // A list of paths to directories that Jest should use to search for files in
110 | // roots: [
111 | // ""
112 | // ],
113 |
114 | // Allows you to use a custom runner instead of Jest's default test runner
115 | // runner: "jest-runner",
116 |
117 | // The paths to modules that run some code to configure or set up the testing environment before each test
118 | // setupFiles: [],
119 |
120 | // The path to a module that runs some code to configure or set up the testing framework before each test
121 | // setupTestFrameworkScriptFile: null,
122 |
123 | // A list of paths to snapshot serializer modules Jest should use for snapshot testing
124 | // snapshotSerializers: [],
125 |
126 | // The test environment that will be used for testing
127 | testEnvironment: "node",
128 |
129 | // Options that will be passed to the testEnvironment
130 | // testEnvironmentOptions: {},
131 |
132 | // Adds a location field to test results
133 | // testLocationInResults: false,
134 |
135 | // The glob patterns Jest uses to detect test files
136 | // testMatch: [
137 | // "**/__tests__/**/*.js?(x)",
138 | // "**/?(*.)+(spec|test).js?(x)"
139 | // ],
140 |
141 | // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
142 | // testPathIgnorePatterns: [
143 | // "/node_modules/"
144 | // ],
145 |
146 | // The regexp pattern Jest uses to detect test files
147 | // testRegex: "",
148 |
149 | // This option allows the use of a custom results processor
150 | // testResultsProcessor: null,
151 |
152 | // This option allows use of a custom test runner
153 | // testRunner: "jasmine2",
154 |
155 | // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href
156 | // testURL: "about:blank",
157 |
158 | // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout"
159 | // timers: "real",
160 |
161 | // A map from regular expressions to paths to transformers
162 | // transform: null,
163 |
164 | // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
165 | // transformIgnorePatterns: [
166 | // "/node_modules/"
167 | // ],
168 |
169 | // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
170 | // unmockedModulePathPatterns: undefined,
171 |
172 | // Indicates whether each individual test should be reported during the run
173 | // verbose: null,
174 |
175 | // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode
176 | // watchPathIgnorePatterns: [],
177 |
178 | // Whether to use watchman for file crawling
179 | // watchman: true,
180 | };
181 |
--------------------------------------------------------------------------------
/lib/gulpPurgecss.es.js:
--------------------------------------------------------------------------------
1 | import through from 'through2';
2 | import PluginError from 'plugin-error';
3 | import Purgecss from 'purgecss';
4 | import glob from 'glob';
5 |
6 | function _toConsumableArray(arr) {
7 | return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread();
8 | }
9 |
10 | function _arrayWithoutHoles(arr) {
11 | if (Array.isArray(arr)) {
12 | for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
13 |
14 | return arr2;
15 | }
16 | }
17 |
18 | function _iterableToArray(iter) {
19 | if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
20 | }
21 |
22 | function _nonIterableSpread() {
23 | throw new TypeError("Invalid attempt to spread non-iterable instance");
24 | }
25 |
26 | var PLUGIN_NAME = 'gulp-purgecss';
27 |
28 | var getFiles = function getFiles(contentArray) {
29 | return contentArray.reduce(function (acc, content) {
30 | return [].concat(_toConsumableArray(acc), _toConsumableArray(glob.sync(content)));
31 | }, []);
32 | };
33 |
34 | var gulpPurgecss = function gulpPurgecss(options) {
35 | return through.obj(function (file, encoding, callback) {
36 | var _this = this;
37 |
38 | // empty
39 | if (file.isNull()) return callback(null, file); // buffer
40 |
41 | if (file.isBuffer()) {
42 | try {
43 | var optionsGulp = Object.assign(options, {
44 | content: getFiles(options.content),
45 | css: [{
46 | raw: file.contents.toString()
47 | }],
48 | stdin: true
49 | });
50 | var purge = new Purgecss(optionsGulp).purge()[0];
51 | var result = optionsGulp.rejected ? purge.rejected.join(' {}\n') + ' {}' : purge.css;
52 | file.contents = new Buffer(result);
53 | callback(null, file);
54 | } catch (e) {
55 | this.emit('error', new PluginError(PLUGIN_NAME, e.message));
56 | }
57 | } // stream
58 |
59 |
60 | if (file.isStream()) {
61 | var css = '';
62 | file.on('readable', function (buffer) {
63 | css += buffer.read().toString();
64 | }).on('end', function () {
65 | try {
66 | var _optionsGulp = Object.assign(options, {
67 | css: [css]
68 | });
69 |
70 | var _purge = new Purgecss(_optionsGulp).purge()[0];
71 |
72 | var _result = _optionsGulp.rejected ? _purge.rejected.join(' {}\n') + ' {}' : _purge.css;
73 |
74 | file.contents = new Buffer(_result);
75 | callback(null, file);
76 | } catch (e) {
77 | _this.emit('error', new PluginError(PLUGIN_NAME, e.message));
78 | }
79 | });
80 | }
81 | });
82 | };
83 |
84 | export default gulpPurgecss;
85 |
--------------------------------------------------------------------------------
/lib/gulpPurgecss.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
4 |
5 | var through = _interopDefault(require('through2'));
6 | var PluginError = _interopDefault(require('plugin-error'));
7 | var Purgecss = _interopDefault(require('purgecss'));
8 | var glob = _interopDefault(require('glob'));
9 |
10 | function _toConsumableArray(arr) {
11 | return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread();
12 | }
13 |
14 | function _arrayWithoutHoles(arr) {
15 | if (Array.isArray(arr)) {
16 | for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
17 |
18 | return arr2;
19 | }
20 | }
21 |
22 | function _iterableToArray(iter) {
23 | if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
24 | }
25 |
26 | function _nonIterableSpread() {
27 | throw new TypeError("Invalid attempt to spread non-iterable instance");
28 | }
29 |
30 | var PLUGIN_NAME = 'gulp-purgecss';
31 |
32 | var getFiles = function getFiles(contentArray) {
33 | return contentArray.reduce(function (acc, content) {
34 | return [].concat(_toConsumableArray(acc), _toConsumableArray(glob.sync(content)));
35 | }, []);
36 | };
37 |
38 | var gulpPurgecss = function gulpPurgecss(options) {
39 | return through.obj(function (file, encoding, callback) {
40 | var _this = this;
41 |
42 | // empty
43 | if (file.isNull()) return callback(null, file); // buffer
44 |
45 | if (file.isBuffer()) {
46 | try {
47 | var optionsGulp = Object.assign(options, {
48 | content: getFiles(options.content),
49 | css: [{
50 | raw: file.contents.toString()
51 | }],
52 | stdin: true
53 | });
54 | var purge = new Purgecss(optionsGulp).purge()[0];
55 | var result = optionsGulp.rejected ? purge.rejected.join(' {}\n') + ' {}' : purge.css;
56 | file.contents = new Buffer(result);
57 | callback(null, file);
58 | } catch (e) {
59 | this.emit('error', new PluginError(PLUGIN_NAME, e.message));
60 | }
61 | } // stream
62 |
63 |
64 | if (file.isStream()) {
65 | var css = '';
66 | file.on('readable', function (buffer) {
67 | css += buffer.read().toString();
68 | }).on('end', function () {
69 | try {
70 | var _optionsGulp = Object.assign(options, {
71 | css: [css]
72 | });
73 |
74 | var _purge = new Purgecss(_optionsGulp).purge()[0];
75 |
76 | var _result = _optionsGulp.rejected ? _purge.rejected.join(' {}\n') + ' {}' : _purge.css;
77 |
78 | file.contents = new Buffer(_result);
79 | callback(null, file);
80 | } catch (e) {
81 | _this.emit('error', new PluginError(PLUGIN_NAME, e.message));
82 | }
83 | });
84 | }
85 | });
86 | };
87 |
88 | module.exports = gulpPurgecss;
89 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gulp-purgecss",
3 | "version": "1.2.0",
4 | "description": "Gulp plugin for purgecss",
5 | "main": "./lib/gulpPurgecss.js",
6 | "module": "./lib/gulpPurgecss.es.js",
7 | "jsnext:main": "./lib/gulpPurgecss.es.js",
8 | "directories": {
9 | "lib": "lib",
10 | "test": "__tests__",
11 | "example": "example"
12 | },
13 | "files": [
14 | "/lib"
15 | ],
16 | "scripts": {
17 | "test": "npx jest",
18 | "build": "rollup -c rollup.config.js",
19 | "lint": "npx eslint -c .eslintrc src/",
20 | "prettier": "npx prettier --write --print-width 100 --tab-width 2 --no-semi --single-quote src/index.js"
21 | },
22 | "repository": {
23 | "type": "git",
24 | "url": "git+https://github.com/FullHuman/gulp-purgecss.git"
25 | },
26 | "keywords": [
27 | "gulpplugin",
28 | "purgecss",
29 | "optimize",
30 | "remove",
31 | "css",
32 | "unused"
33 | ],
34 | "author": "Ffloriel",
35 | "license": "MIT",
36 | "bugs": {
37 | "url": "https://github.com/FullHuman/gulp-purgecss/issues"
38 | },
39 | "homepage": "https://github.com/FullHuman/gulp-purgecss#readme",
40 | "devDependencies": {
41 | "@babel/core": "^7.4.4",
42 | "@babel/preset-env": "^7.4.4",
43 | "babel-core": "^7.0.0-bridge.0",
44 | "babel-jest": "^24.7.1",
45 | "eslint": "^6.0.0",
46 | "jest": "^24.7.1",
47 | "prettier": "^1.17.0",
48 | "rollup": "^1.10.1",
49 | "rollup-plugin-babel": "^4.3.2",
50 | "rollup-plugin-commonjs": "^9.3.4",
51 | "rollup-plugin-node-resolve": "^5.0.0",
52 | "vinyl": "^2.2.0"
53 | },
54 | "dependencies": {
55 | "glob": "^7.1.2",
56 | "plugin-error": "^1.0.1",
57 | "purgecss": "^1.4.1",
58 | "through2": "^2.0.3"
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import babel from 'rollup-plugin-babel'
2 | import commonjs from 'rollup-plugin-commonjs'
3 | import resolve from 'rollup-plugin-node-resolve'
4 |
5 | export default {
6 | input: 'src/index.js',
7 | output: [
8 | {
9 | file: 'lib/gulpPurgecss.es.js',
10 | format: 'es'
11 | },
12 | {
13 | file: 'lib/gulpPurgecss.js',
14 | format: 'cjs'
15 | }
16 | ],
17 | plugins: [resolve(), commonjs(), babel()],
18 | external: ['through2', 'plugin-error', 'purgecss', 'glob']
19 | }
20 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import through from 'through2'
2 | import PluginError from 'plugin-error'
3 | import Purgecss from 'purgecss'
4 | import glob from 'glob'
5 |
6 | const PLUGIN_NAME = 'gulp-purgecss'
7 |
8 | const getFiles = contentArray =>
9 | contentArray.reduce((acc, content) => {
10 | return [...acc, ...glob.sync(content)]
11 | }, [])
12 |
13 | const gulpPurgecss = options => {
14 | return through.obj(function(file, encoding, callback) {
15 | // empty
16 | if (file.isNull()) return callback(null, file)
17 | // buffer
18 | if (file.isBuffer()) {
19 | try {
20 | const optionsGulp = Object.assign(options, {
21 | content: getFiles(options.content),
22 | css: [
23 | {
24 | raw: file.contents.toString()
25 | }
26 | ],
27 | stdin: true
28 | })
29 | const purge = new Purgecss(optionsGulp).purge()[0]
30 | const result = optionsGulp.rejected ? purge.rejected.join(' {}\n') + ' {}' : purge.css
31 | file.contents = new Buffer(result)
32 | callback(null, file)
33 | } catch (e) {
34 | this.emit('error', new PluginError(PLUGIN_NAME, e.message))
35 | }
36 | }
37 | // stream
38 | if (file.isStream()) {
39 | var css = ''
40 | file
41 | .on('readable', buffer => {
42 | css += buffer.read().toString()
43 | })
44 | .on('end', () => {
45 | try {
46 | const optionsGulp = Object.assign(options, { css: [css] })
47 | const purge = new Purgecss(optionsGulp).purge()[0]
48 | const result = optionsGulp.rejected ? purge.rejected.join(' {}\n') + ' {}' : purge.css
49 | file.contents = new Buffer(result)
50 | callback(null, file)
51 | } catch (e) {
52 | this.emit('error', new PluginError(PLUGIN_NAME, e.message))
53 | }
54 | })
55 | }
56 | })
57 | }
58 |
59 | export default gulpPurgecss
60 |
--------------------------------------------------------------------------------