gulp-postcss
Advanced tools
+4
-3
| sudo: false | ||
| language: node_js | ||
| node_js: | ||
| - iojs | ||
| - "0.12" | ||
| - "0.10" | ||
| - stable | ||
| - 6 | ||
| - 4 | ||
| - 0.12 |
+67
-25
@@ -8,8 +8,4 @@ var Stream = require('stream') | ||
| module.exports = function (processors, options) { | ||
| module.exports = withConfigLoader(function (loadConfig) { | ||
| if (!Array.isArray(processors)) { | ||
| throw new gutil.PluginError('gulp-postcss', 'Please provide array of postcss processors!') | ||
| } | ||
| var stream = new Stream.Transform({ objectMode: true }) | ||
@@ -27,25 +23,32 @@ | ||
| // Source map is disabled by default | ||
| var opts = { map: false } | ||
| var attr | ||
| // Protect `from` and `map` if using gulp-sourcemaps | ||
| var isProtected = file.sourceMap | ||
| ? { from: true, map: true } | ||
| : {} | ||
| // Extend default options | ||
| if (options) { | ||
| for (attr in options) { | ||
| if (options.hasOwnProperty(attr)) { | ||
| opts[attr] = options[attr] | ||
| } | ||
| } | ||
| var options = { | ||
| from: file.path | ||
| , to: file.path | ||
| // Generate a separate source map for gulp-sourcemaps | ||
| , map: file.sourceMap ? { annotation: false } : false | ||
| } | ||
| opts.from = file.path | ||
| opts.to = opts.to || file.path | ||
| // Generate separate source map for gulp-sourcemap | ||
| if (file.sourceMap) { | ||
| opts.map = { annotation: false } | ||
| } | ||
| postcss(processors) | ||
| .process(file.contents, opts) | ||
| loadConfig(file) | ||
| .then(function (config) { | ||
| var configOpts = config.options || {} | ||
| // Extend the default options if not protected | ||
| for (var opt in configOpts) { | ||
| if (configOpts.hasOwnProperty(opt) && !isProtected[opt]) { | ||
| options[opt] = configOpts[opt] | ||
| } else { | ||
| gutil.log( | ||
| 'gulp-postcss:', | ||
| file.relative + '\nCannot override ' + opt + | ||
| ' option, because it is required by gulp-sourcemaps' | ||
| ) | ||
| } | ||
| } | ||
| return postcss(config.plugins || []) | ||
| .process(file.contents, options) | ||
| }) | ||
| .then(handleResult, handleError) | ||
@@ -94,2 +97,41 @@ | ||
| return stream | ||
| }) | ||
| function withConfigLoader(cb) { | ||
| return function (plugins, options) { | ||
| if (Array.isArray(plugins)) { | ||
| return cb(function () { | ||
| return Promise.resolve({ | ||
| plugins: plugins | ||
| , options: options | ||
| }) | ||
| }) | ||
| } else if (typeof plugins === 'function') { | ||
| return cb(function (file) { | ||
| return Promise.resolve(plugins(file)) | ||
| }) | ||
| } else { | ||
| var postcssLoadConfig = require('postcss-load-config') | ||
| var contextOptions = plugins || {} | ||
| return cb(function(file) { | ||
| var configPath | ||
| if (contextOptions.config) { | ||
| if (path.isAbsolute(contextOptions.config)) { | ||
| configPath = contextOptions.config | ||
| } else { | ||
| configPath = path.join(file.base, contextOptions.config) | ||
| } | ||
| } else { | ||
| configPath = file.dirname | ||
| } | ||
| return postcssLoadConfig( | ||
| { file: file | ||
| , options: contextOptions | ||
| }, | ||
| configPath | ||
| ) | ||
| }) | ||
| } | ||
| } | ||
| } |
+7
-7
| { | ||
| "name": "gulp-postcss", | ||
| "version": "6.2.0", | ||
| "version": "6.3.0", | ||
| "description": "PostCSS gulp plugin", | ||
@@ -26,10 +26,10 @@ "main": "index.js", | ||
| "dependencies": { | ||
| "gulp-util": "^3.0.7", | ||
| "postcss": "^5.2.0", | ||
| "vinyl-sourcemaps-apply": "^0.2.0" | ||
| "gulp-util": "^3.0.8", | ||
| "postcss": "^5.2.10", | ||
| "postcss-load-config": "^1.1.0", | ||
| "vinyl-sourcemaps-apply": "^0.2.1" | ||
| }, | ||
| "devDependencies": { | ||
| "es6-promise": "^3.0.2", | ||
| "gulp-sourcemaps": "^1.5.1", | ||
| "mocha": "^2.2.5", | ||
| "gulp-sourcemaps": "^1.11.0", | ||
| "mocha": "^3.2.0", | ||
| "proxyquire": "^1.7.4", | ||
@@ -36,0 +36,0 @@ "sinon": "^1.17.3" |
+97
-16
| # gulp-postcss [](https://travis-ci.org/postcss/gulp-postcss) | ||
| [PostCSS](https://github.com/postcss/postcss) gulp plugin to pipe CSS through | ||
| several processors, but parse CSS only once. | ||
| several plugins, but parse CSS only once. | ||
@@ -14,5 +14,22 @@ ## Install | ||
| The configuration is loaded automatically from `postcss.config.js` | ||
| as [described here](https://www.npmjs.com/package/postcss-load-config), | ||
| so you don't have to specify any options. | ||
| ```js | ||
| var postcss = require('gulp-postcss'); | ||
| var gulp = require('gulp'); | ||
| gulp.task('css', function () { | ||
| return gulp.src('./src/*.css') | ||
| .pipe(postcss()) | ||
| .pipe(gulp.dest('./dest')); | ||
| }); | ||
| ``` | ||
| ## Passing plugins directly | ||
| ```js | ||
| var postcss = require('gulp-postcss'); | ||
| var gulp = require('gulp'); | ||
| var autoprefixer = require('autoprefixer'); | ||
@@ -22,8 +39,8 @@ var cssnano = require('cssnano'); | ||
| gulp.task('css', function () { | ||
| var processors = [ | ||
| var plugins = [ | ||
| autoprefixer({browsers: ['last 1 version']}), | ||
| cssnano(), | ||
| cssnano() | ||
| ]; | ||
| return gulp.src('./src/*.css') | ||
| .pipe(postcss(processors)) | ||
| .pipe(postcss(plugins)) | ||
| .pipe(gulp.dest('./dest')); | ||
@@ -37,3 +54,3 @@ }); | ||
| This, for instance, may be used to enable custom syntax: | ||
| This, for instance, may be used to enable custom parser: | ||
@@ -44,8 +61,8 @@ ```js | ||
| var nested = require('postcss-nested'); | ||
| var scss = require('postcss-scss'); | ||
| var sugarss = require('sugarss'); | ||
| gulp.task('default', function () { | ||
| var processors = [nested]; | ||
| return gulp.src('in.css') | ||
| .pipe(postcss(processors, {syntax: scss})) | ||
| var plugins = [nested]; | ||
| return gulp.src('in.sss') | ||
| .pipe(postcss(plugins, { parser: sugarss })) | ||
| .pipe(gulp.dest('out')); | ||
@@ -72,8 +89,8 @@ }); | ||
| gulp.task('css', function () { | ||
| var processors = [ | ||
| var plugins = [ | ||
| cssnext({browsers: ['last 1 version']}), | ||
| opacity, | ||
| opacity | ||
| ]; | ||
| return gulp.src('./src/*.css') | ||
| .pipe(postcss(processors)) | ||
| .pipe(postcss(plugins)) | ||
| .pipe(gulp.dest('./dest')); | ||
@@ -91,3 +108,3 @@ }); | ||
| .pipe(sourcemaps.init()) | ||
| .pipe(postcss(processors)) | ||
| .pipe(postcss(plugins)) | ||
| .pipe(sourcemaps.write('.')) | ||
@@ -97,4 +114,68 @@ .pipe(gulp.dest('./dest')); | ||
| ## Advanced usage | ||
| If you want to configure postcss on per-file-basis, you can pass a callback | ||
| that receives [vinyl file object](https://github.com/gulpjs/vinyl) and returns | ||
| `{ plugins: plugins, options: options }`. For example, when you need to | ||
| parse different extensions differntly: | ||
| ```js | ||
| var gulp = require('gulp'); | ||
| var postcss = require('gulp-postcss'); | ||
| gulp.task('css', function () { | ||
| function callback(file) { | ||
| return { | ||
| plugins: [ | ||
| require('postcss-import')({ root: file.dirname }), | ||
| require('postcss-modules') | ||
| ], | ||
| options: { | ||
| parser: file.extname === '.sss' ? require('sugarss') : false | ||
| } | ||
| } | ||
| } | ||
| return gulp.src('./src/*.css') | ||
| .pipe(postcss(callback)) | ||
| .pipe(gulp.dest('./dest')); | ||
| }); | ||
| ``` | ||
| The same result may be achieved with | ||
| [`postcss-load-config`](https://www.npmjs.com/package/postcss-load-config), | ||
| because it receives `ctx` with the context options and the vinyl file. | ||
| ```js | ||
| var gulp = require('gulp'); | ||
| var postcss = require('gulp-postcss'); | ||
| gulp.task('css', function () { | ||
| var contextOptions = { modules: true }; | ||
| return gulp.src('./src/*.css') | ||
| .pipe(postcss(contextOptions)) | ||
| .pipe(gulp.dest('./dest')); | ||
| }); | ||
| ``` | ||
| ```js | ||
| module.exports = function (ctx) { | ||
| var file = ctx.file; | ||
| var options = ctx.options; | ||
| return { | ||
| parser: file.extname === '.sss' ? : 'sugarss' : false, | ||
| plugins: { | ||
| 'postcss-import': { root: file.dirname } | ||
| 'postcss-modules': options.modules ? {} : false | ||
| } | ||
| } | ||
| }) | ||
| ``` | ||
| ## Changelog | ||
| * 6.3.0 | ||
| * Integrated with postcss-load-config | ||
| * Added a callback to configure postcss on per-file-basis | ||
| * Dropped node 0.10 support | ||
| * 6.2.0 | ||
@@ -134,3 +215,3 @@ * Fix syntax error message for PostCSS 5.2 compatibility | ||
| * Simplified error handling | ||
| * Simplified postcss execution with object processors | ||
| * Simplified postcss execution with object plugins | ||
@@ -150,3 +231,3 @@ * 5.1.3 Updated travis banner | ||
| * 5.0.1 | ||
| * Fix to support object processors | ||
| * Fix to support object plugins | ||
@@ -185,5 +266,5 @@ * 5.0.0 | ||
| * 1.0.1 | ||
| * Don't add source map comment if used with gulp-sourcemap | ||
| * Don't add source map comment if used with gulp-sourcemaps | ||
| * 1.0.0 | ||
| * Initial release |
+181
-15
| /* global it, afterEach, beforeEach, describe, Promise */ | ||
| require('es6-promise').polyfill() | ||
| var assert = require('assert') | ||
@@ -10,2 +9,3 @@ var gutil = require('gulp-util') | ||
| var sinon = require('sinon') | ||
| var path = require('path') | ||
@@ -95,11 +95,2 @@ it('should pass file when it isNull()', function (cb) { | ||
| it('should throw error if processors are not provided', function (cb) { | ||
| assert.throws( function () { postcss() }, gutil.PluginError ) | ||
| assert.throws( function () { postcss('') }, gutil.PluginError ) | ||
| assert.throws( function () { postcss({}) }, gutil.PluginError ) | ||
| cb() | ||
| }) | ||
| it('should generate source maps', function (cb) { | ||
@@ -119,3 +110,3 @@ | ||
| assert.equal(file.sourceMap.mappings, 'AAAA,IAAI,aAAY,CAAZ,aAAY,CAAZ,aAAY,CAAZ,YAAY,EAAE') | ||
| assert(/sourceMappingURL=data:application\/json;base64/.test(file.contents.toString())) | ||
| assert(/sourceMappingURL=data:application\/json;(?:charset=\w+;)?base64/.test(file.contents.toString())) | ||
| cb() | ||
@@ -176,9 +167,18 @@ }) | ||
| } | ||
| var postcssLoadConfigStub | ||
| var postcss = proxyquire('./index', { | ||
| postcss: function () { | ||
| postcss: function (plugins) { | ||
| postcssStub.use(plugins) | ||
| return postcssStub | ||
| } | ||
| , 'postcss-load-config': function (ctx, configPath) { | ||
| return postcssLoadConfigStub(ctx, configPath) | ||
| } | ||
| , 'vinyl-sourcemaps-apply': function () { | ||
| return {} | ||
| } | ||
| }) | ||
| beforeEach(function () { | ||
| postcssLoadConfigStub = sandbox.stub() | ||
| sandbox.stub(postcssStub, 'use') | ||
@@ -192,3 +192,2 @@ sandbox.stub(postcssStub, 'process') | ||
| it('should set `from` and `to` processing options to `file.path`', function (cb) { | ||
@@ -243,2 +242,169 @@ | ||
| it('should take plugins and options from callback', function (cb) { | ||
| var cssPath = __dirname + '/fixture.css' | ||
| var file = new gutil.File({ | ||
| contents: new Buffer('a {}') | ||
| , path: cssPath | ||
| }) | ||
| var plugins = [ doubler ] | ||
| var callback = sandbox.stub().returns({ | ||
| plugins: plugins | ||
| , options: { to: 'overriden' } | ||
| }) | ||
| var stream = postcss(callback) | ||
| postcssStub.process.returns(Promise.resolve({ | ||
| css: '' | ||
| , warnings: function () { | ||
| return [] | ||
| } | ||
| })) | ||
| stream.on('data', function () { | ||
| assert.equal(callback.getCall(0).args[0], file) | ||
| assert.equal(postcssStub.use.getCall(0).args[0], plugins) | ||
| assert.equal(postcssStub.process.getCall(0).args[1].to, 'overriden') | ||
| cb() | ||
| }) | ||
| stream.end(file) | ||
| }) | ||
| it('should take plugins and options from postcss-load-config', function (cb) { | ||
| var cssPath = __dirname + '/fixture.css' | ||
| var file = new gutil.File({ | ||
| contents: new Buffer('a {}') | ||
| , path: cssPath | ||
| }) | ||
| var stream = postcss({ to: 'initial' }) | ||
| var plugins = [ doubler ] | ||
| postcssLoadConfigStub.returns(Promise.resolve({ | ||
| plugins: plugins | ||
| , options: { to: 'overriden' } | ||
| })) | ||
| postcssStub.process.returns(Promise.resolve({ | ||
| css: '' | ||
| , warnings: function () { | ||
| return [] | ||
| } | ||
| })) | ||
| stream.on('data', function () { | ||
| assert.deepEqual(postcssLoadConfigStub.getCall(0).args[0], { | ||
| file: file | ||
| , options: { to: 'initial' } | ||
| }) | ||
| assert.equal(postcssStub.use.getCall(0).args[0], plugins) | ||
| assert.equal(postcssStub.process.getCall(0).args[1].to, 'overriden') | ||
| cb() | ||
| }) | ||
| stream.end(file) | ||
| }) | ||
| it('should point the config location to file directory', function (cb) { | ||
| var cssPath = __dirname + '/fixture.css' | ||
| var stream = postcss() | ||
| postcssLoadConfigStub.returns(Promise.resolve({ plugins: [] })) | ||
| postcssStub.process.returns(Promise.resolve({ | ||
| css: '' | ||
| , warnings: function () { | ||
| return [] | ||
| } | ||
| })) | ||
| stream.on('data', function () { | ||
| assert.deepEqual(postcssLoadConfigStub.getCall(0).args[1], __dirname) | ||
| cb() | ||
| }) | ||
| stream.end(new gutil.File({ | ||
| contents: new Buffer('a {}') | ||
| , path: cssPath | ||
| })) | ||
| }) | ||
| it('should set the config location from option', function (cb) { | ||
| var cssPath = __dirname + '/fixture.css' | ||
| var stream = postcss({ config: '/absolute/path' }) | ||
| postcssLoadConfigStub.returns(Promise.resolve({ plugins: [] })) | ||
| postcssStub.process.returns(Promise.resolve({ | ||
| css: '' | ||
| , warnings: function () { | ||
| return [] | ||
| } | ||
| })) | ||
| stream.on('data', function () { | ||
| assert.deepEqual(postcssLoadConfigStub.getCall(0).args[1], '/absolute/path') | ||
| cb() | ||
| }) | ||
| stream.end(new gutil.File({ | ||
| contents: new Buffer('a {}') | ||
| , path: cssPath | ||
| })) | ||
| }) | ||
| it('should set the config location from option relative to the base dir', function (cb) { | ||
| var cssPath = __dirname + '/src/fixture.css' | ||
| var stream = postcss({ config: './relative/path' }) | ||
| postcssLoadConfigStub.returns(Promise.resolve({ plugins: [] })) | ||
| postcssStub.process.returns(Promise.resolve({ | ||
| css: '' | ||
| , warnings: function () { | ||
| return [] | ||
| } | ||
| })) | ||
| stream.on('data', function () { | ||
| assert.deepEqual(postcssLoadConfigStub.getCall(0).args[1], __dirname + '/relative/path') | ||
| cb() | ||
| }) | ||
| stream.end(new gutil.File({ | ||
| contents: new Buffer('a {}') | ||
| , path: cssPath | ||
| , base: __dirname | ||
| })) | ||
| }) | ||
| it('should not override `from` and `map` if using gulp-sourcemaps', function (cb) { | ||
| var stream = postcss([ doubler ], { from: 'overriden', map: 'overriden' }) | ||
| var cssPath = __dirname + '/fixture.css' | ||
| postcssStub.process.returns(Promise.resolve({ | ||
| css: '' | ||
| , warnings: function () { | ||
| return [] | ||
| } | ||
| , map: { | ||
| toJSON: function () { | ||
| return { | ||
| sources: [], | ||
| file: '' | ||
| } | ||
| } | ||
| } | ||
| })) | ||
| sandbox.stub(gutil, 'log') | ||
| stream.on('data', function () { | ||
| assert.deepEqual(postcssStub.process.getCall(0).args[1].from, cssPath) | ||
| assert.deepEqual(postcssStub.process.getCall(0).args[1].map, { annotation: false }) | ||
| var firstMessage = gutil.log.getCall(0).args[1] | ||
| var secondMessage = gutil.log.getCall(1).args[1] | ||
| assert(firstMessage, '/fixture.css\nCannot override from option, because it is required by gulp-sourcemaps') | ||
| assert(secondMessage, '/fixture.css\nCannot override map option, because it is required by gulp-sourcemaps') | ||
| cb() | ||
| }) | ||
| var file = new gutil.File({ | ||
| contents: new Buffer('a {}') | ||
| , path: cssPath | ||
| }) | ||
| file.sourceMap = {} | ||
| stream.end(file) | ||
| }) | ||
| it('should not output js stack trace for `CssSyntaxError`', function (cb) { | ||
@@ -270,3 +436,3 @@ | ||
| function Warning (msg) { | ||
| this.toSting = function () { | ||
| this.toString = function () { | ||
| return msg | ||
@@ -285,3 +451,3 @@ } | ||
| stream.on('data', function () { | ||
| gutil.log.calledWith('gulp-postcss:', '/src/fixture.css\nmsg1\nmsg2') | ||
| assert(gutil.log.calledWith('gulp-postcss:', 'src' + path.sep + 'fixture.css\nmsg1\nmsg2')) | ||
| cb() | ||
@@ -288,0 +454,0 @@ }) |
24649
50.43%4
-20%526
57.96%261
45%4
33.33%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
Updated
Updated