feat(transformers): provide a flag to disable inlining views

Add a flag to allow a user to disable inlining css/html content into the views.

Closes #2658
This commit is contained in:
Ted Sander 2015-06-20 18:09:23 -07:00 committed by Tobias Bosch
parent 34eaf65a79
commit dcdd73065a
12 changed files with 121 additions and 34 deletions

View File

@ -10,6 +10,7 @@ const CUSTOM_ANNOTATIONS_PARAM = 'custom_annotations';
const ENTRY_POINT_PARAM = 'entry_points'; const ENTRY_POINT_PARAM = 'entry_points';
const GENERATE_CHANGE_DETECTORS_PARAM = 'generate_change_detectors'; const GENERATE_CHANGE_DETECTORS_PARAM = 'generate_change_detectors';
const INIT_REFLECTOR_PARAM = 'init_reflector'; const INIT_REFLECTOR_PARAM = 'init_reflector';
const INLINE_VIEWS_PARAM = 'inline_views';
const MIRROR_MODE_PARAM = 'mirror_mode'; const MIRROR_MODE_PARAM = 'mirror_mode';
const OPTIMIZATION_PHASES_PARAM = 'optimization_phases'; const OPTIMIZATION_PHASES_PARAM = 'optimization_phases';
const REFLECTION_ENTRY_POINT_PARAM = 'reflection_entry_points'; const REFLECTION_ENTRY_POINT_PARAM = 'reflection_entry_points';
@ -32,6 +33,9 @@ class TransformerOptions {
/// Whether to generate calls to our generated `initReflector` code /// Whether to generate calls to our generated `initReflector` code
final bool initReflector; final bool initReflector;
/// Whether to inline html/css urls into the View directive
final bool inlineViews;
/// The [AnnotationMatcher] which is used to identify angular annotations. /// The [AnnotationMatcher] which is used to identify angular annotations.
final AnnotationMatcher annotationMatcher; final AnnotationMatcher annotationMatcher;
@ -50,13 +54,14 @@ class TransformerOptions {
TransformerOptions._internal(this.entryPoints, this.reflectionEntryPoints, TransformerOptions._internal(this.entryPoints, this.reflectionEntryPoints,
this.modeName, this.mirrorMode, this.initReflector, this.modeName, this.mirrorMode, this.initReflector,
this.annotationMatcher, this.optimizationPhases, this.annotationMatcher, this.optimizationPhases,
this.generateChangeDetectors); this.generateChangeDetectors, this.inlineViews);
factory TransformerOptions(List<String> entryPoints, factory TransformerOptions(List<String> entryPoints,
{List<String> reflectionEntryPoints, String modeName: 'release', {List<String> reflectionEntryPoints, String modeName: 'release',
MirrorMode mirrorMode: MirrorMode.none, bool initReflector: true, MirrorMode mirrorMode: MirrorMode.none, bool initReflector: true,
List<AnnotationDescriptor> customAnnotationDescriptors: const [], List<AnnotationDescriptor> customAnnotationDescriptors: const [],
int optimizationPhases: DEFAULT_OPTIMIZATION_PHASES, int optimizationPhases: DEFAULT_OPTIMIZATION_PHASES,
bool inlineViews: true,
bool generateChangeDetectors: true}) { bool generateChangeDetectors: true}) {
if (reflectionEntryPoints == null || reflectionEntryPoints.isEmpty) { if (reflectionEntryPoints == null || reflectionEntryPoints.isEmpty) {
reflectionEntryPoints = entryPoints; reflectionEntryPoints = entryPoints;
@ -66,6 +71,6 @@ class TransformerOptions {
optimizationPhases = optimizationPhases.isNegative ? 0 : optimizationPhases; optimizationPhases = optimizationPhases.isNegative ? 0 : optimizationPhases;
return new TransformerOptions._internal(entryPoints, reflectionEntryPoints, return new TransformerOptions._internal(entryPoints, reflectionEntryPoints,
modeName, mirrorMode, initReflector, annotationMatcher, modeName, mirrorMode, initReflector, annotationMatcher,
optimizationPhases, generateChangeDetectors); optimizationPhases, generateChangeDetectors, inlineViews);
} }
} }

View File

@ -12,6 +12,7 @@ TransformerOptions parseBarbackSettings(BarbackSettings settings) {
_readFileList(config, REFLECTION_ENTRY_POINT_PARAM); _readFileList(config, REFLECTION_ENTRY_POINT_PARAM);
var initReflector = var initReflector =
_readBool(config, INIT_REFLECTOR_PARAM, defaultValue: true); _readBool(config, INIT_REFLECTOR_PARAM, defaultValue: true);
var inlineViews = _readBool(config, INLINE_VIEWS_PARAM, defaultValue: true);
var generateChangeDetectors = var generateChangeDetectors =
_readBool(config, GENERATE_CHANGE_DETECTORS_PARAM, defaultValue: true); _readBool(config, GENERATE_CHANGE_DETECTORS_PARAM, defaultValue: true);
String mirrorModeVal = String mirrorModeVal =
@ -35,6 +36,7 @@ TransformerOptions parseBarbackSettings(BarbackSettings settings) {
modeName: settings.mode.name, modeName: settings.mode.name,
mirrorMode: mirrorMode, mirrorMode: mirrorMode,
initReflector: initReflector, initReflector: initReflector,
inlineViews: inlineViews,
customAnnotationDescriptors: _readCustomAnnotations(config), customAnnotationDescriptors: _readCustomAnnotations(config),
optimizationPhases: optimizationPhases, optimizationPhases: optimizationPhases,
generateChangeDetectors: generateChangeDetectors); generateChangeDetectors: generateChangeDetectors);

View File

@ -23,12 +23,12 @@ import 'visitors.dart';
/// string unless `forceGenerate` is true, in which case an empty ngDeps /// string unless `forceGenerate` is true, in which case an empty ngDeps
/// file is created. /// file is created.
Future<String> createNgDeps(AssetReader reader, AssetId assetId, Future<String> createNgDeps(AssetReader reader, AssetId assetId,
AnnotationMatcher annotationMatcher) async { AnnotationMatcher annotationMatcher, bool inlineViews) async {
// TODO(kegluneq): Shortcut if we can determine that there are no // TODO(kegluneq): Shortcut if we can determine that there are no
// [Directive]s present, taking into account `export`s. // [Directive]s present, taking into account `export`s.
var writer = new AsyncStringWriter(); var writer = new AsyncStringWriter();
var visitor = new CreateNgDepsVisitor( var visitor = new CreateNgDepsVisitor(writer, assetId,
writer, assetId, new XhrImpl(reader, assetId), annotationMatcher); new XhrImpl(reader, assetId), annotationMatcher, inlineViews);
var code = await reader.readAsString(assetId); var code = await reader.readAsString(assetId);
parseCompilationUnit(code, name: assetId.path).accept(visitor); parseCompilationUnit(code, name: assetId.path).accept(visitor);
@ -60,13 +60,14 @@ class CreateNgDepsVisitor extends Object with SimpleAstVisitor<Object> {
/// The assetId for the file which we are parsing. /// The assetId for the file which we are parsing.
final AssetId assetId; final AssetId assetId;
CreateNgDepsVisitor( CreateNgDepsVisitor(AsyncStringWriter writer, this.assetId, XHR xhr,
AsyncStringWriter writer, this.assetId, XHR xhr, this._annotationMatcher) this._annotationMatcher, inlineViews)
: writer = writer, : writer = writer,
_copyVisitor = new ToSourceVisitor(writer), _copyVisitor = new ToSourceVisitor(writer),
_factoryVisitor = new FactoryTransformVisitor(writer), _factoryVisitor = new FactoryTransformVisitor(writer),
_paramsVisitor = new ParameterTransformVisitor(writer), _paramsVisitor = new ParameterTransformVisitor(writer),
_metaVisitor = new AnnotationsTransformVisitor(writer, xhr); _metaVisitor = new AnnotationsTransformVisitor(
writer, xhr, inlineViews);
void _visitNodeListWithSeparator(NodeList<AstNode> list, String separator) { void _visitNodeListWithSeparator(NodeList<AstNode> list, String separator) {
if (list == null) return; if (list == null) return;

View File

@ -34,8 +34,8 @@ class DirectiveProcessor extends Transformer {
try { try {
var asset = transform.primaryInput; var asset = transform.primaryInput;
var reader = new AssetReader.fromTransform(transform); var reader = new AssetReader.fromTransform(transform);
var ngDepsSrc = var ngDepsSrc = await createNgDeps(
await createNgDeps(reader, asset.id, options.annotationMatcher); reader, asset.id, options.annotationMatcher, options.inlineViews);
if (ngDepsSrc != null && ngDepsSrc.isNotEmpty) { if (ngDepsSrc != null && ngDepsSrc.isNotEmpty) {
var ngDepsAssetId = var ngDepsAssetId =
transform.primaryInput.id.changeExtension(DEPS_EXTENSION); transform.primaryInput.id.changeExtension(DEPS_EXTENSION);

View File

@ -211,10 +211,12 @@ bool _isViewAnnotation(Annotation node) => '${node.name}' == 'View';
class AnnotationsTransformVisitor extends ToSourceVisitor { class AnnotationsTransformVisitor extends ToSourceVisitor {
final AsyncStringWriter writer; final AsyncStringWriter writer;
final XHR _xhr; final XHR _xhr;
final bool _inlineViews;
final ConstantEvaluator _evaluator = new ConstantEvaluator(); final ConstantEvaluator _evaluator = new ConstantEvaluator();
bool _processingView = false; bool _processingView = false;
AnnotationsTransformVisitor(AsyncStringWriter writer, this._xhr) AnnotationsTransformVisitor(
AsyncStringWriter writer, this._xhr, this._inlineViews)
: this.writer = writer, : this.writer = writer,
super(writer); super(writer);
@ -259,6 +261,7 @@ class AnnotationsTransformVisitor extends ToSourceVisitor {
return super.visitNamedExpression(node); return super.visitNamedExpression(node);
} }
var keyString = '${node.name.label}'; var keyString = '${node.name.label}';
if (_inlineViews) {
if (keyString == 'templateUrl') { if (keyString == 'templateUrl') {
// Inline the templateUrl // Inline the templateUrl
var url = node.expression.accept(_evaluator); var url = node.expression.accept(_evaluator);
@ -286,6 +289,7 @@ class AnnotationsTransformVisitor extends ToSourceVisitor {
writer.print(']'); writer.print(']');
return null; return null;
} }
}
return super.visitNamedExpression(node); return super.visitNamedExpression(node);
} }

View File

@ -58,6 +58,17 @@ void allTests() {
'should inline multiple `styleUrls` values expressed as absolute urls.', 'should inline multiple `styleUrls` values expressed as absolute urls.',
'multiple_style_urls_files/hello.dart'); 'multiple_style_urls_files/hello.dart');
absoluteReader.addAsset(new AssetId('a', 'lib/template.html'),
readFile('directive_processor/multiple_style_urls_files/template.html'));
absoluteReader.addAsset(new AssetId('a', 'lib/template.css'),
readFile('directive_processor/multiple_style_urls_files/template.css'));
absoluteReader.addAsset(new AssetId('a', 'lib/template_other.css'), readFile(
'directive_processor/multiple_style_urls_files/template_other.css'));
_testNgDeps(
'shouldn\'t inline multiple `styleUrls` values expressed as absolute '
'urls.', 'multiple_style_urls_not_inlined_files/hello.dart',
inlineViews: false, reader: absoluteReader);
_testNgDeps('should inline `templateUrl`s expressed as adjacent strings.', _testNgDeps('should inline `templateUrl`s expressed as adjacent strings.',
'split_url_expression_files/hello.dart'); 'split_url_expression_files/hello.dart');
@ -86,7 +97,7 @@ void allTests() {
void _testNgDeps(String name, String inputPath, void _testNgDeps(String name, String inputPath,
{List<AnnotationDescriptor> customDescriptors: const [], AssetId assetId, {List<AnnotationDescriptor> customDescriptors: const [], AssetId assetId,
AssetReader reader, List<String> expectedLogs}) { AssetReader reader, List<String> expectedLogs, bool inlineViews: true}) {
it(name, () async { it(name, () async {
if (expectedLogs != null) { if (expectedLogs != null) {
log.setLogger(new RecordingLogger()); log.setLogger(new RecordingLogger());
@ -105,7 +116,8 @@ void _testNgDeps(String name, String inputPath,
var expectedId = _assetIdForPath(expectedPath); var expectedId = _assetIdForPath(expectedPath);
var annotationMatcher = new AnnotationMatcher()..addAll(customDescriptors); var annotationMatcher = new AnnotationMatcher()..addAll(customDescriptors);
var output = await createNgDeps(reader, inputId, annotationMatcher); var output =
await createNgDeps(reader, inputId, annotationMatcher, inlineViews);
if (output == null) { if (output == null) {
expect(await reader.hasInput(expectedId)).toBeFalse(); expect(await reader.hasInput(expectedId)).toBeFalse();
} else { } else {

View File

@ -0,0 +1,25 @@
library examples.src.hello_world.index_common_dart.ng_deps.dart;
import 'hello.dart';
import 'package:angular2/angular2.dart'
show bootstrap, Component, Directive, View, NgElement;
var _visited = false;
void initReflector(reflector) {
if (_visited) return;
_visited = true;
reflector
..registerType(HelloCmp, {
'factory': () => new HelloCmp(),
'parameters': const [],
'annotations': const [
const Component(selector: 'hello-app'),
const View(
template: r'''{{greeting}}''',
styles: const [
r'''.greeting { .color: blue; }''',
r'''.hello { .color: red; }''',
])
]
});
}

View File

@ -0,0 +1,25 @@
library examples.src.hello_world.index_common_dart.ng_deps.dart;
import 'hello.dart';
import 'package:angular2/angular2.dart'
show bootstrap, Component, Directive, View, NgElement;
var _visited = false;
void initReflector(reflector) {
if (_visited) return;
_visited = true;
reflector
..registerType(HelloCmp, {
'factory': () => new HelloCmp(),
'parameters': const [],
'annotations': const [
const Component(selector: 'hello-app'),
const View(
templateUrl: 'package:a/template.html',
styleUrls: const [
'package:a/template.css',
'package:a/template_other.css'
])
]
});
}

View File

@ -0,0 +1,10 @@
library examples.src.hello_world.index_common_dart;
import 'package:angular2/angular2.dart'
show bootstrap, Component, Directive, View, NgElement;
@Component(selector: 'hello-app')
@View(
templateUrl: 'package:a/template.html',
styleUrls: const ['package:a/template.css', 'package:a/template_other.css'])
class HelloCmp {}

View File

@ -0,0 +1 @@
.greeting { .color: blue; }