From b08ced1893c894d869e64e513a6181e0af4eabe1 Mon Sep 17 00:00:00 2001 From: Alan Agius Date: Tue, 25 Apr 2023 06:42:28 +0000 Subject: [PATCH] fix(@schematics/angular): add standalone option to library library This commit fixes an issue were libraries could not be created with standalone APIs. Standalone libraries do not have an an NgModule. When consumed users need to import the needed components, pipes, and directives. It is also recommended not to avoid grouping exports as this typically indicates bad architecture and may also hinder tree-shaking. **Don't** ```ts export const COMPONENTS = [ FooComponent, BarComponent, ] ``` **Do** ```ts export { FooComponent } from './foo/foo.component'; export { BarComponent } from './bar/bar.component'; ``` --- .../files/src/__entryFile__.ts.template | 4 +- packages/schematics/angular/library/index.ts | 17 ++++--- .../schematics/angular/library/index_spec.ts | 47 +++++++++++++++++++ .../schematics/angular/library/schema.json | 6 +++ .../tests/generate/library/library-basic.ts | 9 ++++ .../generate/library/library-standalone.ts | 9 ++++ 6 files changed, 83 insertions(+), 9 deletions(-) create mode 100644 tests/legacy-cli/e2e/tests/generate/library/library-basic.ts create mode 100644 tests/legacy-cli/e2e/tests/generate/library/library-standalone.ts diff --git a/packages/schematics/angular/library/files/src/__entryFile__.ts.template b/packages/schematics/angular/library/files/src/__entryFile__.ts.template index b4d46cdc0330..d88dc4f34551 100644 --- a/packages/schematics/angular/library/files/src/__entryFile__.ts.template +++ b/packages/schematics/angular/library/files/src/__entryFile__.ts.template @@ -3,5 +3,5 @@ */ export * from './lib/<%= dasherize(name) %>.service'; -export * from './lib/<%= dasherize(name) %>.component'; -export * from './lib/<%= dasherize(name) %>.module'; +export * from './lib/<%= dasherize(name) %>.component';<% if (!standalone) { %> +export * from './lib/<%= dasherize(name) %>.module';<% } %> diff --git a/packages/schematics/angular/library/index.ts b/packages/schematics/angular/library/index.ts index 9101741bdbfd..ffe13689ac80 100644 --- a/packages/schematics/angular/library/index.ts +++ b/packages/schematics/angular/library/index.ts @@ -165,13 +165,15 @@ export default function (options: LibraryOptions): Rule { addLibToWorkspaceFile(options, libDir, packageName), options.skipPackageJson ? noop() : addDependenciesToPackageJson(), options.skipTsConfig ? noop() : updateTsConfig(packageName, distRoot), - schematic('module', { - name: options.name, - commonModule: false, - flat: true, - path: sourceDir, - project: packageName, - }), + options.standalone + ? noop() + : schematic('module', { + name: options.name, + commonModule: false, + flat: true, + path: sourceDir, + project: packageName, + }), schematic('component', { name: options.name, selector: `${prefix}-${options.name}`, @@ -180,6 +182,7 @@ export default function (options: LibraryOptions): Rule { flat: true, path: sourceDir, export: true, + standalone: options.standalone, project: packageName, }), schematic('service', { diff --git a/packages/schematics/angular/library/index_spec.ts b/packages/schematics/angular/library/index_spec.ts index 31eea5d84afc..dcfa251de67b 100644 --- a/packages/schematics/angular/library/index_spec.ts +++ b/packages/schematics/angular/library/index_spec.ts @@ -390,4 +390,51 @@ describe('Library Schematic', () => { '@angular-devkit/build-angular:ng-packagr', ); }); + + describe('standalone', () => { + const defaultStandaloneOptions = { ...defaultOptions, standalone: true }; + + it('should create correct files', async () => { + const tree = await schematicRunner.runSchematic( + 'library', + defaultStandaloneOptions, + workspaceTree, + ); + + const files = tree.files; + expect(files).toEqual( + jasmine.arrayContaining([ + '/projects/foo/ng-package.json', + '/projects/foo/package.json', + '/projects/foo/README.md', + '/projects/foo/tsconfig.lib.json', + '/projects/foo/tsconfig.lib.prod.json', + '/projects/foo/src/my-index.ts', + '/projects/foo/src/lib/foo.component.spec.ts', + '/projects/foo/src/lib/foo.component.ts', + '/projects/foo/src/lib/foo.service.spec.ts', + '/projects/foo/src/lib/foo.service.ts', + ]), + ); + }); + + it('should not add reference to module file in entry-file', async () => { + const tree = await schematicRunner.runSchematic( + 'library', + defaultStandaloneOptions, + workspaceTree, + ); + expect(tree.readContent('/projects/foo/src/my-index.ts')).not.toContain('foo.module'); + }); + + it('should create a standalone component', async () => { + const tree = await schematicRunner.runSchematic( + 'library', + defaultStandaloneOptions, + workspaceTree, + ); + const componentContent = tree.readContent('/projects/foo/src/lib/foo.component.ts'); + expect(componentContent).toContain('standalone: true'); + }); + }); }); diff --git a/packages/schematics/angular/library/schema.json b/packages/schematics/angular/library/schema.json index 95c97f1732d4..4d6638f04937 100644 --- a/packages/schematics/angular/library/schema.json +++ b/packages/schematics/angular/library/schema.json @@ -47,6 +47,12 @@ "projectRoot": { "type": "string", "description": "The root directory of the new library." + }, + "standalone": { + "description": "Creates a library based upon the standalone API, without NgModules.", + "type": "boolean", + "default": false, + "x-user-analytics": "ep.ng_standalone" } }, "required": ["name"] diff --git a/tests/legacy-cli/e2e/tests/generate/library/library-basic.ts b/tests/legacy-cli/e2e/tests/generate/library/library-basic.ts new file mode 100644 index 000000000000..efc74694ea00 --- /dev/null +++ b/tests/legacy-cli/e2e/tests/generate/library/library-basic.ts @@ -0,0 +1,9 @@ +import { ng } from '../../../utils/process'; +import { useCIChrome } from '../../../utils/project'; + +export default async function () { + await ng('generate', 'library', 'lib-ngmodule', '--no-standalone'); + await useCIChrome('lib-ngmodule', 'projects/lib-ngmodule'); + await ng('test', 'lib-ngmodule', '--no-watch'); + await ng('build', 'lib-ngmodule'); +} diff --git a/tests/legacy-cli/e2e/tests/generate/library/library-standalone.ts b/tests/legacy-cli/e2e/tests/generate/library/library-standalone.ts new file mode 100644 index 000000000000..0b9754644bf5 --- /dev/null +++ b/tests/legacy-cli/e2e/tests/generate/library/library-standalone.ts @@ -0,0 +1,9 @@ +import { ng } from '../../../utils/process'; +import { useCIChrome } from '../../../utils/project'; + +export default async function () { + await ng('generate', 'library', 'lib-standalone', '--standalone'); + await useCIChrome('lib-standalone', 'projects/lib-standalone'); + await ng('test', 'lib-standalone', '--no-watch'); + await ng('build', 'lib-standalone'); +}