From 4e12b0831eaec905d20aa194ac834333d88c96ee Mon Sep 17 00:00:00 2001 From: Olivier Chafik Date: Wed, 18 Nov 2015 15:07:08 -0800 Subject: [PATCH] Make Angular2 transformers lazy in debug mode when option `lazy_transformers: true` is set. This make apps to load quicker with pub serve (only builds what is needed). Note that lazy transformers seem to make pub build slower, so we wrap transformers to force them to be eager in release mode. Closes #5372 --- .../common/eager_transformer_wrapper.dart | 45 +++++++++++++++++++ .../lib/src/transform/common/options.dart | 11 +++++ .../src/transform/common/options_reader.dart | 2 + .../deferred_rewriter/transformer.dart | 7 ++- .../transformer.dart | 17 +++---- .../directive_processor/transformer.dart | 7 ++- .../reflection_remover/transformer.dart | 7 ++- .../stylesheet_compiler/transformer.dart | 20 ++++++++- .../template_compiler/transformer.dart | 8 +++- .../lib/src/transform/transformer.dart | 5 +++ 10 files changed, 115 insertions(+), 14 deletions(-) create mode 100644 modules_dart/transform/lib/src/transform/common/eager_transformer_wrapper.dart diff --git a/modules_dart/transform/lib/src/transform/common/eager_transformer_wrapper.dart b/modules_dart/transform/lib/src/transform/common/eager_transformer_wrapper.dart new file mode 100644 index 0000000000..96b7d17590 --- /dev/null +++ b/modules_dart/transform/lib/src/transform/common/eager_transformer_wrapper.dart @@ -0,0 +1,45 @@ +library angular2.src.transform.common.eager_transformer_wrapper; + +import 'package:barback/barback.dart'; + +abstract class EagerTransformerWrapper { + EagerTransformerWrapper._(); + factory EagerTransformerWrapper(wrapped) { + return wrapped is AggregateTransformer + ? new _EagerAggregateTransformerWrapper(wrapped) + : new _EagerTransformerWrapper(wrapped); + } +} + +class _EagerTransformerWrapper extends EagerTransformerWrapper + implements Transformer { + final Transformer _wrapped; + _EagerTransformerWrapper(this._wrapped) : super._(); + + @override + String get allowedExtensions => _wrapped.allowedExtensions; + + @override + apply(Transform transform) => _wrapped.apply(transform); + + @override + isPrimary(AssetId id) => _wrapped.isPrimary(id); + + @override + toString() => _wrapped.toString(); +} + +class _EagerAggregateTransformerWrapper extends EagerTransformerWrapper + implements AggregateTransformer { + final AggregateTransformer _wrapped; + _EagerAggregateTransformerWrapper(this._wrapped) : super._(); + + @override + apply(AggregateTransform transform) => _wrapped.apply(transform); + + @override + classifyPrimary(AssetId id) => _wrapped.classifyPrimary(id); + + @override + toString() => _wrapped.toString(); +} diff --git a/modules_dart/transform/lib/src/transform/common/options.dart b/modules_dart/transform/lib/src/transform/common/options.dart index f4c6ef8b08..f5d1e5038d 100644 --- a/modules_dart/transform/lib/src/transform/common/options.dart +++ b/modules_dart/transform/lib/src/transform/common/options.dart @@ -15,6 +15,7 @@ const PLATFORM_DIRECTIVES = 'platform_directives'; const INIT_REFLECTOR_PARAM = 'init_reflector'; const INLINE_VIEWS_PARAM = 'inline_views'; const MIRROR_MODE_PARAM = 'mirror_mode'; +const LAZY_TRANSFORMERS = 'lazy_transformers'; /// Provides information necessary to transform an Angular2 app. class TransformerOptions { @@ -56,6 +57,13 @@ class TransformerOptions { /// at any time. final bool inlineViews; + /// Whether to make transformers lazy. + /// If this is `true`, and in `debug` mode only, the transformers will be + /// lazy (will only build assets that are requested). + /// This is undocumented, for testing purposes only, and may change or break + /// at any time. + final bool lazyTransformers; + TransformerOptions._internal( this.entryPoints, this.entryPointGlobs, @@ -66,6 +74,7 @@ class TransformerOptions { {this.reflectPropertiesAsAttributes, this.platformDirectives, this.inlineViews, + this.lazyTransformers, this.formatCode}); factory TransformerOptions(List entryPoints, @@ -76,6 +85,7 @@ class TransformerOptions { bool inlineViews: false, bool reflectPropertiesAsAttributes: true, List platformDirectives, + bool lazyTransformers: false, bool formatCode: false}) { var annotationMatcher = new AnnotationMatcher() ..addAll(customAnnotationDescriptors); @@ -87,6 +97,7 @@ class TransformerOptions { reflectPropertiesAsAttributes: reflectPropertiesAsAttributes, platformDirectives: platformDirectives, inlineViews: inlineViews, + lazyTransformers: lazyTransformers, formatCode: formatCode); } } diff --git a/modules_dart/transform/lib/src/transform/common/options_reader.dart b/modules_dart/transform/lib/src/transform/common/options_reader.dart index 140431f2eb..18d8566a4a 100644 --- a/modules_dart/transform/lib/src/transform/common/options_reader.dart +++ b/modules_dart/transform/lib/src/transform/common/options_reader.dart @@ -42,6 +42,8 @@ TransformerOptions parseBarbackSettings(BarbackSettings settings) { reflectPropertiesAsAttributes: reflectPropertiesAsAttributes, platformDirectives: platformDirectives, inlineViews: _readBool(config, INLINE_VIEWS_PARAM, defaultValue: false), + lazyTransformers: + _readBool(config, LAZY_TRANSFORMERS, defaultValue: false), formatCode: formatCode); } diff --git a/modules_dart/transform/lib/src/transform/deferred_rewriter/transformer.dart b/modules_dart/transform/lib/src/transform/deferred_rewriter/transformer.dart index c5dc4fb725..8d1c0d844a 100644 --- a/modules_dart/transform/lib/src/transform/deferred_rewriter/transformer.dart +++ b/modules_dart/transform/lib/src/transform/deferred_rewriter/transformer.dart @@ -14,11 +14,16 @@ import 'rewriter.dart'; /// Transformer responsible for rewriting deferred library loads to enable /// initializing the reflector in a deferred way to keep the code with the /// deferred library. -class DeferredRewriter extends Transformer { +class DeferredRewriter extends Transformer implements LazyTransformer { final TransformerOptions options; DeferredRewriter(this.options); + @override + declareOutputs(DeclaringTransform transform) { + transform.declareOutput(transform.primaryId); + } + @override bool isPrimary(AssetId id) => id.extension.endsWith('dart') && _isNotGenerated(id); diff --git a/modules_dart/transform/lib/src/transform/directive_metadata_linker/transformer.dart b/modules_dart/transform/lib/src/transform/directive_metadata_linker/transformer.dart index 5270d588f1..6483ac23ed 100644 --- a/modules_dart/transform/lib/src/transform/directive_metadata_linker/transformer.dart +++ b/modules_dart/transform/lib/src/transform/directive_metadata_linker/transformer.dart @@ -30,12 +30,17 @@ import 'ng_meta_linker.dart'; /// /// This transformer is part of a multi-phase transform. /// See `angular2/src/transform/transformer.dart` for transformer ordering. -class DirectiveMetadataLinker extends Transformer { +class DirectiveMetadataLinker extends Transformer implements LazyTransformer { final _encoder = const JsonEncoder.withIndent(' '); @override bool isPrimary(AssetId id) => id.path.endsWith(SUMMARY_META_EXTENSION); + @override + declareOutputs(DeclaringTransform transform) { + transform.declareOutput(_ngLinkedAssetId(transform.primaryId)); + } + @override Future apply(Transform transform) { return zone.exec(() { @@ -45,13 +50,9 @@ class DirectiveMetadataLinker extends Transformer { new AssetReader.fromTransform(transform), primaryId).then((ngMeta) { if (ngMeta != null) { final outputId = _ngLinkedAssetId(primaryId); - if (!ngMeta.isEmpty) { - transform.addOutput(new Asset.fromString( - outputId, _encoder.convert(ngMeta.toJson()))); - } else { - // Not outputting an asset could confuse barback. - transform.addOutput(new Asset.fromString(outputId, '')); - } + // Not outputting an asset could confuse barback. + var output = ngMeta.isEmpty ? '' : _encoder.convert(ngMeta.toJson()); + transform.addOutput(new Asset.fromString(outputId, output)); } }); }, log: transform.logger); diff --git a/modules_dart/transform/lib/src/transform/directive_processor/transformer.dart b/modules_dart/transform/lib/src/transform/directive_processor/transformer.dart index de31b4ea24..d934d493af 100644 --- a/modules_dart/transform/lib/src/transform/directive_processor/transformer.dart +++ b/modules_dart/transform/lib/src/transform/directive_processor/transformer.dart @@ -21,7 +21,7 @@ import 'rewriter.dart'; /// /// This transformer is part of a multi-phase transform. /// See `angular2/src/transform/transformer.dart` for transformer ordering. -class DirectiveProcessor extends Transformer { +class DirectiveProcessor extends Transformer implements LazyTransformer { final TransformerOptions options; final _encoder = const JsonEncoder.withIndent(' '); @@ -30,6 +30,11 @@ class DirectiveProcessor extends Transformer { @override bool isPrimary(AssetId id) => id.extension.endsWith('dart'); + @override + declareOutputs(DeclaringTransform transform) { + transform.declareOutput(_ngSummaryAssetId(transform.primaryId)); + } + @override Future apply(Transform transform) async { Html5LibDomAdapter.makeCurrent(); diff --git a/modules_dart/transform/lib/src/transform/reflection_remover/transformer.dart b/modules_dart/transform/lib/src/transform/reflection_remover/transformer.dart index 2cde0b7e51..dc24d34eb6 100644 --- a/modules_dart/transform/lib/src/transform/reflection_remover/transformer.dart +++ b/modules_dart/transform/lib/src/transform/reflection_remover/transformer.dart @@ -21,7 +21,7 @@ import 'remove_reflection_capabilities.dart'; /// have already been run and that a .ng_deps.dart file has been generated for /// {@link options.entryPoint}. The instantiation of {@link ReflectionCapabilities} is /// replaced by calling `setupReflection` in that .ng_deps.dart file. -class ReflectionRemover extends Transformer { +class ReflectionRemover extends Transformer implements LazyTransformer { final TransformerOptions options; ReflectionRemover(this.options); @@ -30,6 +30,11 @@ class ReflectionRemover extends Transformer { bool isPrimary(AssetId id) => options.entryPointGlobs != null && options.entryPointGlobs.any((g) => g.matches(id.path)); + @override + declareOutputs(DeclaringTransform transform) { + transform.declareOutput(transform.primaryId); + } + @override Future apply(Transform transform) async { return zone.exec(() async { diff --git a/modules_dart/transform/lib/src/transform/stylesheet_compiler/transformer.dart b/modules_dart/transform/lib/src/transform/stylesheet_compiler/transformer.dart index ec52a41bd0..541f35dc9f 100644 --- a/modules_dart/transform/lib/src/transform/stylesheet_compiler/transformer.dart +++ b/modules_dart/transform/lib/src/transform/stylesheet_compiler/transformer.dart @@ -12,7 +12,7 @@ import 'package:angular2/src/transform/common/zone.dart' as zone; import 'processor.dart'; /// Pre-compiles CSS stylesheet files to Dart code for Angular 2. -class StylesheetCompiler extends Transformer { +class StylesheetCompiler extends Transformer implements LazyTransformer { StylesheetCompiler(); @override @@ -20,13 +20,29 @@ class StylesheetCompiler extends Transformer { return id.path.endsWith(CSS_EXTENSION); } + @override + declareOutputs(DeclaringTransform transform) { + // Note: we check this assumption below. + _getExpectedOutputs(transform.primaryId).forEach(transform.declareOutput); + } + + List _getExpectedOutputs(AssetId cssId) => + [shimmedStylesheetAssetId(cssId), nonShimmedStylesheetAssetId(cssId)]; + @override Future apply(Transform transform) async { final reader = new AssetReader.fromTransform(transform); return zone.exec(() async { Html5LibDomAdapter.makeCurrent(); - var outputs = await processStylesheet(reader, transform.primaryInput.id); + var primaryId = transform.primaryInput.id; + var outputs = await processStylesheet(reader, primaryId); + var expectedIds = _getExpectedOutputs(primaryId); outputs.forEach((Asset compiledStylesheet) { + var id = compiledStylesheet.id; + if (!expectedIds.contains(id)) { + throw new StateError( + 'Unexpected output for css processing of $primaryId: $id'); + } transform.addOutput(compiledStylesheet); }); }, log: transform.logger); diff --git a/modules_dart/transform/lib/src/transform/template_compiler/transformer.dart b/modules_dart/transform/lib/src/transform/template_compiler/transformer.dart index b2ee438233..b5069918c0 100644 --- a/modules_dart/transform/lib/src/transform/template_compiler/transformer.dart +++ b/modules_dart/transform/lib/src/transform/template_compiler/transformer.dart @@ -23,7 +23,7 @@ import 'generator.dart'; /// /// This transformer is part of a multi-phase transform. /// See `angular2/src/transform/transformer.dart` for transformer ordering. -class TemplateCompiler extends Transformer { +class TemplateCompiler extends Transformer implements LazyTransformer { final TransformerOptions options; TemplateCompiler(this.options); @@ -31,6 +31,12 @@ class TemplateCompiler extends Transformer { @override bool isPrimary(AssetId id) => id.path.endsWith(META_EXTENSION); + @override + declareOutputs(DeclaringTransform transform) { + transform.declareOutput(ngDepsAssetId(transform.primaryId)); + transform.declareOutput(templatesAssetId(transform.primaryId)); + } + @override Future apply(Transform transform) async { return zone.exec(() async { diff --git a/modules_dart/transform/lib/src/transform/transformer.dart b/modules_dart/transform/lib/src/transform/transformer.dart index a23d168677..4843c0075d 100644 --- a/modules_dart/transform/lib/src/transform/transformer.dart +++ b/modules_dart/transform/lib/src/transform/transformer.dart @@ -3,6 +3,7 @@ library angular2.src.transform.transformer; import 'package:barback/barback.dart'; import 'package:dart_style/dart_style.dart'; +import 'common/eager_transformer_wrapper.dart'; import 'common/formatter.dart' as formatter; import 'common/options.dart'; import 'common/options_reader.dart'; @@ -42,6 +43,10 @@ class AngularTransformerGroup extends TransformerGroup { ], ]; } + if (options.modeName == BarbackMode.RELEASE || !options.lazyTransformers) { + phases = phases + .map((phase) => phase.map((t) => new EagerTransformerWrapper(t))); + } return new AngularTransformerGroup._(phases, formatCode: options.formatCode); }