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:
parent
225b9d306b
commit
31f85f0297
|
@ -45,3 +45,6 @@ npm-debug.log
|
|||
|
||||
# build-analytics
|
||||
.build-analytics
|
||||
|
||||
# built dart payload tests
|
||||
/modules_dart/payload/**/build
|
||||
|
|
34
gulpfile.js
34
gulpfile.js
|
@ -252,8 +252,9 @@ gulp.task('build/check.apidocs.dart',
|
|||
// pubbuild
|
||||
// WARNING: this task is very slow (~15m as of July 2015)
|
||||
|
||||
gulp.task('build/pubbuild.dart',
|
||||
pubbuild(gulp, gulpPlugins,
|
||||
gulp.task(
|
||||
'build/pubbuild.dart',
|
||||
pubbuild.subdirs(gulp, gulpPlugins,
|
||||
{src: CONFIG.dest.dart, dest: CONFIG.dest.js.dart2js, command: DART_SDK.PUB}));
|
||||
|
||||
// ------------
|
||||
|
@ -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) {
|
||||
runSequence('build/tree.dart', 'build/pure-packages.dart', '!build/pubget.angular2.dart',
|
||||
'!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.task('!bundles.js.checksize', function() {
|
||||
gulp.task('!bundles.js.checksize', function(done) {
|
||||
var reportSize = require('./tools/analytics/reportsize');
|
||||
return reportSize('dist/js/bundle/**', {printToConsole: false,
|
||||
reportAnalytics: true});
|
||||
return reportSize('dist/js/bundle/**', {printToConsole: ['gzip level=2']});
|
||||
});
|
||||
|
||||
gulp.task('bundles.js',
|
||||
|
|
|
@ -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
|
|
@ -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";
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -22,11 +22,15 @@ const _gzipConfigs = {
|
|||
|
||||
const _defaultOptions = {
|
||||
// @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.
|
||||
failConditions: {},
|
||||
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
|
||||
};
|
||||
|
||||
|
@ -41,7 +45,7 @@ function reportSize(glob, options) {
|
|||
options[key] = _defaultOptions[key];
|
||||
}
|
||||
}
|
||||
var errStream = _checkFailConditionConfig(options.failConditions);
|
||||
var errStream = _checkConfig(options);
|
||||
if (errStream) {
|
||||
return errStream;
|
||||
}
|
||||
|
@ -83,27 +87,29 @@ function reportSize(glob, options) {
|
|||
if (options.reportAnalytics) {
|
||||
analytics.bundleSize(filePath, fileLen, compressionLevel);
|
||||
}
|
||||
if (options.printToConsole) {
|
||||
if (_shouldPrint(options, compressionLevel)) {
|
||||
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]}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 `null` if everything is fine.
|
||||
function _checkFailConditionConfig(failConditions) {
|
||||
for (const key in failConditions) {
|
||||
if (failConditions.hasOwnProperty(key)) {
|
||||
function _checkConfig(config) {
|
||||
for (const key in config.failConditions) {
|
||||
if (config.failConditions.hasOwnProperty(key)) {
|
||||
if (!_gzipConfigs.hasOwnProperty(key)) {
|
||||
var stream = new Stream();
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ var path = require('path');
|
|||
var glob = require('glob');
|
||||
var fs = require('fs');
|
||||
|
||||
module.exports = function(gulp, plugins, config) {
|
||||
function buildAllWebSubdirs(gulp, plugins, config) {
|
||||
return function() {
|
||||
var webFolders = [].slice.call(glob.sync(path.join(config.src, '*/web')));
|
||||
return nextFolder();
|
||||
|
@ -17,20 +17,34 @@ module.exports = function(gulp, plugins, config) {
|
|||
}
|
||||
var folder = path.resolve(path.join(webFolders.shift(), '..'));
|
||||
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, {
|
||||
stdio: 'inherit',
|
||||
cwd: folder
|
||||
})).then(function() {
|
||||
const nextConfig = {
|
||||
command: config.command,
|
||||
dest: destFolder,
|
||||
mode: config.mode,
|
||||
src: folder
|
||||
};
|
||||
return single(nextConfig).then(function() {
|
||||
return replaceDartWithJsScripts(gulp, destFolder);
|
||||
}).then(function() {
|
||||
return removeWebFolder(gulp, destFolder);
|
||||
}).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) {
|
||||
return util.streamToPromise(gulp.src(path.join(folder, '**/*.html'))
|
||||
|
@ -45,6 +59,10 @@ function replaceDartWithJsScripts(gulp, folder) {
|
|||
.pipe(gulp.dest(folder)));
|
||||
}
|
||||
|
||||
function singleWrapper(gulp, plugins, config) {
|
||||
return function() { return single(config); };
|
||||
}
|
||||
|
||||
function removeWebFolder(gulp, folder) {
|
||||
var folders = [].slice.call(glob.sync(path.join(folder, 'web', '*')));
|
||||
folders.forEach(function(subFolder) {
|
||||
|
@ -53,3 +71,8 @@ function removeWebFolder(gulp, folder) {
|
|||
fs.rmdirSync(path.join(folder, 'web'));
|
||||
return Q.resolve();
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
single: singleWrapper,
|
||||
subdirs: buildAllWebSubdirs
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue