diff --git a/gulpfile.js b/gulpfile.js index 6b7f3c1179..8aecc37e20 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1054,34 +1054,9 @@ gulp.task('!bundle.copy', function() { }); gulp.task('!bundles.js.checksize', function() { - var gzip = require('gulp-gzip'); - var path = require('path'); - - return merge2(gulp.src('dist/js/bundle/**').on('data', checkFileSizeFactory('uncompressed')), - gulp.src('dist/js/bundle/**') - .pipe(gzip({gzipOptions: {level: 1}})) // code.angular.js - .on('data', checkFileSizeFactory('gzip level=1')), - gulp.src('dist/js/bundle/**') - .pipe(gzip({gzipOptions: {level: 2}})) // github pages, most common - .on('data', checkFileSizeFactory('gzip level=2', true)), - gulp.src('dist/js/bundle/**') - .pipe(gzip({gzipOptions: {level: 6}})) // default gzip level - .on('data', checkFileSizeFactory('gzip level=6')), - gulp.src('dist/js/bundle/**') - .pipe(gzip({gzipOptions: {level: 9}})) // max gzip level - .on('data', checkFileSizeFactory('gzip level=9'))); - - function checkFileSizeFactory(compressionLevel, printToConsole) { - return function checkFileSize(file) { - if (file.isNull()) return; - var filePath = - path.relative(path.join('dist', 'js', 'bundle'), file.path).replace('\.gz', ''); - analytics.bundleSize(filePath, file.contents.length, compressionLevel); - if (printToConsole) { - console.log(` ${filePath} => ${file.contents.length} bytes (${compressionLevel})`) - } - } - } + var reportSize = require('./tools/analytics/reportsize'); + return reportSize('dist/js/bundle/**', {printToConsole: false, + reportAnalytics: true}); }); gulp.task('bundles.js', diff --git a/tools/analytics/reportsize.js b/tools/analytics/reportsize.js new file mode 100644 index 0000000000..af44002726 --- /dev/null +++ b/tools/analytics/reportsize.js @@ -0,0 +1,120 @@ +'use strict'; + +let analytics = require('./analytics'); +let gulp = require('gulp'); +let gzip = require('gulp-gzip'); +let merge2 = require('merge2'); +let path = require('path'); +let Stream = require('stream'); + +// Keys are a text description of compressionLevel. +// Values are "gzipOptions" passed to gzip. +// We report one `analytics.bundleSize` event +// * each file in `glob` +// * each entry in `_gzipConfigs`. +const _gzipConfigs = { + 'uncompressed': null, + 'gzip level=1': {level: 1}, // code.angular.js + 'gzip level=2': {level: 2}, // github pages, most common + 'gzip level=6': {level: 6}, // default gzip level + 'gzip level=9': {level: 9} // max gzip level +}; + +const _defaultOptions = { + // @type {Object} + // - Key(s) must match keys of `_gzipConfigs`. + // - Values are the max size (in bytes) allowed for that configuration. + failConditions: {}, + prefix: '', + printToConsole: false, + reportAnalytics: true +}; + +// `glob` is a string representing a glob of files. +// options is an object containing zero or more of +// - printToConsole: Write debug to console. Default: false. +// - reportAnalytics: Report to Google Analytics. Default: true. +function reportSize(glob, options) { + options = options || {}; + for (const key in _defaultOptions) { + if (!options.hasOwnProperty(key)) { + options[key] = _defaultOptions[key]; + } + } + var errStream = _checkFailConditionConfig(options.failConditions); + if (errStream) { + return errStream; + } + + const allStreams = []; + for (const compressionLevel in _gzipConfigs) { + if (_gzipConfigs.hasOwnProperty(compressionLevel)) { + let stream = gulp.src(glob); + if (_gzipConfigs[compressionLevel]) { + stream = stream.pipe(gzip({gzipOptions: _gzipConfigs[compressionLevel]})); + } + allStreams.push(stream.on('data', checkFileSizeFactory(compressionLevel))); + } + } + + let didRun = false; + var errs = []; + return merge2(allStreams, {end: false}) + .on('queueDrain', function() { + if (errs.length) { + errs.unshift(`Failed with ${errs.length} error(s).`); + this.emit('error', new Error(errs.join('\n '))); + } + if (!didRun) { + this.emit('error', new Error(`No file found for pattern "${glob}".`)); + } + this.emit('end'); + }); + + function checkFileSizeFactory(compressionLevel) { + return function checkFileSize(file) { + if (file.isNull()) return; + didRun = true; + var filePath = path.basename(file.path).replace('\.gz', ''); + if (options.prefix) { + filePath = path.join(options.prefix, filePath); + } + const fileLen = file.contents.length; + if (options.reportAnalytics) { + analytics.bundleSize(filePath, fileLen, compressionLevel); + } + if (options.printToConsole) { + console.log(` ${filePath} => ${fileLen} bytes (${compressionLevel})`) + } + if (options.failConditions.hasOwnProperty(compressionLevel)) { + if (options.failConditions[compressionLevel] < fileLen) { + errs.push(`Max size for "${compressionLevel}" is ` + + `${options.failConditions[compressionLevel]}, but the size is now ${fileLen}.`); + if (options.printToConsole) { + console.log(` !!! ${errs[errs.length - 1]}`); + } + } + } + } + } +} + +// Returns an error stream if the fail conditions are not provided property. +// Returns `null` if everything is fine. +function _checkFailConditionConfig(failConditions) { + for (const key in failConditions) { + if (failConditions.hasOwnProperty(key)) { + if (!_gzipConfigs.hasOwnProperty(key)) { + var stream = new Stream(); + stream.emit( + 'error', + new Error(`failCondition for "${key}" will not be tested. Check _gzipConfigs.`)); + stream.emit('end'); + return stream; + } + } + } + return null; +} + +module.exports = reportSize;