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

PR Close #18823
This commit is contained in:
Pawel Kozlowski
2017-07-28 15:58:28 +02:00
committed by Miško Hevery
parent 7ec28fe9af
commit b8b551cf2b
29 changed files with 536 additions and 48 deletions

View File

@ -106,6 +106,7 @@ export type CompilerOptions = {
// Whether to support the `<template>` tag and the `template` attribute to define angular
// templates. They have been deprecated in 4.x, `<ng-template>` should be used instead.
enableLegacyTemplate?: boolean,
preserveWhitespaces?: boolean,
};
/**

View File

@ -676,6 +676,74 @@ export interface Component extends Directive {
* {@link ComponentFactoryResolver}.
*/
entryComponents?: Array<Type<any>|any[]>;
/**
* If {@link Component#preserveWhitespaces Component.preserveWhitespaces} is set to `false`
* potentially superfluous whitespace characters (ones matching the `\s` character class in
* JavaScript regular expressions) will be removed from a compiled template. This can greatly
* reduce AOT-generated code size as well as speed up view creation.
*
* Current implementation works according to the following rules:
* - all whitespaces at the beginning and the end of a template are removed (trimmed);
* - text nodes consisting of whitespaces only are removed (ex.:
* `<button>Action 1</button> <button>Action 2</button>` will be converted to
* `<button>Action 1</button><button>Action 2</button>` (no whitespaces between buttons);
* - series of whitespaces in text nodes are replaced with one space (ex.:
* `<span>\n some text\n</span>` will be converted to `<span> some text </span>`);
* - text nodes are left as-is inside HTML tags where whitespaces are significant (ex. `<pre>`,
* `<textarea>`).
*
* Described transformations can (potentially) influence DOM nodes layout so the
* `preserveWhitespaces` option is `true` be default (no whitespace removal).
* In Angular 5 you need to opt-in for whitespace removal (but we might revisit the default
* setting in Angular 6 or later). If you want to change the default setting for all components
* in your application you can use the `preserveWhitespaces` option of the AOT compiler.
*
* Even if you decide to opt-in for whitespace removal there are ways of preserving whitespaces
* in certain fragments of a template. You can either exclude entire DOM sub-tree by using the
* `ngPreserveWhitespaces` attribute, ex.:
*
* ```html
* <div ngPreserveWhitespaces>
* whitespaces are preserved here
* <span> and here </span>
* </div>
* ```
*
* Alternatively you can force a space to be preserved in a text node by using the `&ngsp;`
* pseudo-entity. `&ngsp;` will be replaced with a space character by Angular's template
* compiler, ex.:
*
* ```html
* <a>Spaces</a>&ngsp;<a>between</a>&ngsp;<a>links.</a>
* ```
*
* will be compiled to the equivalent of:
*
* ```html
* <a>Spaces</a> <a>between</a> <a>links.</a>
* ```
*
* Please note that sequences of `&ngsp;` are still collapsed to just one space character when
* the `preserveWhitespaces` option is set to `false`. Ex.:
*
* ```html
* <a>before</a>&ngsp;&ngsp;&ngsp;<a>after</a>
* ```
*
* would be equivalent to:
*
* ```html
* <a>before</a> <a>after</a>
* ```
*
* The `&ngsp;` pseudo-entity is useful for forcing presence of
* one space (a text node having `&ngsp;` pseudo-entities will never be removed), but it is not
* meant to mark sequences of whitespace characters. The previously described
* `ngPreserveWhitespaces` attribute is more useful for preserving sequences of whitespace
* characters.
*/
preserveWhitespaces?: boolean;
}
/**

View File

@ -1772,6 +1772,51 @@ function declareTests({useJit}: {useJit: boolean}) {
});
});
describe('whitespaces in templates', () => {
it('should not remove whitespaces by default', async(() => {
@Component({
selector: 'comp',
template: '<span>foo</span> <span>bar</span>',
})
class MyCmp {
}
const f = TestBed.configureTestingModule({declarations: [MyCmp]}).createComponent(MyCmp);
f.detectChanges();
expect(f.nativeElement.childNodes.length).toBe(3);
}));
it('should not remove whitespaces when explicitly requested not to do so', async(() => {
@Component({
selector: 'comp',
template: '<span>foo</span> <span>bar</span>',
preserveWhitespaces: true,
})
class MyCmp {
}
const f = TestBed.configureTestingModule({declarations: [MyCmp]}).createComponent(MyCmp);
f.detectChanges();
expect(f.nativeElement.childNodes.length).toBe(3);
}));
it('should remove whitespaces when explicitly requested to do so', async(() => {
@Component({
selector: 'comp',
template: '<span>foo</span> <span>bar</span>',
preserveWhitespaces: false,
})
class MyCmp {
}
const f = TestBed.configureTestingModule({declarations: [MyCmp]}).createComponent(MyCmp);
f.detectChanges();
expect(f.nativeElement.childNodes.length).toBe(2);
}));
});
if (getDOM().supportsDOMEvents()) {
describe('svg', () => {