perf(core): add option to remove blank text nodes from compiled templates

This commit is contained in:
Pawel Kozlowski
2017-07-28 15:58:28 +02:00
committed by Hans
parent 088532bf2e
commit d2c0d986d4
27 changed files with 450 additions and 46 deletions

View File

@ -5,7 +5,7 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {CompileQueryMetadata, CompilerConfig, JitReflector, ProxyClass, StaticSymbol} from '@angular/compiler';
import {CompileQueryMetadata, CompilerConfig, JitReflector, ProxyClass, StaticSymbol, preserveWhitespacesDefault} from '@angular/compiler';
import {CompileAnimationEntryMetadata, CompileDiDependencyMetadata, CompileDirectiveMetadata, CompileDirectiveSummary, CompilePipeMetadata, CompilePipeSummary, CompileProviderMetadata, CompileTemplateMetadata, CompileTokenMetadata, CompileTypeMetadata, tokenReference} from '@angular/compiler/src/compile_metadata';
import {DomElementSchemaRegistry} from '@angular/compiler/src/schema/dom_element_schema_registry';
import {ElementSchemaRegistry} from '@angular/compiler/src/schema/element_schema_registry';
@ -84,7 +84,7 @@ function compileDirectiveMetadataCreate(
function compileTemplateMetadata({encapsulation, template, templateUrl, styles, styleUrls,
externalStylesheets, animations, ngContentSelectors,
interpolation, isInline}: {
interpolation, isInline, preserveWhitespaces}: {
encapsulation?: ViewEncapsulation | null,
template?: string | null,
templateUrl?: string | null,
@ -94,7 +94,8 @@ function compileTemplateMetadata({encapsulation, template, templateUrl, styles,
ngContentSelectors?: string[],
animations?: any[],
interpolation?: [string, string] | null,
isInline?: boolean
isInline?: boolean,
preserveWhitespaces?: boolean | null,
}): CompileTemplateMetadata {
return new CompileTemplateMetadata({
encapsulation: noUndefined(encapsulation),
@ -106,7 +107,8 @@ function compileTemplateMetadata({encapsulation, template, templateUrl, styles,
animations: animations || [],
ngContentSelectors: ngContentSelectors || [],
interpolation: noUndefined(interpolation),
isInline: !!isInline
isInline: !!isInline,
preserveWhitespaces: preserveWhitespacesDefault(noUndefined(preserveWhitespaces)),
});
}
@ -116,7 +118,7 @@ export function main() {
let ngIf: CompileDirectiveSummary;
let parse: (
template: string, directives: CompileDirectiveSummary[], pipes?: CompilePipeSummary[],
schemas?: SchemaMetadata[]) => TemplateAst[];
schemas?: SchemaMetadata[], preserveWhitespaces?: boolean) => TemplateAst[];
let console: ArrayConsole;
function commonBeforeEach() {
@ -148,12 +150,15 @@ export function main() {
parse =
(template: string, directives: CompileDirectiveSummary[],
pipes: CompilePipeSummary[] | null = null,
schemas: SchemaMetadata[] = []): TemplateAst[] => {
pipes: CompilePipeSummary[] | null = null, schemas: SchemaMetadata[] = [],
preserveWhitespaces = true): TemplateAst[] => {
if (pipes === null) {
pipes = [];
}
return parser.parse(component, template, directives, pipes, schemas, 'TestComp')
return parser
.parse(
component, template, directives, pipes, schemas, 'TestComp',
preserveWhitespaces)
.template;
};
}));
@ -398,7 +403,8 @@ export function main() {
externalStylesheets: [],
styleUrls: [],
styles: [],
encapsulation: null
encapsulation: null,
preserveWhitespaces: preserveWhitespacesDefault(null),
}),
isHost: false,
exportAs: null,
@ -417,7 +423,7 @@ export function main() {
});
expect(humanizeTplAst(
parser.parse(component, '{%a%}', [], [], [], 'TestComp').template,
parser.parse(component, '{%a%}', [], [], [], 'TestComp', true).template,
{start: '{%', end: '%}'}))
.toEqual([[BoundTextAst, '{% a %}']]);
}));
@ -2052,6 +2058,48 @@ The pipe 'test' could not be found ("{{[ERROR ->]a | test}}"): TestComp@0:2`);
});
});
describe('whitespaces removal', () => {
it('should not remove whitespaces by default', () => {
expect(humanizeTplAst(parse(' <br> <br>\t<br>\n<br> ', []))).toEqual([
[TextAst, ' '],
[ElementAst, 'br'],
[TextAst, ' '],
[ElementAst, 'br'],
[TextAst, '\t'],
[ElementAst, 'br'],
[TextAst, '\n'],
[ElementAst, 'br'],
[TextAst, ' '],
]);
});
it('should remove whitespaces when explicitly requested', () => {
expect(humanizeTplAst(parse(' <br> <br>\t<br>\n<br> ', [], [], [], false))).toEqual([
[ElementAst, 'br'],
[ElementAst, 'br'],
[ElementAst, 'br'],
[ElementAst, 'br'],
]);
});
it('should remove whitespace between ICU expansions when not preserving whitespaces', () => {
const shortForm = '{ count, plural, =0 {small} many {big} }';
const expandedForm = '<ng-container [ngPlural]="count">' +
'<ng-template ngPluralCase="=0">small</ng-template>' +
'<ng-template ngPluralCase="many">big</ng-template>' +
'</ng-container>';
const humanizedExpandedForm = humanizeTplAst(parse(expandedForm, []));
// ICU expansions are converted to `<ng-container>` tags and all blank text nodes are reomved
// so any whitespace between ICU exansions are removed as well
expect(humanizeTplAst(parse(`${shortForm} ${shortForm}`, [], [], [], false))).toEqual([
...humanizedExpandedForm, ...humanizedExpandedForm
]);
});
});
describe('Template Parser - opt-out `<template>` support', () => {
beforeEach(() => {
TestBed.configureCompiler({