feat(compiler): set `enableLegacyTemplate` to false by default (#18756)

BREAKING CHANGE: the compiler option `enableLegacyTemplate` is now disabled by default as the `<template>` element has been deprecated since v4. Use `<ng-template>` instead. The option `enableLegacyTemplate` and the `<template>` element will both be removed in Angular v6.
PR Close #18756
This commit is contained in:
Olivier Combe 2017-08-17 17:18:33 +02:00 committed by Jason Aden
parent fcadeb2079
commit 56238fe94e
22 changed files with 49 additions and 82 deletions

View File

@ -92,22 +92,22 @@
</div>
<div>
The <code>hero.id</code> in the &lt;template *ngIf&gt; disappears:
The <code>hero.id</code> in the &lt;ng-template *ngIf&gt; disappears:
<p>
<template *ngIf="showId">
<ng-template *ngIf="showId">
Id: ({{hero.id}})
</template>
</ng-template>
Name: {{hero.name}}
</p>
</div>
<div>
The <code>hero.id</code> in the &lt;template [ngIf]&gt;
The <code>hero.id</code> in the &lt;ng-template [ngIf]&gt;
is unaffected by the <span>p-span</span> CSS:
<p>
<template [ngIf]="showId">
<ng-template [ngIf]="showId">
Id: ({{hero.id}})
</template>
</ng-template>
Name: {{hero.name}}
</p>
</div>

View File

@ -18,9 +18,9 @@ describe('Structural Directives', function () {
expect(allLis.get(0).getText()).toEqual('Mr. Nice');
});
it('ngSwitch have three <happy-hero> instances', function () {
it('ngSwitch have two <happy-hero> instances', function () {
const happyHeroEls = element.all(by.tagName('happy-hero'));
expect(happyHeroEls.count()).toEqual(3);
expect(happyHeroEls.count()).toEqual(2);
});
it('should toggle *ngIf="hero" with a button', function () {

View File

@ -55,11 +55,6 @@
</ng-template>
<!-- #enddocregion ngif-template -->
<p>template attribute</p>
<!-- #docregion ngif-template-attr -->
<div template="ngIf hero">{{hero.name}}</div>
<!-- #enddocregion ngif-template-attr -->
<hr>
<h2 id="ng-container">&lt;ng-container&gt;</h2>
@ -131,14 +126,7 @@
</div>
<!--#enddocregion inside-ngfor -->
<p class="code">&lt;div template="ngFor let hero of heroes; let i=index; let odd=odd; trackBy: trackById" [class.odd]="odd"&gt;</p>
<!--#docregion inside-ngfor -->
<div template="ngFor let hero of heroes; let i=index; let odd=odd; trackBy: trackById" [class.odd]="odd">
({{i}}) {{hero.name}}
</div>
<!--#enddocregion inside-ngfor -->
<p class="code">&lt;template ngFor let-hero [ngForOf]="heroes" let-i="index" let-odd="odd" [ngForTrackBy]="trackById"&gt;</p>
<p class="code">&lt;ng-template ngFor let-hero [ngForOf]="heroes" let-i="index" let-odd="odd" [ngForTrackBy]="trackById"/&gt;</p>
<!--#docregion inside-ngfor -->
<ng-template ngFor let-hero [ngForOf]="heroes" let-i="index" let-odd="odd" [ngForTrackBy]="trackById">
<div [class.odd]="odd">({{i}}) {{hero.name}}</div>
@ -169,16 +157,6 @@
</div>
<!-- #enddocregion built-in, ngswitch -->
<h4>NgSwitch with <i>template</i> attribute</h4>
<!-- #docregion ngswitch-template-attr -->
<div [ngSwitch]="hero?.emotion">
<happy-hero template="ngSwitchCase 'happy'" [hero]="hero"></happy-hero>
<sad-hero template="ngSwitchCase 'sad'" [hero]="hero"></sad-hero>
<confused-hero template="ngSwitchCase 'confused'" [hero]="hero"></confused-hero>
<unknown-hero template="ngSwitchDefault" [hero]="hero"></unknown-hero>
</div>
<!-- #enddocregion ngswitch-template-attr -->
<h4>NgSwitch with &lt;ng-template&gt;</h4>
<!-- #docregion ngswitch-template -->
<div [ngSwitch]="hero?.emotion">
@ -199,7 +177,7 @@
<hr>
<h2>&lt;template&gt;</h2>
<h2>&lt;ng-template&gt;</h2>
<!-- #docregion template-tag -->
<p>Hip!</p>
<ng-template>
@ -238,13 +216,13 @@
<p *myUnless="condition">Show this sentence unless the condition is true.</p>
<!-- #enddocregion myUnless-1 -->
<p template="myUnless condition" class="code unless">
(A) &lt;p template="myUnless condition" class="code unless"&gt;
<p *myUnless="condition" class="code unless">
(A) &lt;p *myUnless="condition" class="code unless"&gt;
</p>
<ng-template [myUnless]="condition">
<p class="code unless">
(A) &lt;template [myUnless]="condition"&gt;
(A) &lt;ng-template [myUnless]="condition"&gt;
</p>
</ng-template>

View File

@ -19,8 +19,7 @@ import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
* ### Syntax
*
* - `<div *myUnless="condition">...</div>`
* - `<div template="myUnless condition">...</div>`
* - `<template [myUnless]="condition"><div>...</div></template>`
* - `<ng-template [myUnless]="condition"><div>...</div></ng-template>`
*
// #docregion no-docs
*/

View File

@ -78,11 +78,11 @@
<p>Template input variable expression context (let hero)</p>
<!-- template hides the following; plenty of examples later -->
<template>
<ng-template>
<!-- #docregion context-var -->
<div *ngFor="let hero of heroes">{{hero.name}}</div>
<!-- #enddocregion context-var -->
</template>
</ng-template>
<p>Template reference variable expression context (#heroInput)</p>
<div (keyup)="0" class="context">

View File

@ -208,17 +208,7 @@ Here is `*ngIf` displaying the hero's name if `hero` exists.
The asterisk is "syntactic sugar" for something a bit more complicated.
Internally, Angular desugars it in two stages.
First, it translates the `*ngIf="..."` into a template _attribute_, `template="ngIf ..."`,&nbsp; like this.
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngif-template-attr)" region="ngif-template-attr">
</code-example>
Then it translates the template _attribute_ into a `<ng-template>` _element_, wrapped around the host element, like this.
Internally, Angular translates the `*ngIf` _attribute_ into a `<ng-template>` _element_, wrapped around the host element, like this.
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngif-template)" region="ngif-template">
@ -230,8 +220,7 @@ Then it translates the template _attribute_ into a `<ng-template>` _element_, wr
* The `*ngIf` directive moved to the `<ng-template>` element where it became a property binding,`[ngIf]`.
* The rest of the `<div>`, including its class attribute, moved inside the `<ng-template>` element.
None of these forms are actually rendered.
Only the finished product ends up in the DOM.
The first form is not actually rendered, only the finished product ends up in the DOM.
<figure>
@ -252,10 +241,9 @@ The [`NgFor`](guide/structural-directives#ngFor) and [`NgSwitch...`](guide/struc
## Inside _*ngFor_
Angular transforms the `*ngFor` in similar fashion from asterisk (*) syntax through
template _attribute_ to `<ng-template>` _element_.
Angular transforms the `*ngFor` in similar fashion from asterisk (*) syntax to `<ng-template>` _element_.
Here's a full-featured application of `NgFor`, written all three ways:
Here's a full-featured application of `NgFor`, written both ways:
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (inside-ngfor)" region="inside-ngfor">
@ -415,16 +403,7 @@ The `<unknown-hero>` is the host element for the `*ngSwitchDefault`.
As with other structural directives, the `NgSwitchCase` and `NgSwitchDefault`
can be desugared into the template _attribute_ form.
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngswitch-template-attr)" region="ngswitch-template-attr">
</code-example>
That, in turn, can be desugared into the `<ng-template>` element form.
can be desugared into the `<ng-template>` element form.
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngswitch-template)" region="ngswitch-template">
@ -438,7 +417,7 @@ That, in turn, can be desugared into the `<ng-template>` element form.
## Prefer the asterisk (*) syntax.
The asterisk (*) syntax is more clear than the other desugared forms.
The asterisk (*) syntax is more clear than the desugared form.
Use [&lt;ng-container&gt;](guide/structural-directives#ng-container) when there's no single element
to host the directive.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@ -79,7 +79,6 @@ export class NgForOfContext<T> {
* ### Syntax
*
* - `<li *ngFor="let item of items; index as i; trackBy: trackByFn">...</li>`
* - `<li template="ngFor let item of items; index as i; trackBy: trackByFn">...</li>`
*
* With `<ng-template>` element:
*

View File

@ -75,7 +75,6 @@ import {Directive, EmbeddedViewRef, Input, TemplateRef, ViewContainerRef} from '
*
* Simple form:
* - `<div *ngIf="condition">...</div>`
* - `<div template="ngIf condition">...</div>`
* - `<ng-template [ngIf]="condition"><div>...</div></ng-template>`
*
* Form with an else block:

View File

@ -101,7 +101,7 @@ export class CodeGenerator {
translations: transContent,
i18nFormat: cliOptions.i18nFormat || undefined,
locale: cliOptions.locale || undefined, missingTranslation,
enableLegacyTemplate: options.enableLegacyTemplate !== false,
enableLegacyTemplate: options.enableLegacyTemplate === true,
enableSummariesForJit: options.enableSummariesForJit !== false,
preserveWhitespaces: options.preserveWhitespaces,
});

View File

@ -90,7 +90,7 @@ export interface CompilerOptions extends ts.CompilerOptions {
// Print extra information while running the compiler
trace?: boolean;
// Whether to enable support for <template> and the template attribute (true by default)
// Whether to enable support for <template> and the template attribute (false by default)
enableLegacyTemplate?: boolean;
// Whether to enable lowering expressions lambdas and expressions in a reference value

View File

@ -65,7 +65,7 @@ export function createAotCompiler(compilerHost: AotCompilerHost, options: AotCom
const config = new CompilerConfig({
defaultEncapsulation: ViewEncapsulation.Emulated,
useJit: false,
enableLegacyTemplate: options.enableLegacyTemplate !== false,
enableLegacyTemplate: options.enableLegacyTemplate === true,
missingTranslation: options.missingTranslation,
preserveWhitespaces: options.preserveWhitespaces,
});

View File

@ -36,7 +36,7 @@ export class CompilerConfig {
this.useJit = !!useJit;
this.jitDevMode = !!jitDevMode;
this.missingTranslation = missingTranslation || null;
this.enableLegacyTemplate = enableLegacyTemplate !== false;
this.enableLegacyTemplate = enableLegacyTemplate === true;
this.preserveWhitespaces = preserveWhitespacesDefault(noUndefined(preserveWhitespaces));
}
}

View File

@ -121,16 +121,19 @@ export function main() {
schemas?: SchemaMetadata[], preserveWhitespaces?: boolean) => TemplateAst[];
let console: ArrayConsole;
function commonBeforeEach() {
function configureCompiler() {
console = new ArrayConsole();
beforeEach(() => {
console = new ArrayConsole();
TestBed.configureCompiler({
providers: [
{provide: Console, useValue: console},
{provide: CompilerConfig, useValue: new CompilerConfig({enableLegacyTemplate: true})}
],
});
});
}
function commonBeforeEach() {
beforeEach(inject([TemplateParser], (parser: TemplateParser) => {
const someAnimation = new CompileAnimationEntryMetadata('someAnimation', []);
const someTemplate = compileTemplateMetadata({animations: [someAnimation]});
@ -286,6 +289,7 @@ export function main() {
});
});
configureCompiler();
commonBeforeEach();
describe('security context', () => {
@ -318,6 +322,7 @@ export function main() {
TestBed.configureCompiler({providers: [TEST_COMPILER_PROVIDERS, MOCK_SCHEMA_REGISTRY]});
});
configureCompiler();
commonBeforeEach();
describe('parse', () => {
@ -2129,13 +2134,13 @@ The pipe 'test' could not be found ("{{[ERROR ->]a | test}}"): TestComp@0:2`);
});
describe('Template Parser - opt-out `<template>` support', () => {
describe('Template Parser - `<template>` support disabled by default', () => {
beforeEach(() => {
TestBed.configureCompiler({
providers: [{
provide: CompilerConfig,
useValue: new CompilerConfig({enableLegacyTemplate: false}),
}],
providers: [
{provide: Console, useValue: console},
{provide: CompilerConfig, useValue: new CompilerConfig()}
],
});
});

View File

@ -7,6 +7,7 @@
*/
import {CommonModule} from '@angular/common';
import {CompilerConfig} from '@angular/compiler';
import {Compiler, ComponentFactory, ComponentRef, ErrorHandler, EventEmitter, Host, Inject, Injectable, InjectionToken, Injector, NO_ERRORS_SCHEMA, NgModule, NgModuleRef, OnDestroy, SkipSelf, ViewRef} from '@angular/core';
import {ChangeDetectionStrategy, ChangeDetectorRef, PipeTransform} from '@angular/core/src/change_detection/change_detection';
import {getDebugContext} from '@angular/core/src/errors';
@ -37,7 +38,14 @@ export function main() {
function declareTests({useJit}: {useJit: boolean}) {
describe('integration tests', function() {
beforeEach(() => { TestBed.configureCompiler({useJit}); });
beforeEach(() => {
TestBed.configureCompiler({
useJit,
providers: [
{provide: CompilerConfig, useValue: new CompilerConfig({enableLegacyTemplate: true})}
]
});
});
describe('react to record changes', function() {
it('should consume text node changes', () => {

View File

@ -160,7 +160,7 @@ export class JitCompilerFactory implements CompilerFactory {
useJit: true,
defaultEncapsulation: ViewEncapsulation.Emulated,
missingTranslation: MissingTranslationStrategy.Warning,
enableLegacyTemplate: true,
enableLegacyTemplate: false,
};
this._defaultOptions = [compilerOptions, ...defaultOptions];

View File

@ -76,7 +76,7 @@ interface Options extends ts.CompilerOptions {
// Print extra information while running the compiler
trace?: boolean;
// Whether to enable support for <template> and the template attribute (true by default)
// Whether to enable support for <template> and the template attribute (false by default)
enableLegacyTemplate?: boolean;
// Whether to generate .ngsummary.ts files that allow to use AOTed artifacts