chore(analytics): Build hello_world, check constraints

Create gulp targets to build `hello_world` and check its gzipped size
against size constraints.

See #5312, #5314
This commit is contained in:
Tim Blasi 2015-11-19 16:08:23 -08:00 committed by Timothy Blasi
parent 225b9d306b
commit 31f85f0297
7 changed files with 197 additions and 24 deletions

3
.gitignore vendored
View File

@ -45,3 +45,6 @@ npm-debug.log
# build-analytics # build-analytics
.build-analytics .build-analytics
# built dart payload tests
/modules_dart/payload/**/build

View File

@ -252,9 +252,10 @@ gulp.task('build/check.apidocs.dart',
// pubbuild // pubbuild
// WARNING: this task is very slow (~15m as of July 2015) // WARNING: this task is very slow (~15m as of July 2015)
gulp.task('build/pubbuild.dart', gulp.task(
pubbuild(gulp, gulpPlugins, 'build/pubbuild.dart',
{src: CONFIG.dest.dart, dest: CONFIG.dest.js.dart2js, command: DART_SDK.PUB})); pubbuild.subdirs(gulp, gulpPlugins,
{src: CONFIG.dest.dart, dest: CONFIG.dest.js.dart2js, command: DART_SDK.PUB}));
// ------------ // ------------
// formatting // formatting
@ -584,6 +585,30 @@ gulp.task('test.unit.dart', function(done) {
}); });
}); });
// Dart Payload Size Test
// This test will fail if the size of our hello_world app goes beyond one of
// these values when compressed at the specified level.
// Measure in bytes.
var _DART_PAYLOAD_SIZE_LIMITS = {'uncompressed': 375 * 1024, 'gzip level=6': 105 * 1024};
gulp.task('test.payload.dart/ci', function(done) {
runSequence('build/packages.dart', '!pubget.payload.dart', '!pubbuild.payload.dart',
'!checkAndReport.payload.dart', done);
});
gulp.task('!pubget.payload.dart',
pubget.dir(gulp, gulpPlugins,
{dir: 'modules_dart/payload/hello_world', command: DART_SDK.PUB}));
gulp.task('!pubbuild.payload.dart',
pubbuild.single(gulp, gulpPlugins,
{command: DART_SDK.PUB, src: 'modules_dart/payload/hello_world'}));
gulp.task('!checkAndReport.payload.dart', function() {
var reportSize = require('./tools/analytics/reportsize');
return reportSize('modules_dart/payload/hello_world/build/web/*.dart.js',
{failConditions: _DART_PAYLOAD_SIZE_LIMITS, prefix: 'hello_world'});
});
gulp.task('watch.dart.dev', function(done) { gulp.task('watch.dart.dev', function(done) {
runSequence('build/tree.dart', 'build/pure-packages.dart', '!build/pubget.angular2.dart', runSequence('build/tree.dart', 'build/pure-packages.dart', '!build/pubget.angular2.dart',
'!build/change_detect.dart', '!build/remove-pub-symlinks', 'build.dart.material.css', '!build/change_detect.dart', '!build/remove-pub-symlinks', 'build.dart.material.css',
@ -1053,10 +1078,9 @@ gulp.task('!bundle.copy', function() {
gulp.src('dist/js/bundle/**').pipe(gulp.dest('dist/js/dev/es5/bundle'))); gulp.src('dist/js/bundle/**').pipe(gulp.dest('dist/js/dev/es5/bundle')));
}); });
gulp.task('!bundles.js.checksize', function() { gulp.task('!bundles.js.checksize', function(done) {
var reportSize = require('./tools/analytics/reportsize'); var reportSize = require('./tools/analytics/reportsize');
return reportSize('dist/js/bundle/**', {printToConsole: false, return reportSize('dist/js/bundle/**', {printToConsole: ['gzip level=2']});
reportAnalytics: true});
}); });
gulp.task('bundles.js', gulp.task('bundles.js',

View File

@ -0,0 +1,24 @@
name: hello_world
environment:
sdk: '>=1.10.0 <2.0.0'
dependencies:
observe: '^0.13.1'
angular2: any
browser: '^0.10.0'
dependency_overrides:
angular2:
path: ../../../dist/dart/angular2
transformers:
- angular2:
platform_directives: 'package:angular2/src/common/directives.dart#CORE_DIRECTIVES'
entry_points:
- web/index.dart
- $dart2js:
minify: true
commandLineOptions:
- --show-package-warnings
- --trust-type-annotations
- --trust-primitives
# Uncomment to generate summaries from dart2js
# - --dump-info

View File

@ -0,0 +1,68 @@
library hello_world.index;
import "package:angular2/bootstrap.dart" show bootstrap;
import "package:angular2/core.dart"
show ElementRef, Component, Directive, Injectable;
import "package:angular2/render.dart" show Renderer;
main() {
// Bootstrapping only requires specifying a root component.
// The boundary between the Angular application and the rest of the page is
// the shadowDom of this root component.
// The selector of the component passed in is used to find where to insert the
// application.
// You can use the light dom of the <hello-app> tag as temporary content (for
// example 'Loading...') before the application is ready.
bootstrap(HelloCmp);
}
// A service available to the Injector, used by the HelloCmp component.
@Injectable()
class GreetingService {
String greeting = "hello";
}
// Directives are light-weight. They don't allow new
// expression contexts (use @Component for those needs).
@Directive(selector: "[red]")
class RedDec {
// ElementRef is always injectable and it wraps the element on which the
// directive was found by the compiler.
RedDec(ElementRef el, Renderer renderer) {
renderer.setElementStyle(el, "color", "red");
}
}
// Angular 2.0 supports 2 basic types of directives:
// - Component - the basic building blocks of Angular 2.0 apps. Backed by
// ShadowDom.(http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom/)
// - Directive - add behavior to existing elements.
// @Component is AtScript syntax to annotate the HelloCmp class as an Angular
// 2.0 component.
@Component(
selector: "hello-app",
viewProviders: const [GreetingService],
template:
'''<div class="greeting">{{greeting}} <span red>world</span>!</div>
<button class="changeButton" (click)="changeGreeting()">change greeting</button>''',
directives: const [RedDec])
class HelloCmp {
String greeting;
HelloCmp(GreetingService service) {
this.greeting = service.greeting;
}
void changeGreeting() {
this.greeting = "howdy";
}
}

View File

@ -0,0 +1,12 @@
<!doctype html>
<html>
<title>Hello Angular 2.0</title>
<body>
<hello-app>
Loading...
</hello-app>
<script src="index.dart" type="application/dart"></script>
<script src="packages/browser/dart.js" type="text/javascript"></script>
</body>
</html>

View File

@ -22,11 +22,15 @@ const _gzipConfigs = {
const _defaultOptions = { const _defaultOptions = {
// @type {Object<string, number>} // @type {Object<string, number>}
// - Key(s) must match keys of `_gzipConfigs`. // - Key(s) must match one of `_gzipConfigs` keys.
// - Values are the max size (in bytes) allowed for that configuration. // - Values are the max size (in bytes) allowed for that configuration.
failConditions: {}, failConditions: {},
prefix: '', prefix: '',
printToConsole: false, // @type {Array<string>|boolean}
// Entries must match one of `_gzipConfigs` keys. These values will be
// printed to the screen.
// If this is the boolean value `true`, will print all to screen.
printToConsole: ['gzip level=6'],
reportAnalytics: true reportAnalytics: true
}; };
@ -41,7 +45,7 @@ function reportSize(glob, options) {
options[key] = _defaultOptions[key]; options[key] = _defaultOptions[key];
} }
} }
var errStream = _checkFailConditionConfig(options.failConditions); var errStream = _checkConfig(options);
if (errStream) { if (errStream) {
return errStream; return errStream;
} }
@ -83,27 +87,29 @@ function reportSize(glob, options) {
if (options.reportAnalytics) { if (options.reportAnalytics) {
analytics.bundleSize(filePath, fileLen, compressionLevel); analytics.bundleSize(filePath, fileLen, compressionLevel);
} }
if (options.printToConsole) { if (_shouldPrint(options, compressionLevel)) {
console.log(` ${filePath} => ${fileLen} bytes (${compressionLevel})`) console.log(` ${filePath} => ${fileLen} bytes (${compressionLevel})`)
} }
if (options.failConditions.hasOwnProperty(compressionLevel)) { if (options.failConditions.hasOwnProperty(compressionLevel)) {
if (options.failConditions[compressionLevel] < fileLen) { if (options.failConditions[compressionLevel] < fileLen) {
errs.push(`Max size for "${compressionLevel}" is ` + errs.push(`Max size for "${compressionLevel}" is ` +
`${options.failConditions[compressionLevel]}, but the size is now ${fileLen}.`); `${options.failConditions[compressionLevel]}, but the size is now ${fileLen}.`);
if (options.printToConsole) {
console.log(` !!! ${errs[errs.length - 1]}`);
}
} }
} }
} }
} }
} }
function _shouldPrint(options, compressionLevel) {
const printAll = typeof options.printToConsole == 'boolean' && options.printToConsole;
return printAll || options.printToConsole.indexOf(compressionLevel) >= 0;
}
// Returns an error stream if the fail conditions are not provided property. // Returns an error stream if the fail conditions are not provided property.
// Returns `null` if everything is fine. // Returns `null` if everything is fine.
function _checkFailConditionConfig(failConditions) { function _checkConfig(config) {
for (const key in failConditions) { for (const key in config.failConditions) {
if (failConditions.hasOwnProperty(key)) { if (config.failConditions.hasOwnProperty(key)) {
if (!_gzipConfigs.hasOwnProperty(key)) { if (!_gzipConfigs.hasOwnProperty(key)) {
var stream = new Stream(); var stream = new Stream();
stream.emit( stream.emit(
@ -114,6 +120,19 @@ function _checkFailConditionConfig(failConditions) {
} }
} }
} }
if (typeof config.printToConsole != 'boolean') {
for (var i = 0; i < config.printToConsole.length; ++i) {
const key = config.printToConsole[i];
if (!_gzipConfigs.hasOwnProperty(key)) {
var stream = new Stream();
stream.emit(
'error',
new Error(`Incorrect value "${key}" in printToConsole. Check _gzipConfigs.`));
stream.emit('end');
return stream;
}
}
}
return null; return null;
} }

View File

@ -6,7 +6,7 @@ var path = require('path');
var glob = require('glob'); var glob = require('glob');
var fs = require('fs'); var fs = require('fs');
module.exports = function(gulp, plugins, config) { function buildAllWebSubdirs(gulp, plugins, config) {
return function() { return function() {
var webFolders = [].slice.call(glob.sync(path.join(config.src, '*/web'))); var webFolders = [].slice.call(glob.sync(path.join(config.src, '*/web')));
return nextFolder(); return nextFolder();
@ -17,20 +17,34 @@ module.exports = function(gulp, plugins, config) {
} }
var folder = path.resolve(path.join(webFolders.shift(), '..')); var folder = path.resolve(path.join(webFolders.shift(), '..'));
var destFolder = path.resolve(path.join(config.dest, path.basename(folder))); var destFolder = path.resolve(path.join(config.dest, path.basename(folder)));
var pubMode = config.mode || 'release';
var pubArgs = ['build', '--mode', pubMode, '-o', destFolder];
return util.processToPromise(spawn(config.command, pubArgs, { const nextConfig = {
stdio: 'inherit', command: config.command,
cwd: folder dest: destFolder,
})).then(function() { mode: config.mode,
src: folder
};
return single(nextConfig).then(function() {
return replaceDartWithJsScripts(gulp, destFolder); return replaceDartWithJsScripts(gulp, destFolder);
}).then(function() { }).then(function() {
return removeWebFolder(gulp, destFolder); return removeWebFolder(gulp, destFolder);
}).then(nextFolder); }).then(nextFolder);
} }
}; };
}; }
function single(config) {
var pubMode = config.mode || 'release';
var pubArgs = ['build', '--mode', pubMode];
if (config.dest) {
pubArgs = pubArgs.concat(['-o', config.dest]);
}
return util.processToPromise(spawn(config.command, pubArgs, {
stdio: 'inherit',
cwd: config.src
}));
}
function replaceDartWithJsScripts(gulp, folder) { function replaceDartWithJsScripts(gulp, folder) {
return util.streamToPromise(gulp.src(path.join(folder, '**/*.html')) return util.streamToPromise(gulp.src(path.join(folder, '**/*.html'))
@ -45,6 +59,10 @@ function replaceDartWithJsScripts(gulp, folder) {
.pipe(gulp.dest(folder))); .pipe(gulp.dest(folder)));
} }
function singleWrapper(gulp, plugins, config) {
return function() { return single(config); };
}
function removeWebFolder(gulp, folder) { function removeWebFolder(gulp, folder) {
var folders = [].slice.call(glob.sync(path.join(folder, 'web', '*'))); var folders = [].slice.call(glob.sync(path.join(folder, 'web', '*')));
folders.forEach(function(subFolder) { folders.forEach(function(subFolder) {
@ -53,3 +71,8 @@ function removeWebFolder(gulp, folder) {
fs.rmdirSync(path.join(folder, 'web')); fs.rmdirSync(path.join(folder, 'web'));
return Q.resolve(); return Q.resolve();
} }
module.exports = {
single: singleWrapper,
subdirs: buildAllWebSubdirs
};