Skip to content

Commit

Permalink
feat(schematics): adapt lazy-components for projects (#437)
Browse files Browse the repository at this point in the history
Co-authored-by: MKless <mkless@intershop.de>
  • Loading branch information
dhhyi and MKless authored Nov 16, 2020
1 parent ab733d1 commit 18a3f2f
Show file tree
Hide file tree
Showing 10 changed files with 162 additions and 55 deletions.
13 changes: 13 additions & 0 deletions e2e/test-schematics.sh
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,19 @@ stat src/app/shared/cms/components/audio/audio.component.ts
grep "AudioComponent" src/app/shared/cms/cms.module.ts
grep "AudioComponent" src/app/shared/shared.module.ts

npx ng g lazy-component --project organization-management --path projects/organization-management/src/app/components/user-profile-form/user-profile-form.component.ts
stat projects/organization-management/src/app/exports/lazy-user-profile-form/lazy-user-profile-form.component.ts
stat projects/organization-management/src/app/exports/lazy-user-profile-form/lazy-user-profile-form.component.html
stat projects/organization-management/src/app/exports/organization-management-exports.module.ts
grep "LazyUserProfileFormComponent" projects/organization-management/src/app/exports/organization-management-exports.module.ts
grep "LazyUserProfileFormComponent" projects/organization-management/src/app/exports/index.ts

npx ng g lazy-component --project organization-management --path projects/organization-management/src/app/components/user-roles-selection/user-roles-selection.component.ts
stat projects/organization-management/src/app/exports/lazy-user-roles-selection/lazy-user-roles-selection.component.ts
stat projects/organization-management/src/app/exports/lazy-user-roles-selection/lazy-user-roles-selection.component.html
grep "LazyUserRolesSelectionComponent" projects/organization-management/src/app/exports/organization-management-exports.module.ts
grep "LazyUserRolesSelectionComponent" projects/organization-management/src/app/exports/index.ts

npm run lint

node schematics/customization/add custom
Expand Down
36 changes: 18 additions & 18 deletions schematics/src/helpers/customized-copy/factory_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,24 +102,24 @@ export class DummyTwoComponent {}
.runSchematicAsync('customized-copy', { project: 'bar', from: 'foo/dummy' }, appTree)
.toPromise();

expect(appTree.files.filter(x => x.includes('/src/app/'))).toMatchInlineSnapshot(`
expect(appTree.files.filter(x => x.includes('/src/app/')).sort()).toMatchInlineSnapshot(`
Array [
"/src/app/app-routing.module.ts",
"/src/app/app.module.ts",
"/src/app/app.component.css",
"/src/app/app.component.html",
"/src/app/app.component.spec.ts",
"/src/app/app.component.ts",
"/src/app/shared/shared.module.ts",
"/src/app/shared/dummy-two/dummy-two.component.html",
"/src/app/shared/dummy-two/dummy-two.component.spec.ts",
"/src/app/shared/dummy-two/dummy-two.component.ts",
"/src/app/foo/dummy/dummy.component.html",
"/src/app/foo/dummy/dummy.component.spec.ts",
"/src/app/foo/dummy/dummy.component.ts",
"/src/app/app.module.ts",
"/src/app/foo/custom-dummy/custom-dummy.component.html",
"/src/app/foo/custom-dummy/custom-dummy.component.spec.ts",
"/src/app/foo/custom-dummy/custom-dummy.component.ts",
"/src/app/foo/dummy/dummy.component.html",
"/src/app/foo/dummy/dummy.component.spec.ts",
"/src/app/foo/dummy/dummy.component.ts",
"/src/app/shared/dummy-two/dummy-two.component.html",
"/src/app/shared/dummy-two/dummy-two.component.spec.ts",
"/src/app/shared/dummy-two/dummy-two.component.ts",
"/src/app/shared/shared.module.ts",
]
`);

Expand Down Expand Up @@ -171,24 +171,24 @@ export class DummyTwoComponent {}
.runSchematicAsync('customized-copy', { project: 'bar', from: 'shared/dummy-two' }, appTree)
.toPromise();

expect(appTree.files.filter(x => x.includes('/src/app/'))).toMatchInlineSnapshot(`
expect(appTree.files.filter(x => x.includes('/src/app/')).sort()).toMatchInlineSnapshot(`
Array [
"/src/app/app-routing.module.ts",
"/src/app/app.module.ts",
"/src/app/app.component.css",
"/src/app/app.component.html",
"/src/app/app.component.spec.ts",
"/src/app/app.component.ts",
"/src/app/shared/shared.module.ts",
"/src/app/shared/dummy-two/dummy-two.component.html",
"/src/app/shared/dummy-two/dummy-two.component.spec.ts",
"/src/app/shared/dummy-two/dummy-two.component.ts",
"/src/app/shared/custom-dummy-two/custom-dummy-two.component.html",
"/src/app/shared/custom-dummy-two/custom-dummy-two.component.spec.ts",
"/src/app/shared/custom-dummy-two/custom-dummy-two.component.ts",
"/src/app/app.module.ts",
"/src/app/foo/dummy/dummy.component.html",
"/src/app/foo/dummy/dummy.component.spec.ts",
"/src/app/foo/dummy/dummy.component.ts",
"/src/app/shared/custom-dummy-two/custom-dummy-two.component.html",
"/src/app/shared/custom-dummy-two/custom-dummy-two.component.spec.ts",
"/src/app/shared/custom-dummy-two/custom-dummy-two.component.ts",
"/src/app/shared/dummy-two/dummy-two.component.html",
"/src/app/shared/dummy-two/dummy-two.component.spec.ts",
"/src/app/shared/dummy-two/dummy-two.component.ts",
"/src/app/shared/shared.module.ts",
]
`);

Expand Down
34 changes: 23 additions & 11 deletions schematics/src/helpers/lazy-components/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,32 @@ export function createLazyComponents(options: Options): Rule {
const project = workspace.projects.get(options.project);
const operations = [];

const fileVisitor = (file: string) => {
if (file.endsWith('.component.ts')) {
const componentContent = host.read(file).toString('utf-8');
if (componentContent.includes('@GenerateLazyComponent')) {
operations.push(schematic('lazy-component', { ...options, path: file.substring(1) }));
}
}
};

const extensionsRoot = `/${project.sourceRoot}/app/extensions`;
host.getDir(extensionsRoot).subdirs.forEach(extension => {
const sharedComponentFolder = `${extensionsRoot}/${extension}/shared`;
const extensionComponents = host.getDir(sharedComponentFolder).subdirs;

if (extensionComponents.length) {
host.getDir(sharedComponentFolder).visit(file => {
if (file.endsWith('.component.ts')) {
const componentContent = host.read(file).toString('utf-8');
if (componentContent.includes('@GenerateLazyComponent')) {
operations.push(schematic('lazy-component', { ...options, path: file.replace(/.*\/src\/app\//, '') }));
}
}
});
const components = host.getDir(sharedComponentFolder).subdirs;

if (components.length) {
host.getDir(sharedComponentFolder).visit(fileVisitor);
}
});

const projectsRoot = `/projects`;
host.getDir(projectsRoot).subdirs.forEach(projectName => {
const sharedComponentFolder = `${projectsRoot}/${projectName}/src/app/components`;
const components = host.getDir(sharedComponentFolder).subdirs;

if (components.length) {
host.getDir(sharedComponentFolder).visit(fileVisitor);
}
});

Expand Down
12 changes: 6 additions & 6 deletions schematics/src/helpers/move-component/factory_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,21 +60,21 @@ export class DummyTwoComponent {}
.runSchematicAsync('move-component', { project: 'bar', from: 'foo/dummy', to: 'foo' }, appTree)
.toPromise();

expect(appTree.files.filter(x => x.includes('/src/app/'))).toMatchInlineSnapshot(`
expect(appTree.files.filter(x => x.includes('/src/app/')).sort()).toMatchInlineSnapshot(`
Array [
"/src/app/app-routing.module.ts",
"/src/app/app.module.ts",
"/src/app/app.component.css",
"/src/app/app.component.html",
"/src/app/app.component.spec.ts",
"/src/app/app.component.ts",
"/src/app/shared/shared.module.ts",
"/src/app/shared/dummy-two/dummy-two.component.html",
"/src/app/shared/dummy-two/dummy-two.component.spec.ts",
"/src/app/shared/dummy-two/dummy-two.component.ts",
"/src/app/app.module.ts",
"/src/app/foo/foo.component.html",
"/src/app/foo/foo.component.spec.ts",
"/src/app/foo/foo.component.ts",
"/src/app/shared/dummy-two/dummy-two.component.html",
"/src/app/shared/dummy-two/dummy-two.component.spec.ts",
"/src/app/shared/dummy-two/dummy-two.component.ts",
"/src/app/shared/shared.module.ts",
]
`);
});
Expand Down
57 changes: 51 additions & 6 deletions schematics/src/lazy-component/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
forEach,
mergeWith,
move,
schematic,
url,
} from '@angular-devkit/schematics';
import { tsquery } from '@phenomnomnominal/tsquery';
Expand All @@ -16,7 +17,14 @@ import * as ts from 'typescript';

import { determineArtifactName, findDeclaringModule } from '../utils/common';
import { applyLintFix } from '../utils/lint-fix';
import { addDeclarationToNgModule, addDecoratorToClass, addExportToNgModule } from '../utils/registration';
import {
addDeclarationToNgModule,
addDecoratorToClass,
addExportToBarrelFile,
addExportToNgModule,
generateGitignore,
updateModule,
} from '../utils/registration';

import { PWALazyComponentOptionsSchema as Options } from './schema';

Expand All @@ -26,24 +34,30 @@ export function createLazyComponent(options: Options): Rule {
throw new SchematicsException('Option (project) is required.');
}
const workspace = await getWorkspace(host);
const project = workspace.projects.get(options.project);
const isProject = options.path.startsWith('projects/');
const projectName = isProject ? options.path.split('/')[1].trim() : '';
const project = workspace.projects.get(isProject ? options.path.split('/')[1] : options.project);

const originalPath = options.path.replace(/.*src\/app\//, '');
const componentPath = `/${project.sourceRoot}/app/${originalPath}`;

if (
!originalPath.endsWith('component.ts') ||
!originalPath.startsWith('extensions/') ||
!(originalPath.startsWith('extensions/') || isProject) ||
!host.exists(componentPath)
) {
throw new SchematicsException('path does not point to an existing component in an extension');
throw new SchematicsException('path does not point to an existing component in an extension or project');
}

const pathSplits = originalPath.split('/');
const extension = pathSplits[1];
const originalName = /\/([a-z0-9-]+)\.component\.ts/.exec(originalPath)[1];
options.name = 'lazy-' + originalName;
options.path = `${project.sourceRoot}/app/extensions/${extension}/exports`;
if (isProject) {
options.path = `${project.sourceRoot}/app/exports`;
} else {
options.path = `${project.sourceRoot}/app/extensions/${extension}/exports`;
}
options = findDeclaringModule(host, options);
options = determineArtifactName('component', host, options);

Expand Down Expand Up @@ -108,12 +122,40 @@ export function createLazyComponent(options: Options): Rule {
}
}
}
const exportsModuleName = `${isProject ? projectName : extension}-exports`;
const exportsModuleExists = host.exists(`/${options.path}/${exportsModuleName}.module.ts`);

const gitignoreExists = host.exists(`/${options.path}/.gitignore`);

const operations = [];

if (!options.ci) {
if (!exportsModuleExists) {
operations.push(
schematic('module', {
...options,
name: exportsModuleName,
flat: true,
})
);
operations.push(updateModule(options));
operations.push(
addExportToBarrelFile({
...options,
artifactName: strings.classify(`${exportsModuleName}-module`),
moduleImportPath: `/${options.path}/${exportsModuleName}.module`,
})
);
}
operations.push(addDeclarationToNgModule(options));
operations.push(addExportToNgModule(options));
if (!gitignoreExists) {
operations.push(generateGitignore({ ...options, content: '/lazy**' }));
}

if (isProject) {
operations.push(addExportToBarrelFile(options));
}
operations.push(
addDecoratorToClass(
componentPath,
Expand All @@ -133,11 +175,13 @@ export function createLazyComponent(options: Options): Rule {
bindings,
imports,
originalPath,
projectName,
extension,
originalName,
onChanges,
isProject,
}),
move(`/${project.sourceRoot}/app/extensions/${extension}/exports`),
move(options.path),
forEach(fileEntry => {
if (host.exists(fileEntry.path)) {
host.overwrite(fileEntry.path, fileEntry.content);
Expand All @@ -153,6 +197,7 @@ export function createLazyComponent(options: Options): Rule {

if (!options.ci) {
operations.push(applyLintFix());
operations.push(applyLintFix());
}

return chain(operations);
Expand Down
2 changes: 1 addition & 1 deletion schematics/src/lazy-component/factory_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ describe('Lazy Component Schematic', () => {
.toPromise()
.catch(error => error);

expect(err.message).toEqual('path does not point to an existing component in an extension');
expect(err.message).toMatch(/path does not point to an existing component/);
});

it.each(['extensions/ext/shared/dummy/dummy.component.ts', 'src/app/extensions/ext/shared/dummy/dummy.component.ts'])(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,19 @@ export class <%= classify(name) %>Component implements OnInit <% if (bindings.le
private component: ComponentRef<any>;<% } %>

constructor(
private featureToggleService: FeatureToggleService,
<% if(!isProject) { %> private featureToggleService: FeatureToggleService, <% } %>
private compiler: Compiler,
private injector: Injector
) {}

async ngOnInit() {
if (this.featureToggleService.enabled('<%= camelize(extension) %>')) {
<% if(!isProject) { %> if (this.featureToggleService.enabled('<%= camelize(extension) %>')) { <% } %>
// prevent cyclic dependency warnings
const extension = '<%= dasherize(extension) %>';
const extension = '<% if(isProject) { %><%= dasherize(projectName) %><% } else { %><%=dasherize(extension)%><% } %>';
const moduleObj = await import(`../../${extension}.module`);
const module = moduleObj[Object.keys(moduleObj)[0]];

const { <%= classify(originalName) %>Component } = await import('../../shared/<%= dasherize(originalName) %>/<%= dasherize(originalName) %>.component');
const { <%= classify(originalName) %>Component } = await import('../../<% if (isProject) { %>components<% } else { %>shared<% } %>/<%= dasherize(originalName) %>/<%= dasherize(originalName) %>.component');

const moduleFactory = await this.loadModuleFactory(module);
const moduleRef = moduleFactory.create(this.injector);
Expand All @@ -60,7 +60,7 @@ export class <%= classify(name) %>Component implements OnInit <% if (bindings.le
<% } else { %>
this.anchor.createComponent(factory).changeDetectorRef.markForCheck();
<% } %>
}
<% if(!isProject){ %> } <% } %>
}

<% if (bindings.length) { %>
Expand Down
6 changes: 3 additions & 3 deletions schematics/src/store/factory_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ describe('Store Schematic', () => {
const options = { ...defaultOptions };

const tree = await schematicRunner.runSchematicAsync('store', options, appTree).toPromise();
const files = tree.files.filter(x => x.search('foo') >= 0);
const files = tree.files.filter(x => x.search('foo') >= 0).sort();
expect(files).toMatchInlineSnapshot(`
Array [
"/src/app/core/store/core/foo/foo.actions.ts",
Expand Down Expand Up @@ -70,7 +70,7 @@ describe('Store Schematic', () => {
const options = { ...defaultOptions, feature: 'bar' };

const tree = await schematicRunner.runSchematicAsync('store', options, appTree).toPromise();
const files = tree.files.filter(x => x.search('foo') >= 0);
const files = tree.files.filter(x => x.search('foo') >= 0).sort();
expect(files).toMatchInlineSnapshot(`
Array [
"/src/app/core/store/bar/foo/foo.actions.ts",
Expand Down Expand Up @@ -102,7 +102,7 @@ describe('Store Schematic', () => {
const options = { ...defaultOptions, extension: 'feature' };

const tree = await schematicRunner.runSchematicAsync('store', options, appTree).toPromise();
const files = tree.files.filter(x => x.search('foo') >= 0);
const files = tree.files.filter(x => x.search('foo') >= 0).sort();
expect(files).toMatchInlineSnapshot(`
Array [
"/src/app/extensions/feature/store/foo/foo.actions.ts",
Expand Down
Loading

0 comments on commit 18a3f2f

Please sign in to comment.