* Replaces the old tokenizer with a new one which doesn't use any escaping.
* Replaces the old `@import` inlining with one on top of the new tokenizer.
* Simplifies URL rebasing with a single `rebaseTo` option in API or inferred from `--output` in CLI.
+* Splits `inliner` option into `inlineRequest` and `inlineTimeout`.
* Fixed issue [#209](https://github.com/jakubpawlowicz/clean-css/issues/209) - adds output formatting via `beautify` flag.
* Fixed issue [#432](https://github.com/jakubpawlowicz/clean-css/issues/432) - adds URLs normalization.
* Fixed issue [#657](https://github.com/jakubpawlowicz/clean-css/issues/657) - adds property name validation.
* `roundingPrecision` is disabled by default
* `roundingPrecision` applies to **all** units now, not only `px` as in 3.x;
* `processImport` and `processImportFrom` are merged into `inline` option which defaults to `local`. Remote `@import` rules are **NOT** inlined by default anymore.
+* renames CLI `--timeout` option to `--inline-timeout`;
+* splits API `inliner: { request: ..., timeout: ... }` option into `inlineRequest` and `inlineTimeout` options;
Please note this list is not final. You are more than welcome to comment these changes in [4.0 release discussion](https://github.com/jakubpawlowicz/clean-css/issues/842) thread.
-c, --compatibility [ie7|ie8] Force compatibility mode (see Readme for advanced examples)
-d, --debug Shows debug information (minification time & compression efficiency)
-o, --output [output-file] Use [output-file] as output instead of STDOUT
--t, --timeout [seconds] Per connection timeout when fetching remote @imports (defaults to 5 seconds)
--beautify Formats output CSS by using indentation and one rule or property per line
--inline [rules] Enables inlining for listed sources (defaults to `local`)
+--inline-timeout [seconds] Per connection timeout when fetching remote stylesheets (defaults to 5 seconds)
--rounding-precision [n] Rounds pixel values to `N` decimal places. `off` disables rounding (defaults to `off`)
--s0 Remove all special comments, i.e. /*! comment */
--s1 Remove all special comments but the first one
* `benchmark` - turns on benchmarking mode measuring time spent on cleaning up (run `npm run bench` to see example)
* `compatibility` - enables compatibility mode, see [below for more examples](#how-to-set-a-compatibility-mode)
* `inline` - whether to inline `@import` rules, can be `['all']`, `['local']` (default), `['remote']`, or a blacklisted domain/path e.g. `['!fonts.googleapis.com']`
-* `inliner` - a hash of options for `@import` inliner, see [test/protocol-imports-test.js](https://github.com/jakubpawlowicz/clean-css/blob/master/test/protocol-imports-test.js#L372) for examples, or [this comment](https://github.com/jakubpawlowicz/clean-css/issues/612#issuecomment-119594185) for a proxy use case.
+* `inlineRequest` - an object with [HTTP(S) request options](https://nodejs.org/api/http.html#http_http_request_options_callback) for inlining remote `@import` rules
+* `inlineTimeout` - an integer denoting a number of milliseconds after which inlining a remote `@import` fails (defaults to 5000 ms)
* `keepBreaks` - whether to keep line breaks (default is false)
* `keepSpecialComments` - `*` for keeping all (default), `1` for keeping first one only, `0` for removing all
* `mediaMerging` - whether to merge `@media` at-rules (default is true)
.option('-c, --compatibility [ie7|ie8]', 'Force compatibility mode (see Readme for advanced examples)')
.option('-d, --debug', 'Shows debug information (minification time & compression efficiency)')
.option('-o, --output [output-file]', 'Use [output-file] as output instead of STDOUT')
- .option('-t, --timeout [seconds]', 'Per connection timeout when fetching remote @imports (defaults to 5 seconds)')
.option('--beautify', 'Formats output CSS by using indentation and one rule or property per line')
.option('--inline [rules]', 'Enables inlining for listed sources (defaults to `local`)')
+ .option('--inline-timeout [seconds]', 'Per connection timeout when fetching remote stylesheets (defaults to 5 seconds)', parseFloat)
.option('--rounding-precision [n]', 'Rounds pixel values to `N` decimal places. -1 disables rounding (defaults to -1)')
.option('--s0', 'Remove all special comments, i.e. /*! comment */')
.option('--s1', 'Remove all special comments but the first one')
beautify: commands.beautify,
compatibility: commands.compatibility,
inline: commands.inline || 'local',
- inliner: commands.timeout ? { timeout: parseFloat(commands.timeout) * 1000 } : undefined,
+ inlineTimeout: commands.inlineTimeout * 1000,
keepBreaks: !!commands.keepLineBreaks,
keepSpecialComments: commands.s0 ? 0 : (commands.s1 ? 1 : '*'),
mediaMerging: commands.skipMediaMerging ? false : true,
benchmark: options.benchmark,
compatibility: compatibility(options.compatibility),
inline: inlineOptionsFrom(options.inline),
- inliner: options.inliner || {},
+ inlineRequest: options.inlineRequest || {},
+ inlineTimeout: options.inlineTimeout || DEFAULT_TIMEOUT,
keepBreaks: options.keepBreaks || false,
keepSpecialComments: 'keepSpecialComments' in options ? options.keepSpecialComments : '*',
mediaMerging: undefined === options.mediaMerging ? true : !!options.mediaMerging,
sourceMapInlineSources: !!options.sourceMapInlineSources
};
- this.options.inliner.timeout = this.options.inliner.timeout || DEFAULT_TIMEOUT;
- this.options.inliner.request = override(
+ this.options.inlineRequest = override(
/* jshint camelcase: false */
proxyOptionsFrom(process.env.HTTP_PROXY || process.env.http_proxy),
- this.options.inliner.request || {}
+ this.options.inlineRequest
);
};
callback: callback,
index: 0,
inline: context.options.inline,
- inliner: context.options.inliner,
+ inlineRequest: context.options.inlineRequest,
+ inlineTimeout: context.options.inlineTimeout,
inputSourceMapTracker: context.inputSourceMapTracker,
localOnly: context.localOnly,
processedTokens: [],
return whenLoaded(null);
}
- loadRemoteResource(uri, applyContext.inliner, function (error, body) {
+ loadRemoteResource(uri, applyContext.inlineRequest, applyContext.inlineTimeout, function (error, body) {
if (error) {
applyContext.warnings.push('Missing source map at "' + uri + '" - ' + error);
return whenLoaded(null);
callback: callback,
index: 0,
inline: context.options.inline,
- inliner: context.options.inliner,
+ inlineRequest: context.options.inlineRequest,
+ inlineTimeout: context.options.inlineTimeout,
localOnly: context.localOnly,
rebaseTo: context.options.rebaseTo,
sourcesContent: context.sourcesContent,
return whenLoaded(null);
}
- loadRemoteResource(uri, loadContext.inliner, function (error, content) {
+ loadRemoteResource(uri, loadContext.inlineRequest, loadContext.inlineTimeout, function (error, content) {
if (error) {
loadContext.warnings.push('Missing original source at "' + uri + '" - ' + error);
}
var HTTP_PROTOCOL = 'http:';
-function loadRemoteResource(uri, inlinerOptions, callback) {
- var proxyProtocol = inlinerOptions.request.protocol || inlinerOptions.request.hostname;
+function loadRemoteResource(uri, inlineRequest, inlineTimeout, callback) {
+ var proxyProtocol = inlineRequest.protocol || inlineRequest.hostname;
var errorHandled = false;
var requestOptions;
var fetch;
requestOptions = override(
url.parse(uri),
- inlinerOptions.request || {}
+ inlineRequest || {}
);
- if (inlinerOptions.request.hostname !== undefined) {
+ if (inlineRequest.hostname !== undefined) {
// overwrite as we always expect a http proxy currently
- requestOptions.protocol = inlinerOptions.request.protocol || HTTP_PROTOCOL;
+ requestOptions.protocol = inlineRequest.protocol || HTTP_PROTOCOL;
requestOptions.path = requestOptions.href;
}
return callback(res.statusCode, null);
} else if (res.statusCode > 299) {
movedUri = url.resolve(uri, res.headers.location);
- return loadRemoteResource(movedUri, inlinerOptions, callback);
+ return loadRemoteResource(movedUri, inlineRequest, inlineTimeout, callback);
}
res.on('data', function (chunk) {
errorHandled = true;
callback('timeout', null);
})
- .setTimeout(inlinerOptions.timeout);
+ .setTimeout(inlineTimeout);
}
module.exports = loadRemoteResource;
externalContext: externalContext,
inlinedStylesheets: parentInlinerContext.inlinedStylesheets || externalContext.inlinedStylesheets,
inline: parentInlinerContext.inline,
- inlinerOptions: externalContext.options.inliner,
+ inlineRequest: externalContext.options.inlineRequest,
+ inlineTimeout: externalContext.options.inlineTimeout,
isRemote: parentInlinerContext.isRemote || false,
localOnly: externalContext.localOnly,
outputTokens: [],
return isLoaded ?
whenLoaded(null, inlinerContext.externalContext.sourcesContent[uri]) :
- loadRemoteResource(uri, inlinerContext.inlinerOptions, whenLoaded);
+ loadRemoteResource(uri, inlinerContext.inlineRequest, inlinerContext.inlineTimeout, whenLoaded);
}
function inlineLocalStylesheet(uri, mediaQuery, metadata, inlinerContext) {
setTimeout(function () {}, 1000);
});
this.server.listen('24682', function () {
- exec('echo "' + source + '" | ./bin/cleancss --timeout 0.01 --inline all', self.callback);
+ exec('echo "' + source + '" | ./bin/cleancss --inline all --inline-timeout 0.01', self.callback);
});
},
'should raise warning': function (error, stdout, stderr) {
new CleanCSS({
inline: 'all',
- inliner: {
- request: {
- method: 'POST'
- }
+ inlineRequest: {
+ method: 'POST'
}
}).minify('@import url(http://127.0.0.1/computed.css);a{color:red}', this.callback);
},
this.server.listen(port, function () {
new CleanCSS({
inline: 'all',
- inliner: {
- timeout: timeout
- }
+ inlineTimeout: timeout
}).minify('@import url(http://localhost:' + port + '/timeout.css);a{color:red}', self.callback);
});
enableDestroy(self.server);
this.proxyServer.listen(8080, function () {
var options = {
inline: 'all',
- inliner: {
- request: {
- hostname: '127.0.0.1',
- port: 8080
- }
+ inlineRequest: {
+ hostname: '127.0.0.1',
+ port: 8080
}
};
this.proxyServer.listen(8080, function () {
var options = {
inline: 'all',
- inliner: {
- request: {
- hostname: '127.0.0.1',
- port: 8080
- }
+ inlineRequest: {
+ hostname: '127.0.0.1',
+ port: 8080
}
};
this.proxyServer.listen(8082, function () {
var options = {
inline: 'all',
- inliner: {
- request: {
- hostname: '127.0.0.1',
- port: 8082
- }
+ inlineRequest: {
+ hostname: '127.0.0.1',
+ port: 8082
}
};
}
});
this.server.listen(port, '127.0.0.1', function () {
- new CleanCSS({ inline: 'all', sourceMap: true, inliner: { timeout: timeout } })
+ new CleanCSS({ inline: 'all', inlineTimeout: timeout, sourceMap: true })
.minify('@import url(http://127.0.0.1:' + port + '/remote.css);', self.callback);
});
enableDestroy(this.server);
.post('/remote.css.map')
.reply(200, inputMap);
- new CleanCSS({ inline: 'all', sourceMap: true, inliner: { request: { method: 'POST' } } })
+ new CleanCSS({ inline: 'all', inlineRequest: { method: 'POST' }, sourceMap: true })
.minify('@import url(http://127.0.0.1/remote.css);', this.callback);
},
'has mapping': function (errors, minified) {