feat(compiler): Add a `enableLegacyTemplate` option to support `<template>`
When the `enableLegacyTemplate` is set to `false`, `<template>` tags and the `template` attribute are no more used to define angular templates but are treated as regular tag and attribute. The default value is `true`. In order to define a template, you have to use the `<ng-template>` tag. This option applies to your application and all the libraries it uses. That is you should make sure none of them rely on the legacy way to defined templates when this option is turned off (`false`).
This commit is contained in:
parent
bf8eb41248
commit
e99d721612
|
@ -75,7 +75,8 @@ export class CodeGenerator {
|
||||||
debug: options.debug === true,
|
debug: options.debug === true,
|
||||||
translations: transContent,
|
translations: transContent,
|
||||||
i18nFormat: cliOptions.i18nFormat,
|
i18nFormat: cliOptions.i18nFormat,
|
||||||
locale: cliOptions.locale
|
locale: cliOptions.locale,
|
||||||
|
enableLegacyTemplate: options.enableLegacyTemplate !== false,
|
||||||
});
|
});
|
||||||
return new CodeGenerator(options, program, tsCompilerHost, aotCompiler, ngCompilerHost);
|
return new CodeGenerator(options, program, tsCompilerHost, aotCompiler, ngCompilerHost);
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,8 @@ export function createAotCompiler(compilerHost: AotCompilerHost, options: AotCom
|
||||||
defaultEncapsulation: ViewEncapsulation.Emulated,
|
defaultEncapsulation: ViewEncapsulation.Emulated,
|
||||||
logBindingUpdate: false,
|
logBindingUpdate: false,
|
||||||
useJit: false,
|
useJit: false,
|
||||||
useViewEngine: options.useViewEngine
|
useViewEngine: options.useViewEngine,
|
||||||
|
enableLegacyTemplate: options.enableLegacyTemplate !== false,
|
||||||
});
|
});
|
||||||
const normalizer = new DirectiveNormalizer(
|
const normalizer = new DirectiveNormalizer(
|
||||||
{get: (url: string) => compilerHost.loadResource(url)}, urlResolver, htmlParser, config);
|
{get: (url: string) => compilerHost.loadResource(url)}, urlResolver, htmlParser, config);
|
||||||
|
|
|
@ -12,4 +12,5 @@ export interface AotCompilerOptions {
|
||||||
i18nFormat?: string;
|
i18nFormat?: string;
|
||||||
translations?: string;
|
translations?: string;
|
||||||
useViewEngine?: boolean;
|
useViewEngine?: boolean;
|
||||||
|
enableLegacyTemplate?: boolean;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,22 +23,28 @@ export const USE_VIEW_ENGINE = new InjectionToken<boolean>('UseViewEngine');
|
||||||
export class CompilerConfig {
|
export class CompilerConfig {
|
||||||
public renderTypes: RenderTypes;
|
public renderTypes: RenderTypes;
|
||||||
public defaultEncapsulation: ViewEncapsulation;
|
public defaultEncapsulation: ViewEncapsulation;
|
||||||
private _genDebugInfo: boolean;
|
// Whether to support the `<template>` tag and the `template` attribute to define angular
|
||||||
private _logBindingUpdate: boolean;
|
// templates. They have been deprecated in 4.x, `<ng-template>` should be used instead.
|
||||||
|
public enableLegacyTemplate: boolean;
|
||||||
public useJit: boolean;
|
public useJit: boolean;
|
||||||
public useViewEngine: boolean;
|
public useViewEngine: boolean;
|
||||||
public missingTranslation: MissingTranslationStrategy;
|
public missingTranslation: MissingTranslationStrategy;
|
||||||
|
|
||||||
|
private _genDebugInfo: boolean;
|
||||||
|
private _logBindingUpdate: boolean;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
{renderTypes = new DefaultRenderTypes(), defaultEncapsulation = ViewEncapsulation.Emulated,
|
{renderTypes = new DefaultRenderTypes(), defaultEncapsulation = ViewEncapsulation.Emulated,
|
||||||
genDebugInfo, logBindingUpdate, useJit = true, missingTranslation, useViewEngine}: {
|
genDebugInfo, logBindingUpdate, useJit = true, missingTranslation, useViewEngine,
|
||||||
|
enableLegacyTemplate}: {
|
||||||
renderTypes?: RenderTypes,
|
renderTypes?: RenderTypes,
|
||||||
defaultEncapsulation?: ViewEncapsulation,
|
defaultEncapsulation?: ViewEncapsulation,
|
||||||
genDebugInfo?: boolean,
|
genDebugInfo?: boolean,
|
||||||
logBindingUpdate?: boolean,
|
logBindingUpdate?: boolean,
|
||||||
useJit?: boolean,
|
useJit?: boolean,
|
||||||
missingTranslation?: MissingTranslationStrategy,
|
missingTranslation?: MissingTranslationStrategy,
|
||||||
useViewEngine?: boolean
|
useViewEngine?: boolean,
|
||||||
|
enableLegacyTemplate?: boolean,
|
||||||
} = {}) {
|
} = {}) {
|
||||||
this.renderTypes = renderTypes;
|
this.renderTypes = renderTypes;
|
||||||
this.defaultEncapsulation = defaultEncapsulation;
|
this.defaultEncapsulation = defaultEncapsulation;
|
||||||
|
@ -47,6 +53,7 @@ export class CompilerConfig {
|
||||||
this.useJit = useJit;
|
this.useJit = useJit;
|
||||||
this.missingTranslation = missingTranslation;
|
this.missingTranslation = missingTranslation;
|
||||||
this.useViewEngine = true;
|
this.useViewEngine = true;
|
||||||
|
this.enableLegacyTemplate = enableLegacyTemplate !== false;
|
||||||
}
|
}
|
||||||
|
|
||||||
get genDebugInfo(): boolean {
|
get genDebugInfo(): boolean {
|
||||||
|
|
|
@ -104,7 +104,6 @@ export const COMPILER_PROVIDERS: Array<any|Type<any>|{[k: string]: any}|any[]> =
|
||||||
AnimationParser,
|
AnimationParser,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
@CompilerInjectable()
|
@CompilerInjectable()
|
||||||
export class JitCompilerFactory implements CompilerFactory {
|
export class JitCompilerFactory implements CompilerFactory {
|
||||||
private _defaultOptions: CompilerOptions[];
|
private _defaultOptions: CompilerOptions[];
|
||||||
|
@ -136,7 +135,8 @@ export class JitCompilerFactory implements CompilerFactory {
|
||||||
// from the app providers
|
// from the app providers
|
||||||
defaultEncapsulation: opts.defaultEncapsulation,
|
defaultEncapsulation: opts.defaultEncapsulation,
|
||||||
logBindingUpdate: opts.useDebug,
|
logBindingUpdate: opts.useDebug,
|
||||||
missingTranslation: opts.missingTranslation, useViewEngine
|
missingTranslation: opts.missingTranslation, useViewEngine,
|
||||||
|
enableLegacyTemplate: opts.enableLegacyTemplate,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
deps: [USE_VIEW_ENGINE]
|
deps: [USE_VIEW_ENGINE]
|
||||||
|
|
|
@ -273,7 +273,7 @@ class TemplateParseVisitor implements html.Visitor {
|
||||||
let hasInlineTemplates = false;
|
let hasInlineTemplates = false;
|
||||||
const attrs: AttrAst[] = [];
|
const attrs: AttrAst[] = [];
|
||||||
const isTemplateElement = isTemplate(
|
const isTemplateElement = isTemplate(
|
||||||
element,
|
element, this.config.enableLegacyTemplate,
|
||||||
(m: string, span: ParseSourceSpan) => this._reportError(m, span, ParseErrorLevel.WARNING));
|
(m: string, span: ParseSourceSpan) => this._reportError(m, span, ParseErrorLevel.WARNING));
|
||||||
|
|
||||||
element.attrs.forEach(attr => {
|
element.attrs.forEach(attr => {
|
||||||
|
@ -285,7 +285,7 @@ class TemplateParseVisitor implements html.Visitor {
|
||||||
let prefixToken: string|undefined;
|
let prefixToken: string|undefined;
|
||||||
let normalizedName = this._normalizeAttributeName(attr.name);
|
let normalizedName = this._normalizeAttributeName(attr.name);
|
||||||
|
|
||||||
if (normalizedName == TEMPLATE_ATTR) {
|
if (this.config.enableLegacyTemplate && normalizedName == TEMPLATE_ATTR) {
|
||||||
this._reportError(
|
this._reportError(
|
||||||
`The template attribute is deprecated. Use an ng-template element instead.`,
|
`The template attribute is deprecated. Use an ng-template element instead.`,
|
||||||
attr.sourceSpan, ParseErrorLevel.WARNING);
|
attr.sourceSpan, ParseErrorLevel.WARNING);
|
||||||
|
@ -905,16 +905,19 @@ function isEmptyExpression(ast: AST): boolean {
|
||||||
|
|
||||||
// `template` is deprecated in 4.x
|
// `template` is deprecated in 4.x
|
||||||
function isTemplate(
|
function isTemplate(
|
||||||
el: html.Element, reportDeprecation: (m: string, span: ParseSourceSpan) => void): boolean {
|
el: html.Element, enableLegacyTemplate: boolean,
|
||||||
|
reportDeprecation: (m: string, span: ParseSourceSpan) => void): boolean {
|
||||||
const tagNoNs = splitNsName(el.name)[1];
|
const tagNoNs = splitNsName(el.name)[1];
|
||||||
// `<ng-template>` is an angular construct and is lower case
|
// `<ng-template>` is an angular construct and is lower case
|
||||||
if (tagNoNs === NG_TEMPLATE_ELEMENT) return true;
|
if (tagNoNs === NG_TEMPLATE_ELEMENT) return true;
|
||||||
// `<template>` is HTML and case insensitive
|
// `<template>` is HTML and case insensitive
|
||||||
if (tagNoNs.toLowerCase() === TEMPLATE_ELEMENT) {
|
if (tagNoNs.toLowerCase() === TEMPLATE_ELEMENT) {
|
||||||
reportDeprecation(
|
if (enableLegacyTemplate && tagNoNs.toLowerCase() === TEMPLATE_ELEMENT) {
|
||||||
`The <template> element is deprecated. Use <ng-template> instead`, el.sourceSpan);
|
reportDeprecation(
|
||||||
return true;
|
`The <template> element is deprecated. Use <ng-template> instead`, el.sourceSpan);
|
||||||
}
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
|
@ -5,6 +5,7 @@
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
* 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
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
import {CompilerConfig} from '@angular/compiler';
|
||||||
import {CompileAnimationEntryMetadata, CompileDiDependencyMetadata, CompileDirectiveMetadata, CompileDirectiveSummary, CompilePipeMetadata, CompilePipeSummary, CompileProviderMetadata, CompileTemplateMetadata, CompileTokenMetadata, CompileTypeMetadata, tokenReference} from '@angular/compiler/src/compile_metadata';
|
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 {DomElementSchemaRegistry} from '@angular/compiler/src/schema/dom_element_schema_registry';
|
||||||
import {ElementSchemaRegistry} from '@angular/compiler/src/schema/element_schema_registry';
|
import {ElementSchemaRegistry} from '@angular/compiler/src/schema/element_schema_registry';
|
||||||
|
@ -44,8 +45,13 @@ export function main() {
|
||||||
function commonBeforeEach() {
|
function commonBeforeEach() {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
console = new ArrayConsole();
|
console = new ArrayConsole();
|
||||||
TestBed.configureCompiler({providers: [{provide: Console, useValue: console}]});
|
TestBed.configureCompiler({
|
||||||
|
providers: [
|
||||||
|
{provide: Console, useValue: console},
|
||||||
|
],
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(inject([TemplateParser], (parser: TemplateParser) => {
|
beforeEach(inject([TemplateParser], (parser: TemplateParser) => {
|
||||||
const someAnimation = new CompileAnimationEntryMetadata('someAnimation', []);
|
const someAnimation = new CompileAnimationEntryMetadata('someAnimation', []);
|
||||||
const someTemplate = new CompileTemplateMetadata({animations: [someAnimation]});
|
const someTemplate = new CompileTemplateMetadata({animations: [someAnimation]});
|
||||||
|
@ -2023,6 +2029,47 @@ The pipe 'test' could not be found ("{{[ERROR ->]a | test}}"): TestComp@0:2`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Template Parser - opt-out `<template>` support', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureCompiler({
|
||||||
|
providers: [{
|
||||||
|
provide: CompilerConfig,
|
||||||
|
useValue: new CompilerConfig({enableLegacyTemplate: false}),
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
commonBeforeEach();
|
||||||
|
|
||||||
|
it('should support * directives', () => {
|
||||||
|
expect(humanizeTplAst(parse('<div *ngIf>', [ngIf]))).toEqual([
|
||||||
|
[EmbeddedTemplateAst],
|
||||||
|
[DirectiveAst, ngIf],
|
||||||
|
[BoundDirectivePropertyAst, 'ngIf', 'null'],
|
||||||
|
[ElementAst, 'div'],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should support <ng-template>', () => {
|
||||||
|
expect(humanizeTplAst(parse('<ng-template>', []))).toEqual([
|
||||||
|
[EmbeddedTemplateAst],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should treat <template> as a regular tag', () => {
|
||||||
|
expect(humanizeTplAst(parse('<template>', []))).toEqual([
|
||||||
|
[ElementAst, 'template'],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not special case the template attribute', () => {
|
||||||
|
expect(humanizeTplAst(parse('<p template="ngFor">', []))).toEqual([
|
||||||
|
[ElementAst, 'p'],
|
||||||
|
[AttrAst, 'template', 'ngFor'],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function humanizeTplAst(
|
function humanizeTplAst(
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Injectable, InjectionToken} from '../di';
|
import {Injectable, InjectionToken} from '../di';
|
||||||
import {stringify} from '../facade/lang';
|
|
||||||
import {MissingTranslationStrategy} from '../i18n/tokens';
|
import {MissingTranslationStrategy} from '../i18n/tokens';
|
||||||
import {ViewEncapsulation} from '../metadata';
|
import {ViewEncapsulation} from '../metadata';
|
||||||
import {Type} from '../type';
|
import {Type} from '../type';
|
||||||
|
@ -99,6 +98,9 @@ export type CompilerOptions = {
|
||||||
defaultEncapsulation?: ViewEncapsulation,
|
defaultEncapsulation?: ViewEncapsulation,
|
||||||
providers?: any[],
|
providers?: any[],
|
||||||
missingTranslation?: MissingTranslationStrategy,
|
missingTranslation?: MissingTranslationStrategy,
|
||||||
|
// 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,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -78,6 +78,9 @@ interface Options extends ts.CompilerOptions {
|
||||||
|
|
||||||
// Whether to embed debug information in the compiled templates
|
// Whether to embed debug information in the compiled templates
|
||||||
debug?: boolean;
|
debug?: boolean;
|
||||||
|
|
||||||
|
// Whether to enable support for <template> and the template attribute (true by default)
|
||||||
|
enableLegacyTemplate?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Options;
|
export default Options;
|
||||||
|
|
|
@ -234,6 +234,7 @@ export declare type CompilerOptions = {
|
||||||
defaultEncapsulation?: ViewEncapsulation;
|
defaultEncapsulation?: ViewEncapsulation;
|
||||||
providers?: any[];
|
providers?: any[];
|
||||||
missingTranslation?: MissingTranslationStrategy;
|
missingTranslation?: MissingTranslationStrategy;
|
||||||
|
enableLegacyTemplate?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @stable */
|
/** @stable */
|
||||||
|
|
Loading…
Reference in New Issue