diff --git a/packages/core/src/render3/jit/directive.ts b/packages/core/src/render3/jit/directive.ts index 358cf80f183..dadc5978232 100644 --- a/packages/core/src/render3/jit/directive.ts +++ b/packages/core/src/render3/jit/directive.ts @@ -91,6 +91,13 @@ export function compileComponent(type: Type, metadata: Component): void { type: type, }); + if (metadata.foreignImports !== undefined) { + throw new Error( + `Foreign components are not supported in JIT mode. ` + + `Component '${type.name}' cannot specify 'foreignImports'.`, + ); + } + if (componentNeedsResolution(metadata)) { const error = [`Component '${type.name}' is not resolved:`]; if (metadata.templateUrl) { diff --git a/packages/core/src/render3/jit/util.ts b/packages/core/src/render3/jit/util.ts index 596e0a067a0..d0416cc2700 100644 --- a/packages/core/src/render3/jit/util.ts +++ b/packages/core/src/render3/jit/util.ts @@ -8,12 +8,17 @@ import {isForwardRef, resolveForwardRef} from '../../di/forward_ref'; import {ModuleWithProviders} from '../../di/interface/provider'; +import {ForeignComponent, RENDER} from '../../interface/foreign_component'; import {Type} from '../../interface/type'; import {NgModuleDef} from '../../metadata/ng_module_def'; import {getComponentDef, getDirectiveDef, getPipeDef, getNgModuleDef} from '../def_getters'; import type {ComponentType, DirectiveType, PipeType} from '../interfaces/definition'; import {stringifyForError} from '../util/stringify_utils'; +export function isForeignComponent(value: any): value is ForeignComponent { + return typeof value === 'object' && value !== null && RENDER in value; +} + export function isModuleWithProviders(value: any): value is ModuleWithProviders<{}> { return (value as {ngModule?: any}).ngModule !== undefined; } @@ -75,6 +80,12 @@ export function verifyStandaloneImport(depType: Type, importingType: Ty importingType, )}". Modules with providers are not supported in standalone components imports.`, ); + } else if (isForeignComponent(depType)) { + throw new Error( + `A foreign component, imported from "${stringifyForError( + importingType, + )}", cannot be imported using 'imports'. Foreign components are only supported in AOT mode and must be registered in 'foreignImports'.`, + ); } else { throw new Error( `The "${stringifyForError(depType)}" type, imported from "${stringifyForError( diff --git a/packages/core/test/render3/ivy/jit_spec.ts b/packages/core/test/render3/ivy/jit_spec.ts index 6115dac9bbd..b40f3aad1d0 100644 --- a/packages/core/test/render3/ivy/jit_spec.ts +++ b/packages/core/test/render3/ivy/jit_spec.ts @@ -31,6 +31,7 @@ import {ɵɵdefineInjectable, ɵɵInjectorDef} from '../../../src/di/interface/d import {FactoryFn} from '../../../src/render3/definition_factory'; import {ComponentDef, PipeDef} from '../../../src/render3/interfaces/definition'; import {InputFlags} from '../../../src/render3/interfaces/input_flags'; +import {foreignImport} from '../../../src/render3/foreign_import'; describe('render3 jit', () => { let injector: any; @@ -546,6 +547,52 @@ describe('render3 jit', () => { ); }); }); + + describe('foreign components', () => { + function fooImport(component: (props: TProps) => Node[]) { + return foreignImport( + (props) => [component(props)], + () => {}, + (producer) => producer(), + ); + } + + function FooComponent(props: {children?: Node[]}): Node[] { + return []; + } + + it('should error when foreignImports is specified on a component in JIT mode', () => { + expect(() => { + @Component({ + selector: 'test-cmp', + template: 'test', + // @ts-ignore + foreignImports: [fooImport(FooComponent)], + }) + class SomeCmp {} + + const _ = (SomeCmp as any).ɵcmp; + }).toThrowError( + `Foreign components are not supported in JIT mode. Component 'SomeCmp' cannot specify 'foreignImports'.`, + ); + }); + + it('should error when a foreign component is imported via imports array in JIT mode', () => { + @Component({ + selector: 'test-cmp', + template: 'test', + imports: [fooImport(FooComponent) as any], + }) + class SomeCmp {} + + const cmpDef = (SomeCmp as any).ɵcmp as ComponentDef; + expect(() => { + (cmpDef.directiveDefs! as () => unknown)(); + }).toThrowError( + /A foreign component, imported from "SomeCmp", cannot be imported using 'imports'\. Foreign components are only supported in AOT mode and must be registered in 'foreignImports'\./, + ); + }); + }); }); it('ensure at least one spec exists', () => {});