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:
parent
34eaf65a79
commit
dcdd73065a
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,32 +261,34 @@ class AnnotationsTransformVisitor extends ToSourceVisitor {
|
||||||
return super.visitNamedExpression(node);
|
return super.visitNamedExpression(node);
|
||||||
}
|
}
|
||||||
var keyString = '${node.name.label}';
|
var keyString = '${node.name.label}';
|
||||||
if (keyString == 'templateUrl') {
|
if (_inlineViews) {
|
||||||
// Inline the templateUrl
|
if (keyString == 'templateUrl') {
|
||||||
var url = node.expression.accept(_evaluator);
|
// Inline the templateUrl
|
||||||
if (url is String) {
|
var url = node.expression.accept(_evaluator);
|
||||||
writer.print("template: r'''");
|
|
||||||
writer.asyncPrint(_readOrEmptyString(url));
|
|
||||||
writer.print("'''");
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
logger.warning('template url is not a String $url');
|
|
||||||
}
|
|
||||||
} else if (keyString == 'styleUrls') {
|
|
||||||
// Inline the styleUrls
|
|
||||||
var urls = node.expression.accept(_evaluator);
|
|
||||||
writer.print('styles: const [');
|
|
||||||
for (var url in urls) {
|
|
||||||
if (url is String) {
|
if (url is String) {
|
||||||
writer.print("r'''");
|
writer.print("template: r'''");
|
||||||
writer.asyncPrint(_readOrEmptyString(url));
|
writer.asyncPrint(_readOrEmptyString(url));
|
||||||
writer.print("''', ");
|
writer.print("'''");
|
||||||
|
return null;
|
||||||
} else {
|
} else {
|
||||||
logger.warning('style url is not a String ${url}');
|
logger.warning('template url is not a String $url');
|
||||||
}
|
}
|
||||||
|
} else if (keyString == 'styleUrls') {
|
||||||
|
// Inline the styleUrls
|
||||||
|
var urls = node.expression.accept(_evaluator);
|
||||||
|
writer.print('styles: const [');
|
||||||
|
for (var url in urls) {
|
||||||
|
if (url is String) {
|
||||||
|
writer.print("r'''");
|
||||||
|
writer.asyncPrint(_readOrEmptyString(url));
|
||||||
|
writer.print("''', ");
|
||||||
|
} else {
|
||||||
|
logger.warning('style url is not a String ${url}');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writer.print(']');
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
writer.print(']');
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
return super.visitNamedExpression(node);
|
return super.visitNamedExpression(node);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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; }''',
|
||||||
|
])
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
|
@ -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'
|
||||||
|
])
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
|
@ -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 {}
|
|
@ -0,0 +1 @@
|
||||||
|
.greeting { .color: blue; }
|
|
@ -0,0 +1 @@
|
||||||
|
{{greeting}}
|
|
@ -0,0 +1 @@
|
||||||
|
.hello { .color: red; }
|
Loading…
Reference in New Issue