diff --git a/packages/schematics/angular/component/files/__name@dasherize@if-flat__/__name@dasherize__.__type@dasherize__.ts.template b/packages/schematics/angular/component/files/__name@dasherize@if-flat__/__name@dasherize__.__type@dasherize__.ts.template index 442a76f98278..761920833dd8 100644 --- a/packages/schematics/angular/component/files/__name@dasherize@if-flat__/__name@dasherize__.__type@dasherize__.ts.template +++ b/packages/schematics/angular/component/files/__name@dasherize@if-flat__/__name@dasherize__.__type@dasherize__.ts.template @@ -1,6 +1,7 @@ import { Component, OnInit<% if(!!viewEncapsulation) { %>, ViewEncapsulation<% }%><% if(changeDetection !== 'Default') { %>, ChangeDetectionStrategy<% }%> } from '@angular/core'; -@Component({<% if(!skipSelector) {%> +@Component({<% if (standalone) {%> + standalone: true,<%}%><% if(!skipSelector) {%> selector: '<%= selector %>',<%}%><% if(inlineTemplate) { %> template: `
diff --git a/packages/schematics/angular/component/index_spec.ts b/packages/schematics/angular/component/index_spec.ts index 14235575b3b0..6b83137d9e0b 100644 --- a/packages/schematics/angular/component/index_spec.ts +++ b/packages/schematics/angular/component/index_spec.ts @@ -119,6 +119,41 @@ describe('Component Schematic', () => { ); }); + it('should create a standalone component', async () => { + const options = { ...defaultOptions, standalone: true }; + + const fooModule = '/projects/bar/src/app/foo/foo.module.ts'; + appTree.create( + fooModule, + ` + import { NgModule } from '@angular/core'; + + @NgModule({ + imports: [], + declarations: [] + }) + export class FooModule { } + `, + ); + + const tree = await schematicRunner.runSchematicAsync('component', options, appTree).toPromise(); + const files = tree.files; + expect(files).toEqual( + jasmine.arrayContaining([ + '/projects/bar/src/app/foo/foo.component.css', + '/projects/bar/src/app/foo/foo.component.html', + '/projects/bar/src/app/foo/foo.component.spec.ts', + '/projects/bar/src/app/foo/foo.component.ts', + ]), + ); + + const fooComponentContent = tree.readContent('/projects/bar/src/app/foo/foo.component.ts'); + expect(fooComponentContent).toContain('standalone: true,'); + + const fooModuleContent = tree.readContent(fooModule); + expect(fooModuleContent).not.toContain('FooComponent'); + }); + it('should find the closest module', async () => { const options = { ...defaultOptions }; const fooModule = '/projects/bar/src/app/foo/foo.module.ts'; diff --git a/packages/schematics/angular/component/schema.json b/packages/schematics/angular/component/schema.json index 115185cf9cb6..6c8edde23b69 100644 --- a/packages/schematics/angular/component/schema.json +++ b/packages/schematics/angular/component/schema.json @@ -48,6 +48,13 @@ "alias": "t", "x-user-analytics": 10 }, + "standalone": { + "description": "Generate a standalone component", + "type": "boolean", + "default": false, + "alias": "sa", + "x-user-analytics": 100 + }, "viewEncapsulation": { "description": "The view encapsulation strategy to use in the new component.", "enum": ["Emulated", "None", "ShadowDom"], diff --git a/packages/schematics/angular/utility/find-module.ts b/packages/schematics/angular/utility/find-module.ts index a420f07eb052..24a1e2c466b7 100644 --- a/packages/schematics/angular/utility/find-module.ts +++ b/packages/schematics/angular/utility/find-module.ts @@ -17,6 +17,7 @@ export interface ModuleOptions { skipImport?: boolean; moduleExt?: string; routingModuleExt?: string; + standalone?: boolean; } export const MODULE_EXT = '.module.ts'; @@ -31,6 +32,11 @@ export function findModuleFromOptions(host: Tree, options: ModuleOptions): Path return undefined; } + // eslint-disable-next-line no-prototype-builtins + if (options.hasOwnProperty('standalone') && options.standalone) { + return undefined; + } + const moduleExt = options.moduleExt || MODULE_EXT; const routingModuleExt = options.routingModuleExt || ROUTING_MODULE_EXT;