gulp-postcss
Advanced tools
Comparing version 6.2.0 to 6.3.0
92
index.js
@@ -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 | ||
) | ||
}) | ||
} | ||
} | ||
} |
{ | ||
"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" |
113
README.md
# gulp-postcss [![Build Status](https://api.travis-ci.org/postcss/gulp-postcss.png)](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 |
196
test.js
/* 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 @@ }) |
Sorry, the diff of this file is not supported yet
24649
4
526
261
4
+ Addedpostcss-load-config@^1.1.0
+ Addedargparse@1.0.10(transitive)
+ Addedcosmiconfig@2.2.2(transitive)
+ Addederror-ex@1.3.2(transitive)
+ Addedesprima@4.0.1(transitive)
+ Addedis-arrayish@0.2.1(transitive)
+ Addedis-directory@0.3.1(transitive)
+ Addedjs-yaml@3.14.1(transitive)
+ Addedobject-assign@4.1.1(transitive)
+ Addedos-homedir@1.0.2(transitive)
+ Addedparse-json@2.2.0(transitive)
+ Addedpostcss-load-config@1.2.0(transitive)
+ Addedpostcss-load-options@1.2.0(transitive)
+ Addedpostcss-load-plugins@2.3.0(transitive)
+ Addedrequire-from-string@1.2.1(transitive)
+ Addedsprintf-js@1.0.3(transitive)
Updatedgulp-util@^3.0.8
Updatedpostcss@^5.2.10