refactor(core): expand error logging when the JIT compiler is not available (#42693)

If a decorator or partial declaration has not been AOT compiled, then
the compiler is needed at runtime to be able to JIT compile the code.
However, it may occur that the compiler is not available, if it has not
been loaded into the application. The error that was reported in this
case did not provide insight into which class requested compilation, nor
did it differentiate between decorators vs. partial declarations.

This commit expands the error logging to provide better insight into the
class that initiated JIT compilation and offers a specialized error
message for partial declarations. This should help a developer better
understand why the error occurs and what can be done to resolve it.

Closes #40609

PR Close #42693
This commit is contained in:
JoostK 2021-06-28 23:07:41 +02:00 committed by Alex Rickabaugh
parent 07d7e6034f
commit 31593db489
9 changed files with 227 additions and 51 deletions

View File

@ -13,7 +13,7 @@ import {share} from 'rxjs/operators';
import {ApplicationInitStatus} from './application_init'; import {ApplicationInitStatus} from './application_init';
import {APP_BOOTSTRAP_LISTENER, PLATFORM_INITIALIZER} from './application_tokens'; import {APP_BOOTSTRAP_LISTENER, PLATFORM_INITIALIZER} from './application_tokens';
import {getCompilerFacade} from './compiler/compiler_facade'; import {getCompilerFacade, JitCompilerUsage} from './compiler/compiler_facade';
import {Console} from './console'; import {Console} from './console';
import {Injectable} from './di/injectable'; import {Injectable} from './di/injectable';
import {InjectionToken} from './di/injection_token'; import {InjectionToken} from './di/injection_token';
@ -94,7 +94,11 @@ export function compileNgModuleFactory__POST_R3__<M>(
return Promise.resolve(moduleFactory); return Promise.resolve(moduleFactory);
} }
const compiler = getCompilerFacade(); const compiler = getCompilerFacade({
usage: JitCompilerUsage.Decorator,
kind: 'NgModule',
type: moduleType,
});
const compilerInjector = Injector.create({providers: compilerProviders}); const compilerInjector = Injector.create({providers: compilerProviders});
const resourceLoader = compilerInjector.get(compiler.ResourceLoader); const resourceLoader = compilerInjector.get(compiler.ResourceLoader);
// The resource loader can also return a string while the "resolveComponentResources" // The resource loader can also return a string while the "resolveComponentResources"

View File

@ -6,17 +6,51 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {global} from '../util/global'; import {global} from '../util/global';
import {CompilerFacade, ExportedCompilerFacade} from './compiler_facade_interface'; import {CompilerFacade, ExportedCompilerFacade, Type} from './compiler_facade_interface';
export * from './compiler_facade_interface'; export * from './compiler_facade_interface';
export function getCompilerFacade(): CompilerFacade { export const enum JitCompilerUsage {
const globalNg: ExportedCompilerFacade = global['ng']; Decorator,
if (!globalNg || !globalNg.ɵcompilerFacade) { PartialDeclaration,
throw new Error( }
`Angular JIT compilation failed: '@angular/compiler' not loaded!\n` +
` - JIT compilation is discouraged for production use-cases! Consider AOT mode instead.\n` + interface JitCompilerUsageRequest {
` - Did you bootstrap using '@angular/platform-browser-dynamic' or '@angular/platform-server'?\n` + usage: JitCompilerUsage;
` - Alternatively provide the compiler with 'import "@angular/compiler";' before bootstrapping.`); kind: 'directive'|'component'|'pipe'|'injectable'|'NgModule';
} type: Type;
return globalNg.ɵcompilerFacade; }
export function getCompilerFacade(request: JitCompilerUsageRequest): CompilerFacade {
const globalNg: ExportedCompilerFacade = global['ng'];
if (globalNg && globalNg.ɵcompilerFacade) {
return globalNg.ɵcompilerFacade;
}
if (typeof ngDevMode === 'undefined' || ngDevMode) {
// Log the type as an error so that a developer can easily navigate to the type from the
// console.
console.error(`JIT compilation failed for ${request.kind}`, request.type);
let message = `The ${request.kind} '${
request
.type.name}' needs to be compiled using the JIT compiler, but '@angular/compiler' is not available.\n\n`;
if (request.usage === JitCompilerUsage.PartialDeclaration) {
message += `The ${request.kind} is part of a library that has been partially compiled.\n`;
message +=
`However, the Angular Linker has not processed the library such that JIT compilation is used as fallback.\n`;
message += '\n';
message +=
`Ideally, the library is processed using the Angular Linker to become fully AOT compiled.\n`;
} else {
message +=
`JIT compilation is discouraged for production use-cases! Consider using AOT mode instead.\n`;
}
message +=
`Alternatively, the JIT compiler should be loaded by bootstrapping using '@angular/platform-browser-dynamic' or '@angular/platform-server',\n`;
message +=
`or manually provide the compiler with 'import "@angular/compiler";' before bootstrapping.`;
throw new Error(message);
} else {
throw new Error('JIT compiler unavailable');
}
} }

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {getCompilerFacade, R3InjectableMetadataFacade} from '../../compiler/compiler_facade'; import {getCompilerFacade, JitCompilerUsage, R3InjectableMetadataFacade} from '../../compiler/compiler_facade';
import {Type} from '../../interface/type'; import {Type} from '../../interface/type';
import {NG_FACTORY_DEF} from '../../render3/fields'; import {NG_FACTORY_DEF} from '../../render3/fields';
import {getClosureSafeProperty} from '../../util/property'; import {getClosureSafeProperty} from '../../util/property';
@ -33,7 +33,9 @@ export function compileInjectable(type: Type<any>, meta?: Injectable): void {
Object.defineProperty(type, NG_PROV_DEF, { Object.defineProperty(type, NG_PROV_DEF, {
get: () => { get: () => {
if (ngInjectableDef === null) { if (ngInjectableDef === null) {
ngInjectableDef = getCompilerFacade().compileInjectable( const compiler =
getCompilerFacade({usage: JitCompilerUsage.Decorator, kind: 'injectable', type});
ngInjectableDef = compiler.compileInjectable(
angularCoreDiEnv, `ng:///${type.name}/ɵprov.js`, getInjectableMetadata(type, meta)); angularCoreDiEnv, `ng:///${type.name}/ɵprov.js`, getInjectableMetadata(type, meta));
} }
return ngInjectableDef; return ngInjectableDef;
@ -46,7 +48,8 @@ export function compileInjectable(type: Type<any>, meta?: Injectable): void {
Object.defineProperty(type, NG_FACTORY_DEF, { Object.defineProperty(type, NG_FACTORY_DEF, {
get: () => { get: () => {
if (ngFactoryDef === null) { if (ngFactoryDef === null) {
const compiler = getCompilerFacade(); const compiler =
getCompilerFacade({usage: JitCompilerUsage.Decorator, kind: 'injectable', type});
ngFactoryDef = compiler.compileFactory(angularCoreDiEnv, `ng:///${type.name}/ɵfac.js`, { ngFactoryDef = compiler.compileFactory(angularCoreDiEnv, `ng:///${type.name}/ɵfac.js`, {
name: type.name, name: type.name,
type, type,

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {getCompilerFacade, R3DirectiveMetadataFacade} from '../../compiler/compiler_facade'; import {getCompilerFacade, JitCompilerUsage, R3DirectiveMetadataFacade} from '../../compiler/compiler_facade';
import {R3ComponentMetadataFacade, R3QueryMetadataFacade} from '../../compiler/compiler_facade_interface'; import {R3ComponentMetadataFacade, R3QueryMetadataFacade} from '../../compiler/compiler_facade_interface';
import {resolveForwardRef} from '../../di/forward_ref'; import {resolveForwardRef} from '../../di/forward_ref';
import {getReflect, reflectDependencies} from '../../di/jit/util'; import {getReflect, reflectDependencies} from '../../di/jit/util';
@ -68,7 +68,8 @@ export function compileComponent(type: Type<any>, metadata: Component): void {
Object.defineProperty(type, NG_COMP_DEF, { Object.defineProperty(type, NG_COMP_DEF, {
get: () => { get: () => {
if (ngComponentDef === null) { if (ngComponentDef === null) {
const compiler = getCompilerFacade(); const compiler =
getCompilerFacade({usage: JitCompilerUsage.Decorator, kind: 'component', type: type});
if (componentNeedsResolution(metadata)) { if (componentNeedsResolution(metadata)) {
const error = [`Component '${type.name}' is not resolved:`]; const error = [`Component '${type.name}' is not resolved:`];
@ -180,8 +181,10 @@ export function compileDirective(type: Type<any>, directive: Directive|null): vo
// that use `@Directive()` with no selector. In that case, pass empty object to the // that use `@Directive()` with no selector. In that case, pass empty object to the
// `directiveMetadata` function instead of null. // `directiveMetadata` function instead of null.
const meta = getDirectiveMetadata(type, directive || {}); const meta = getDirectiveMetadata(type, directive || {});
const compiler =
getCompilerFacade({usage: JitCompilerUsage.Decorator, kind: 'directive', type});
ngDirectiveDef = ngDirectiveDef =
getCompilerFacade().compileDirective(angularCoreEnv, meta.sourceMapUrl, meta.metadata); compiler.compileDirective(angularCoreEnv, meta.sourceMapUrl, meta.metadata);
} }
return ngDirectiveDef; return ngDirectiveDef;
}, },
@ -193,7 +196,7 @@ export function compileDirective(type: Type<any>, directive: Directive|null): vo
function getDirectiveMetadata(type: Type<any>, metadata: Directive) { function getDirectiveMetadata(type: Type<any>, metadata: Directive) {
const name = type && type.name; const name = type && type.name;
const sourceMapUrl = `ng:///${name}/ɵdir.js`; const sourceMapUrl = `ng:///${name}/ɵdir.js`;
const compiler = getCompilerFacade(); const compiler = getCompilerFacade({usage: JitCompilerUsage.Decorator, kind: 'directive', type});
const facade = directiveMetadata(type as ComponentType<any>, metadata); const facade = directiveMetadata(type as ComponentType<any>, metadata);
facade.typeSourceSpan = compiler.createParseSourceSpan('Directive', name, sourceMapUrl); facade.typeSourceSpan = compiler.createParseSourceSpan('Directive', name, sourceMapUrl);
if (facade.usesInheritance) { if (facade.usesInheritance) {
@ -209,7 +212,8 @@ function addDirectiveFactoryDef(type: Type<any>, metadata: Directive|Component)
get: () => { get: () => {
if (ngFactoryDef === null) { if (ngFactoryDef === null) {
const meta = getDirectiveMetadata(type, metadata); const meta = getDirectiveMetadata(type, metadata);
const compiler = getCompilerFacade(); const compiler =
getCompilerFacade({usage: JitCompilerUsage.Decorator, kind: 'directive', type});
ngFactoryDef = compiler.compileFactory(angularCoreEnv, `ng:///${type.name}/ɵfac.js`, { ngFactoryDef = compiler.compileFactory(angularCoreEnv, `ng:///${type.name}/ɵfac.js`, {
name: meta.metadata.name, name: meta.metadata.name,
type: meta.metadata.type, type: meta.metadata.type,

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {getCompilerFacade, R3InjectorMetadataFacade} from '../../compiler/compiler_facade'; import {getCompilerFacade, JitCompilerUsage, R3InjectorMetadataFacade} from '../../compiler/compiler_facade';
import {resolveForwardRef} from '../../di/forward_ref'; import {resolveForwardRef} from '../../di/forward_ref';
import {NG_INJ_DEF} from '../../di/interface/defs'; import {NG_INJ_DEF} from '../../di/interface/defs';
import {reflectDependencies} from '../../di/jit/util'; import {reflectDependencies} from '../../di/jit/util';
@ -114,20 +114,21 @@ export function compileNgModuleDefs(
// go into an infinite loop before we've reached the point where we throw all the errors. // go into an infinite loop before we've reached the point where we throw all the errors.
throw new Error(`'${stringifyForError(moduleType)}' module can't import itself`); throw new Error(`'${stringifyForError(moduleType)}' module can't import itself`);
} }
ngModuleDef = getCompilerFacade().compileNgModule( const compiler = getCompilerFacade(
angularCoreEnv, `ng:///${moduleType.name}/ɵmod.js`, { {usage: JitCompilerUsage.Decorator, kind: 'NgModule', type: moduleType});
type: moduleType, ngModuleDef = compiler.compileNgModule(angularCoreEnv, `ng:///${moduleType.name}/ɵmod.js`, {
bootstrap: flatten(ngModule.bootstrap || EMPTY_ARRAY).map(resolveForwardRef), type: moduleType,
declarations: declarations.map(resolveForwardRef), bootstrap: flatten(ngModule.bootstrap || EMPTY_ARRAY).map(resolveForwardRef),
imports: flatten(ngModule.imports || EMPTY_ARRAY) declarations: declarations.map(resolveForwardRef),
.map(resolveForwardRef) imports: flatten(ngModule.imports || EMPTY_ARRAY)
.map(expandModuleWithProviders), .map(resolveForwardRef)
exports: flatten(ngModule.exports || EMPTY_ARRAY) .map(expandModuleWithProviders),
.map(resolveForwardRef) exports: flatten(ngModule.exports || EMPTY_ARRAY)
.map(expandModuleWithProviders), .map(resolveForwardRef)
schemas: ngModule.schemas ? flatten(ngModule.schemas) : null, .map(expandModuleWithProviders),
id: ngModule.id || null, schemas: ngModule.schemas ? flatten(ngModule.schemas) : null,
}); id: ngModule.id || null,
});
// Set `schemas` on ngModuleDef to an empty array in JIT mode to indicate that runtime // Set `schemas` on ngModuleDef to an empty array in JIT mode to indicate that runtime
// should verify that there are no unknown elements in a template. In AOT mode, that check // should verify that there are no unknown elements in a template. In AOT mode, that check
// happens at compile time and `schemas` information is not present on Component and Module // happens at compile time and `schemas` information is not present on Component and Module
@ -144,7 +145,8 @@ export function compileNgModuleDefs(
Object.defineProperty(moduleType, NG_FACTORY_DEF, { Object.defineProperty(moduleType, NG_FACTORY_DEF, {
get: () => { get: () => {
if (ngFactoryDef === null) { if (ngFactoryDef === null) {
const compiler = getCompilerFacade(); const compiler = getCompilerFacade(
{usage: JitCompilerUsage.Decorator, kind: 'NgModule', type: moduleType});
ngFactoryDef = compiler.compileFactory(angularCoreEnv, `ng:///${moduleType.name}/ɵfac.js`, { ngFactoryDef = compiler.compileFactory(angularCoreEnv, `ng:///${moduleType.name}/ɵfac.js`, {
name: moduleType.name, name: moduleType.name,
type: moduleType, type: moduleType,
@ -175,8 +177,10 @@ export function compileNgModuleDefs(
(ngModule.exports || EMPTY_ARRAY).map(resolveForwardRef), (ngModule.exports || EMPTY_ARRAY).map(resolveForwardRef),
], ],
}; };
ngInjectorDef = getCompilerFacade().compileInjector( const compiler = getCompilerFacade(
angularCoreEnv, `ng:///${moduleType.name}/ɵinj.js`, meta); {usage: JitCompilerUsage.Decorator, kind: 'NgModule', type: moduleType});
ngInjectorDef =
compiler.compileInjector(angularCoreEnv, `ng:///${moduleType.name}/ɵinj.js`, meta);
} }
return ngInjectorDef; return ngInjectorDef;
}, },

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {getCompilerFacade, R3DeclareComponentFacade, R3DeclareDirectiveFacade, R3DeclareFactoryFacade, R3DeclareInjectableFacade, R3DeclareInjectorFacade, R3DeclareNgModuleFacade, R3DeclarePipeFacade} from '../../compiler/compiler_facade'; import {FactoryTarget, getCompilerFacade, JitCompilerUsage, R3DeclareComponentFacade, R3DeclareDirectiveFacade, R3DeclareFactoryFacade, R3DeclareInjectableFacade, R3DeclareInjectorFacade, R3DeclareNgModuleFacade, R3DeclarePipeFacade} from '../../compiler/compiler_facade';
import {Type} from '../../interface/type'; import {Type} from '../../interface/type';
import {setClassMetadata} from '../metadata'; import {setClassMetadata} from '../metadata';
import {angularCoreEnv} from './environment'; import {angularCoreEnv} from './environment';
@ -17,7 +17,8 @@ import {angularCoreEnv} from './environment';
* @codeGenApi * @codeGenApi
*/ */
export function ɵɵngDeclareDirective(decl: R3DeclareDirectiveFacade): unknown { export function ɵɵngDeclareDirective(decl: R3DeclareDirectiveFacade): unknown {
const compiler = getCompilerFacade(); const compiler = getCompilerFacade(
{usage: JitCompilerUsage.PartialDeclaration, kind: 'directive', type: decl.type});
return compiler.compileDirectiveDeclaration( return compiler.compileDirectiveDeclaration(
angularCoreEnv, `ng:///${decl.type.name}/ɵfac.js`, decl); angularCoreEnv, `ng:///${decl.type.name}/ɵfac.js`, decl);
} }
@ -42,7 +43,8 @@ export function ɵɵngDeclareClassMetadata(decl: {
* @codeGenApi * @codeGenApi
*/ */
export function ɵɵngDeclareComponent(decl: R3DeclareComponentFacade): unknown { export function ɵɵngDeclareComponent(decl: R3DeclareComponentFacade): unknown {
const compiler = getCompilerFacade(); const compiler = getCompilerFacade(
{usage: JitCompilerUsage.PartialDeclaration, kind: 'component', type: decl.type});
return compiler.compileComponentDeclaration( return compiler.compileComponentDeclaration(
angularCoreEnv, `ng:///${decl.type.name}/ɵcmp.js`, decl); angularCoreEnv, `ng:///${decl.type.name}/ɵcmp.js`, decl);
} }
@ -53,18 +55,38 @@ export function ɵɵngDeclareComponent(decl: R3DeclareComponentFacade): unknown
* @codeGenApi * @codeGenApi
*/ */
export function ɵɵngDeclareFactory(decl: R3DeclareFactoryFacade): unknown { export function ɵɵngDeclareFactory(decl: R3DeclareFactoryFacade): unknown {
const compiler = getCompilerFacade(); const compiler = getCompilerFacade({
usage: JitCompilerUsage.PartialDeclaration,
kind: getFactoryKind(decl.target),
type: decl.type
});
return compiler.compileFactoryDeclaration( return compiler.compileFactoryDeclaration(
angularCoreEnv, `ng:///${decl.type.name}/ɵfac.js`, decl); angularCoreEnv, `ng:///${decl.type.name}/ɵfac.js`, decl);
} }
function getFactoryKind(target: FactoryTarget) {
switch (target) {
case FactoryTarget.Directive:
return 'directive';
case FactoryTarget.Component:
return 'component';
case FactoryTarget.Injectable:
return 'injectable';
case FactoryTarget.Pipe:
return 'pipe';
case FactoryTarget.NgModule:
return 'NgModule';
}
}
/** /**
* Compiles a partial injectable declaration object into a full injectable definition object. * Compiles a partial injectable declaration object into a full injectable definition object.
* *
* @codeGenApi * @codeGenApi
*/ */
export function ɵɵngDeclareInjectable(decl: R3DeclareInjectableFacade): unknown { export function ɵɵngDeclareInjectable(decl: R3DeclareInjectableFacade): unknown {
const compiler = getCompilerFacade(); const compiler = getCompilerFacade(
{usage: JitCompilerUsage.PartialDeclaration, kind: 'injectable', type: decl.type});
return compiler.compileInjectableDeclaration( return compiler.compileInjectableDeclaration(
angularCoreEnv, `ng:///${decl.type.name}/ɵprov.js`, decl); angularCoreEnv, `ng:///${decl.type.name}/ɵprov.js`, decl);
} }
@ -80,7 +102,8 @@ export {FactoryTarget} from '../../compiler/compiler_facade';
* @codeGenApi * @codeGenApi
*/ */
export function ɵɵngDeclareInjector(decl: R3DeclareInjectorFacade): unknown { export function ɵɵngDeclareInjector(decl: R3DeclareInjectorFacade): unknown {
const compiler = getCompilerFacade(); const compiler = getCompilerFacade(
{usage: JitCompilerUsage.PartialDeclaration, kind: 'NgModule', type: decl.type});
return compiler.compileInjectorDeclaration( return compiler.compileInjectorDeclaration(
angularCoreEnv, `ng:///${decl.type.name}/ɵinj.js`, decl); angularCoreEnv, `ng:///${decl.type.name}/ɵinj.js`, decl);
} }
@ -91,7 +114,8 @@ export function ɵɵngDeclareInjector(decl: R3DeclareInjectorFacade): unknown {
* @codeGenApi * @codeGenApi
*/ */
export function ɵɵngDeclareNgModule(decl: R3DeclareNgModuleFacade): unknown { export function ɵɵngDeclareNgModule(decl: R3DeclareNgModuleFacade): unknown {
const compiler = getCompilerFacade(); const compiler = getCompilerFacade(
{usage: JitCompilerUsage.PartialDeclaration, kind: 'NgModule', type: decl.type});
return compiler.compileNgModuleDeclaration( return compiler.compileNgModuleDeclaration(
angularCoreEnv, `ng:///${decl.type.name}/ɵmod.js`, decl); angularCoreEnv, `ng:///${decl.type.name}/ɵmod.js`, decl);
} }
@ -102,6 +126,7 @@ export function ɵɵngDeclareNgModule(decl: R3DeclareNgModuleFacade): unknown {
* @codeGenApi * @codeGenApi
*/ */
export function ɵɵngDeclarePipe(decl: R3DeclarePipeFacade): unknown { export function ɵɵngDeclarePipe(decl: R3DeclarePipeFacade): unknown {
const compiler = getCompilerFacade(); const compiler = getCompilerFacade(
{usage: JitCompilerUsage.PartialDeclaration, kind: 'pipe', type: decl.type});
return compiler.compilePipeDeclaration(angularCoreEnv, `ng:///${decl.type.name}/ɵpipe.js`, decl); return compiler.compilePipeDeclaration(angularCoreEnv, `ng:///${decl.type.name}/ɵpipe.js`, decl);
} }

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {getCompilerFacade, R3PipeMetadataFacade} from '../../compiler/compiler_facade'; import {getCompilerFacade, JitCompilerUsage, R3PipeMetadataFacade} from '../../compiler/compiler_facade';
import {reflectDependencies} from '../../di/jit/util'; import {reflectDependencies} from '../../di/jit/util';
import {Type} from '../../interface/type'; import {Type} from '../../interface/type';
import {Pipe} from '../../metadata/directives'; import {Pipe} from '../../metadata/directives';
@ -22,7 +22,8 @@ export function compilePipe(type: Type<any>, meta: Pipe): void {
get: () => { get: () => {
if (ngFactoryDef === null) { if (ngFactoryDef === null) {
const metadata = getPipeMetadata(type, meta); const metadata = getPipeMetadata(type, meta);
const compiler = getCompilerFacade(); const compiler = getCompilerFacade(
{usage: JitCompilerUsage.Decorator, kind: 'pipe', type: metadata.type});
ngFactoryDef = compiler.compileFactory(angularCoreEnv, `ng:///${metadata.name}/ɵfac.js`, { ngFactoryDef = compiler.compileFactory(angularCoreEnv, `ng:///${metadata.name}/ɵfac.js`, {
name: metadata.name, name: metadata.name,
type: metadata.type, type: metadata.type,
@ -41,8 +42,10 @@ export function compilePipe(type: Type<any>, meta: Pipe): void {
get: () => { get: () => {
if (ngPipeDef === null) { if (ngPipeDef === null) {
const metadata = getPipeMetadata(type, meta); const metadata = getPipeMetadata(type, meta);
ngPipeDef = getCompilerFacade().compilePipe( const compiler = getCompilerFacade(
angularCoreEnv, `ng:///${metadata.name}/ɵpipe.js`, metadata); {usage: JitCompilerUsage.Decorator, kind: 'pipe', type: metadata.type});
ngPipeDef =
compiler.compilePipe(angularCoreEnv, `ng:///${metadata.name}/ɵpipe.js`, metadata);
} }
return ngPipeDef; return ngPipeDef;
}, },

View File

@ -0,0 +1,30 @@
load("//tools:defaults.bzl", "jasmine_node_test", "karma_web_test_suite", "ts_library")
package(default_visibility = ["//visibility:private"])
ts_library(
name = "compiler_lib",
testonly = True,
srcs = glob(
["**/*.ts"],
),
deps = [
"//packages/core/src/compiler",
"//packages/core/src/util",
],
)
jasmine_node_test(
name = "compiler",
bootstrap = ["//tools/testing:node_es5"],
deps = [
":compiler_lib",
],
)
karma_web_test_suite(
name = "compiler_web",
deps = [
":compiler_lib",
],
)

View File

@ -0,0 +1,69 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* 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 {getCompilerFacade, JitCompilerUsage} from '../../src/compiler/compiler_facade';
import {CompilerFacade, ExportedCompilerFacade} from '../../src/compiler/compiler_facade_interface';
import {global} from '../../src/util/global';
describe('getCompilerFacade', () => {
describe('errors', () => {
beforeEach(clearCompilerFacade);
afterEach(restoreCompilerFacade);
it('reports an error when requested for a decorator', () => {
try {
getCompilerFacade({usage: JitCompilerUsage.Decorator, kind: 'directive', type: TestClass});
fail('Error expected as compiler facade is not available');
} catch (e) {
expect(e.message).toEqual(
`The directive 'TestClass' needs to be compiled using the JIT compiler, but '@angular/compiler' is not available.
JIT compilation is discouraged for production use-cases! Consider using AOT mode instead.
Alternatively, the JIT compiler should be loaded by bootstrapping using '@angular/platform-browser-dynamic' or '@angular/platform-server',
or manually provide the compiler with 'import "@angular/compiler";' before bootstrapping.`);
}
});
it('reports an error when requested for a partial declaration', () => {
try {
getCompilerFacade(
{usage: JitCompilerUsage.PartialDeclaration, kind: 'directive', type: TestClass});
fail('Error expected as compiler facade is not available');
} catch (e) {
expect(e.message).toEqual(
`The directive 'TestClass' needs to be compiled using the JIT compiler, but '@angular/compiler' is not available.
The directive is part of a library that has been partially compiled.
However, the Angular Linker has not processed the library such that JIT compilation is used as fallback.
Ideally, the library is processed using the Angular Linker to become fully AOT compiled.
Alternatively, the JIT compiler should be loaded by bootstrapping using '@angular/platform-browser-dynamic' or '@angular/platform-server',
or manually provide the compiler with 'import "@angular/compiler";' before bootstrapping.`);
}
});
});
});
class TestClass {}
let ɵcompilerFacade: CompilerFacade|null = null;
function clearCompilerFacade() {
const ng: ExportedCompilerFacade = global.ng;
ɵcompilerFacade = ng.ɵcompilerFacade;
ng.ɵcompilerFacade = undefined!;
}
function restoreCompilerFacade() {
if (ɵcompilerFacade === null) {
return;
}
const ng: ExportedCompilerFacade = global.ng;
ng.ɵcompilerFacade = ɵcompilerFacade;
ɵcompilerFacade = null;
}