diff --git a/modules_dart/transform/lib/src/transform/common/names.dart b/modules_dart/transform/lib/src/transform/common/names.dart index 3a06b076fc..db5e8ffe25 100644 --- a/modules_dart/transform/lib/src/transform/common/names.dart +++ b/modules_dart/transform/lib/src/transform/common/names.dart @@ -6,6 +6,7 @@ const SETUP_METHOD_NAME = 'initReflector'; const REFLECTOR_VAR_NAME = 'reflector'; const TRANSFORM_DYNAMIC_MODE = 'transform_dynamic'; const CSS_EXTENSION = '.css'; +const DEFERRED_EXTENSION = '.dart.deferredCount'; const SHIMMED_STYLESHEET_EXTENSION = '.css.shim.dart'; const NON_SHIMMED_STYLESHEET_EXTENSION = '.css.dart'; const META_EXTENSION = '.ng_meta.json'; @@ -21,8 +22,10 @@ const TEMPLATE_EXTENSION = '.template.dart'; /// Note that due to the implementation of `_toExtension`, ordering is /// important. For example, putting '.dart' first in this list will cause -/// incorrect behavior. +/// incorrect behavior because it will (incompletely) match '.template.dart' +/// files. const ALL_EXTENSIONS = const [ + DEFERRED_EXTENSION, META_EXTENSION, SUMMARY_META_EXTENSION, TEMPLATE_EXTENSION, @@ -36,6 +39,7 @@ const ALL_EXTENSIONS = const [ /// any files named like transformer outputs will be reported as generated. bool isGenerated(String uri) { return const [ + DEFERRED_EXTENSION, META_EXTENSION, NON_SHIMMED_STYLESHEET_EXTENSION, SHIMMED_STYLESHEET_EXTENSION, @@ -44,6 +48,10 @@ bool isGenerated(String uri) { ].any((ext) => uri.endsWith(ext)); } +/// Returns `uri` with its extension updated to [DEFERRED_EXTENSION]. +String toDeferredExtension(String uri) => + _toExtension(uri, ALL_EXTENSIONS, DEFERRED_EXTENSION); + /// Returns `uri` with its extension updated to [META_EXTENSION]. String toMetaExtension(String uri) => _toExtension(uri, ALL_EXTENSIONS, META_EXTENSION); 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 8d1c0d844a..6b57fcc35c 100644 --- a/modules_dart/transform/lib/src/transform/deferred_rewriter/transformer.dart +++ b/modules_dart/transform/lib/src/transform/deferred_rewriter/transformer.dart @@ -14,7 +14,7 @@ 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 implements LazyTransformer { +class DeferredRewriter extends AggregateTransformer implements LazyTransformer { final TransformerOptions options; DeferredRewriter(this.options); @@ -25,23 +25,60 @@ class DeferredRewriter extends Transformer implements LazyTransformer { } @override - bool isPrimary(AssetId id) => - id.extension.endsWith('dart') && _isNotGenerated(id); + dynamic classifyPrimary(AssetId id) { + // Map .dart and .dart.deferredCount => . + // Anything else to `null`. + var extension = null; + if (id.path.endsWith(DEFERRED_EXTENSION)) { + extension = DEFERRED_EXTENSION; + } else if (id.path.endsWith('.dart') && !isGenerated(id.path)) { + extension = '.dart'; + } else { + return null; + } + return id.path.substring(0, id.path.length - extension.length); + } @override - Future apply(Transform transform) async { + Future apply(AggregateTransform transform) async { return zone.exec(() async { - var asset = transform.primaryInput; - var reader = new AssetReader.fromTransform(transform); - var transformedCode = await rewriteDeferredLibraries(reader, asset.id); + final dartAsset = await _assetToProcess(transform); + if (dartAsset == null) return; + + var transformedCode = await rewriteDeferredLibraries( + new AssetReader.fromTransform(transform), dartAsset.id); if (transformedCode != null) { - transform.addOutput(new Asset.fromString(asset.id, transformedCode)); + transform + .addOutput(new Asset.fromString(dartAsset.id, transformedCode)); } }, log: transform.logger); } -} -bool _isNotGenerated(AssetId id) => !isGenerated(id.path); + /// Returns the asset we need to process or `null` if none exists. + /// + /// Consumes the .dart.deferredCount asset if it is present. + Future _assetToProcess(AggregateTransform transform) async { + // We only need to process .dart files that have an associated + // .dart.deferredCount file with a value != "0". + // + // The .dart.deferredCount file is generated by a previous phase for files + // which have deferred imports. An absent .dart.deferredCount asset is the + // treated the same as a .dart.deferredCount asset with value "0". + var dartAsset, deferredCountAsset; + await for (Asset a in transform.primaryInputs) { + if (a.id.path.endsWith(DEFERRED_EXTENSION)) { + deferredCountAsset = a; + } else if (a.id.path.endsWith('.dart')) { + dartAsset = a; + } + } + if (deferredCountAsset == null) return null; + // No longer necessary. + transform.consumePrimary(deferredCountAsset.id); + if ((await deferredCountAsset.readAsString()) == "0") return null; + return dartAsset; + } +} // Visible for testing Future rewriteDeferredLibraries(AssetReader reader, AssetId id) async { 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 a3eda41a27..89f8451c1b 100644 --- a/modules_dart/transform/lib/src/transform/directive_processor/transformer.dart +++ b/modules_dart/transform/lib/src/transform/directive_processor/transformer.dart @@ -33,6 +33,7 @@ class DirectiveProcessor extends Transformer implements LazyTransformer { @override declareOutputs(DeclaringTransform transform) { + transform.declareOutput(_deferredAssetId(transform.primaryId)); transform.declareOutput(_ngSummaryAssetId(transform.primaryId)); } @@ -49,6 +50,17 @@ class DirectiveProcessor extends Transformer implements LazyTransformer { } transform.addOutput(new Asset.fromString( _ngSummaryAssetId(primaryId), _encoder.convert(ngMeta.toJson()))); + + var deferredCount = 0; + if (ngMeta.ngDeps != null) { + deferredCount = ngMeta.ngDeps.imports.where((i) => i.isDeferred).length; + } + if (deferredCount > 0) { + // The existence of this file with the value != "0" signals + // DeferredRewriter that the associated .dart file needs attention. + transform.addOutput(new Asset.fromString( + _deferredAssetId(primaryId), deferredCount.toString())); + } }, log: transform.logger); } } @@ -57,3 +69,8 @@ AssetId _ngSummaryAssetId(AssetId primaryInputId) { return new AssetId( primaryInputId.package, toSummaryExtension(primaryInputId.path)); } + +AssetId _deferredAssetId(AssetId primaryInputId) { + return new AssetId( + primaryInputId.package, toDeferredExtension(primaryInputId.path)); +}