feat(compiler-cli): propagate standalone flag to runtime (#44973)

This commit carries the `standalone` flag forward from a directive/pipe
into its generated directive/pipe definition, allowing the runtime to
recognize standalone entities.

PR Close #44973
This commit is contained in:
Alex Rickabaugh 2022-03-22 15:25:13 -07:00 committed by Dylan Hunn
parent 6f653e05f9
commit 2142ffd295
5 changed files with 64 additions and 2 deletions

View file

@ -45,7 +45,9 @@ runInEachFileSystem(() => {
export class TestCmp {}
`);
env.driveMain();
expect(env.getContents('test.js')).toContain('directives: [TestDir]');
const jsCode = env.getContents('test.js');
expect(jsCode).toContain('directives: [TestDir]');
expect(jsCode).toContain('standalone: true');
});
it('should error when a non-standalone component tries to use imports', () => {
@ -397,5 +399,35 @@ runInEachFileSystem(() => {
.toEqual('imports: [TestDir]');
});
});
describe('other types', () => {
it('should compile a basic standalone directive', () => {
env.write('test.ts', `
import {Directive} from '@angular/core';
@Directive({
selector: '[dir]',
standalone: true,
})
export class TestDir {}
`);
env.driveMain();
expect(env.getContents('test.js')).toContain('standalone: true');
});
it('should compile a basic standalone pipe', () => {
env.write('test.ts', `
import {Pipe} from '@angular/core';
@Pipe({
name: 'testpipe',
standalone: true,
})
export class TestPipe {}
`);
env.driveMain();
expect(env.getContents('test.js')).toContain('standalone: true');
});
});
});
});

View file

@ -69,6 +69,10 @@ export function compilePipeFromMetadata(metadata: R3PipeMetadata): R3CompiledExp
// e.g. `pure: true`
definitionMapValues.push({key: 'pure', value: o.literal(metadata.pure), quoted: false});
if (metadata.isStandalone) {
definitionMapValues.push({key: 'standalone', value: o.literal(true), quoted: false});
}
const expression =
o.importExpr(R3.definePipe).callFn([o.literalMap(definitionMapValues)], undefined, true);
const type = createPipeType(metadata);

View file

@ -77,6 +77,10 @@ function baseDirectiveFields(
definitionMap.set('exportAs', o.literalArr(meta.exportAs.map(e => o.literal(e))));
}
if (meta.isStandalone) {
definitionMap.set('standalone', o.literal(true));
}
return definitionMap;
}

View file

@ -284,6 +284,11 @@ export function ɵɵdefineComponent<T>(componentDefinition: {
* The set of schemas that declare elements to be allowed in the component's template.
*/
schemas?: SchemaMetadata[] | null;
/**
* Whether this directive/component is standalone.
*/
standalone?: boolean;
}): unknown {
return noSideEffects(() => {
// Initialize ngDevMode. This must be the first statement in ɵɵdefineComponent.
@ -312,6 +317,7 @@ export function ɵɵdefineComponent<T>(componentDefinition: {
onPush: componentDefinition.changeDetection === ChangeDetectionStrategy.OnPush,
directiveDefs: null!, // assigned in noSideEffects
pipeDefs: null!, // assigned in noSideEffects
standalone: componentDefinition.standalone === true,
selectors: componentDefinition.selectors || EMPTY_ARRAY,
viewQuery: componentDefinition.viewQuery || null,
features: componentDefinition.features as DirectiveDefFeature[] || null,
@ -709,13 +715,19 @@ export function ɵɵdefinePipe<T>(pipeDef: {
type: Type<T>,
/** Whether the pipe is pure. */
pure?: boolean
pure?: boolean,
/**
* Whether the pipe is standalone.
*/
standalone?: boolean,
}): unknown {
return (<PipeDef<T>>{
type: pipeDef.type,
name: pipeDef.name,
factory: null,
pure: pipeDef.pure !== false,
standalone: pipeDef.standalone === true,
onDestroy: pipeDef.type.prototype.ngOnDestroy || null
});
}

View file

@ -189,6 +189,11 @@ export interface DirectiveDef<T> {
*/
readonly exportAs: string[]|null;
/**
* Whether this directive (or component) is standalone.
*/
readonly standalone: boolean;
/**
* Factory function used to create a new directive instance. Will be null initially.
* Populated when the factory is first requested by directive instantiation logic.
@ -355,6 +360,11 @@ export interface PipeDef<T> {
*/
readonly pure: boolean;
/**
* Whether this pipe is standalone.
*/
readonly standalone: boolean;
/* The following are lifecycle hooks for this pipe */
onDestroy: (() => void)|null;
}