fix(@schematics/angular): generate components without a .component extension/type

To align with the updated style guide, Angular v20 will generate components
without a `.component` file extension type for all component related
files by default. Projects will automatically use this naming convention.
Projects can however opt-out by setting the `type` option to `Component`
for the component schematic. This can be done as a default in the `angular.json`
or directly on the commandline via `--type=Component` when executing `ng generate`.
As an example, `app.component.css` will now be named `app.css`. Additionally,
the TypeScript class name will be `App` instead of the previous `AppComponent`.
This commit is contained in:
Charles Lyding 2025-03-10 11:56:47 -04:00 committed by Douglas Parker
parent f126f8d34b
commit 23fc8e1e17
94 changed files with 399 additions and 453 deletions

View File

@ -182,7 +182,7 @@ function addServerRoutes(options: AppShellOptions): Rule {
.filter((node) => node.kind === ts.SyntaxKind.ImportDeclaration) .filter((node) => node.kind === ts.SyntaxKind.ImportDeclaration)
.sort((a, b) => a.getStart() - b.getStart()); .sort((a, b) => a.getStart() - b.getStart());
const insertPosition = imports[imports.length - 1].getEnd(); const insertPosition = imports[imports.length - 1].getEnd();
const routeText = `\n\nconst routes: Routes = [ { path: '${APP_SHELL_ROUTE}', component: AppShellComponent }];`; const routeText = `\n\nconst routes: Routes = [ { path: '${APP_SHELL_ROUTE}', component: AppShell }];`;
recorder.insertRight(insertPosition, routeText); recorder.insertRight(insertPosition, routeText);
host.commitUpdate(recorder); host.commitUpdate(recorder);
} }
@ -262,7 +262,7 @@ function addStandaloneServerRoute(options: AppShellOptions): Rule {
multi: true, multi: true,
useValue: [{ useValue: [{
path: '${APP_SHELL_ROUTE}', path: '${APP_SHELL_ROUTE}',
component: AppShellComponent component: AppShell
}] }]
}\n `, }\n `,
]; ];
@ -270,12 +270,7 @@ function addStandaloneServerRoute(options: AppShellOptions): Rule {
recorder.insertRight(providersLiteral.getStart(), `[\n${updatedProvidersString.join(',\n')}]`); recorder.insertRight(providersLiteral.getStart(), `[\n${updatedProvidersString.join(',\n')}]`);
applyToUpdateRecorder(recorder, [ applyToUpdateRecorder(recorder, [
insertImport( insertImport(configSourceFile, configFilePath, 'AppShell', './app-shell/app-shell'),
configSourceFile,
configFilePath,
'AppShellComponent',
'./app-shell/app-shell.component',
),
]); ]);
host.commitUpdate(recorder); host.commitUpdate(recorder);
}; };
@ -315,16 +310,11 @@ function addServerRoutingConfig(options: AppShellOptions, isStandalone: boolean)
} }
recorder = host.beginUpdate(configFilePath); recorder = host.beginUpdate(configFilePath);
recorder.insertLeft(functionCall.end - 1, `, withAppShell(AppShellComponent)`); recorder.insertLeft(functionCall.end - 1, `, withAppShell(AppShell)`);
applyToUpdateRecorder(recorder, [ applyToUpdateRecorder(recorder, [
insertImport(configSourceFile, configFilePath, 'withAppShell', '@angular/ssr'), insertImport(configSourceFile, configFilePath, 'withAppShell', '@angular/ssr'),
insertImport( insertImport(configSourceFile, configFilePath, 'AppShell', './app-shell/app-shell'),
configSourceFile,
configFilePath,
'AppShellComponent',
'./app-shell/app-shell.component',
),
]); ]);
host.commitUpdate(recorder); host.commitUpdate(recorder);

View File

@ -82,14 +82,14 @@ describe('App Shell Schematic', () => {
it('should work if server config was added prior to running the app-shell schematic', async () => { it('should work if server config was added prior to running the app-shell schematic', async () => {
let tree = await schematicRunner.runSchematic('server', defaultOptions, appTree); let tree = await schematicRunner.runSchematic('server', defaultOptions, appTree);
tree = await schematicRunner.runSchematic('app-shell', defaultOptions, tree); tree = await schematicRunner.runSchematic('app-shell', defaultOptions, tree);
expect(tree.exists('/projects/bar/src/app/app-shell/app-shell.component.ts')).toBe(true); expect(tree.exists('/projects/bar/src/app/app-shell/app-shell.ts')).toBe(true);
}); });
it('should create the shell component', async () => { it('should create the shell component', async () => {
const tree = await schematicRunner.runSchematic('app-shell', defaultOptions, appTree); const tree = await schematicRunner.runSchematic('app-shell', defaultOptions, appTree);
expect(tree.exists('/projects/bar/src/app/app-shell/app-shell.component.ts')).toBe(true); expect(tree.exists('/projects/bar/src/app/app-shell/app-shell.ts')).toBe(true);
const content = tree.readContent('/projects/bar/src/app/app.module.server.ts'); const content = tree.readContent('/projects/bar/src/app/app.module.server.ts');
expect(content).toMatch(/app-shell\.component/); expect(content).toMatch(/app-shell/);
}); });
}); });
@ -117,27 +117,25 @@ describe('App Shell Schematic', () => {
it('should create the shell component', async () => { it('should create the shell component', async () => {
const tree = await schematicRunner.runSchematic('app-shell', defaultOptions, appTree); const tree = await schematicRunner.runSchematic('app-shell', defaultOptions, appTree);
expect(tree.exists('/projects/bar/src/app/app-shell/app-shell.component.ts')).toBe(true); expect(tree.exists('/projects/bar/src/app/app-shell/app-shell.ts')).toBe(true);
const content = tree.readContent('/projects/bar/src/app/app.config.server.ts'); const content = tree.readContent('/projects/bar/src/app/app.config.server.ts');
expect(content).toMatch(/app-shell\.component/); expect(content).toMatch(/app-shell/);
}); });
it(`should update the 'provideServerRouting' call to include 'withAppShell'`, async () => { it(`should update the 'provideServerRouting' call to include 'withAppShell'`, async () => {
const tree = await schematicRunner.runSchematic('app-shell', defaultOptions, appTree); const tree = await schematicRunner.runSchematic('app-shell', defaultOptions, appTree);
const content = tree.readContent('/projects/bar/src/app/app.config.server.ts'); const content = tree.readContent('/projects/bar/src/app/app.config.server.ts');
expect(tags.oneLine`${content}`).toContain( expect(tags.oneLine`${content}`).toContain(
tags.oneLine`provideServerRouting(serverRoutes, withAppShell(AppShellComponent))`, tags.oneLine`provideServerRouting(serverRoutes, withAppShell(AppShell))`,
); );
}); });
it(`should add import to 'AppShellComponent'`, async () => { it(`should add import to 'AppShell'`, async () => {
const tree = await schematicRunner.runSchematic('app-shell', defaultOptions, appTree); const tree = await schematicRunner.runSchematic('app-shell', defaultOptions, appTree);
const filePath = '/projects/bar/src/app/app.config.server.ts'; const filePath = '/projects/bar/src/app/app.config.server.ts';
const content = tree.readContent(filePath); const content = tree.readContent(filePath);
expect(content).toContain( expect(content).toContain(`import { AppShell } from './app-shell/app-shell';`);
`import { AppShellComponent } from './app-shell/app-shell.component';`,
);
}); });
}); });
}); });

View File

@ -2,17 +2,17 @@ import { NgModule<% if(experimentalZoneless) { %>, provideExperimentalZonelessCh
import { BrowserModule } from '@angular/platform-browser'; import { BrowserModule } from '@angular/platform-browser';
<% if (routing) { %> <% if (routing) { %>
import { AppRoutingModule } from './app-routing.module';<% } %> import { AppRoutingModule } from './app-routing.module';<% } %>
import { AppComponent } from './app.component'; import { App } from './app';
@NgModule({ @NgModule({
declarations: [ declarations: [
AppComponent App
], ],
imports: [ imports: [
BrowserModule<% if (routing) { %>, BrowserModule<% if (routing) { %>,
AppRoutingModule<% } %> AppRoutingModule<% } %>
], ],
providers: [<% if (experimentalZoneless) { %>provideExperimentalZonelessChangeDetection()<% } %>], providers: [<% if (experimentalZoneless) { %>provideExperimentalZonelessChangeDetection()<% } %>],
bootstrap: [AppComponent] bootstrap: [App]
}) })
export class AppModule { } export class AppModule { }

View File

@ -1,35 +1,35 @@
<% if(experimentalZoneless) { %>import { provideExperimentalZonelessChangeDetection } from '@angular/core'; <% if(experimentalZoneless) { %>import { provideExperimentalZonelessChangeDetection } from '@angular/core';
<% } %>import { TestBed } from '@angular/core/testing';<% if (routing) { %> <% } %>import { TestBed } from '@angular/core/testing';<% if (routing) { %>
import { RouterModule } from '@angular/router';<% } %> import { RouterModule } from '@angular/router';<% } %>
import { AppComponent } from './app.component'; import { App } from './app';
describe('AppComponent', () => { describe('App', () => {
beforeEach(async () => { beforeEach(async () => {
await TestBed.configureTestingModule({<% if (routing) { %> await TestBed.configureTestingModule({<% if (routing) { %>
imports: [ imports: [
RouterModule.forRoot([]) RouterModule.forRoot([])
],<% } %> ],<% } %>
declarations: [ declarations: [
AppComponent App
],<% if(experimentalZoneless) { %> ],<% if(experimentalZoneless) { %>
providers: [provideExperimentalZonelessChangeDetection()]<% } %> providers: [provideExperimentalZonelessChangeDetection()]<% } %>
}).compileComponents(); }).compileComponents();
}); });
it('should create the app', () => { it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent); const fixture = TestBed.createComponent(App);
const app = fixture.componentInstance; const app = fixture.componentInstance;
expect(app).toBeTruthy(); expect(app).toBeTruthy();
}); });
it(`should have as title '<%= name %>'`, () => { it(`should have as title '<%= name %>'`, () => {
const fixture = TestBed.createComponent(AppComponent); const fixture = TestBed.createComponent(App);
const app = fixture.componentInstance; const app = fixture.componentInstance;
expect(app.title).toEqual('<%= name %>'); expect(app.title).toEqual('<%= name %>');
}); });
it('should render title', () => { it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent); const fixture = TestBed.createComponent(App);
fixture.detectChanges(); fixture.detectChanges();
const compiled = fixture.nativeElement as HTMLElement; const compiled = fixture.nativeElement as HTMLElement;
expect(compiled.querySelector('h1')?.textContent).toContain('Hello, <%= name %>'); expect(compiled.querySelector('h1')?.textContent).toContain('Hello, <%= name %>');

View File

@ -9,11 +9,11 @@ import { Component } from '@angular/core';
%><router-outlet /><% %><router-outlet /><%
} %> } %>
`,<% } else { %> `,<% } else { %>
templateUrl: './app.component.ng.html',<% } %> templateUrl: './app.ng.html',<% } %>
standalone: false,<% if(inlineStyle) { %> standalone: false,<% if(inlineStyle) { %>
styles: []<% } else { %> styles: []<% } else { %>
styleUrl: './app.component.<%= style %>'<% } %> styleUrl: './app.<%= style %>'<% } %>
}) })
export class AppComponent { export class App {
title = '<%= name %>'; title = '<%= name %>';
} }

View File

@ -1,29 +1,29 @@
<% if(experimentalZoneless) { %>import { provideExperimentalZonelessChangeDetection } from '@angular/core'; <% if(experimentalZoneless) { %>import { provideExperimentalZonelessChangeDetection } from '@angular/core';
<% } %>import { TestBed } from '@angular/core/testing'; <% } %>import { TestBed } from '@angular/core/testing';
import { AppComponent } from './app.component'; import { App } from './app';
describe('AppComponent', () => { describe('App', () => {
beforeEach(async () => { beforeEach(async () => {
await TestBed.configureTestingModule({ await TestBed.configureTestingModule({
imports: [AppComponent],<% if(experimentalZoneless) { %> imports: [App],<% if(experimentalZoneless) { %>
providers: [provideExperimentalZonelessChangeDetection()]<% } %> providers: [provideExperimentalZonelessChangeDetection()]<% } %>
}).compileComponents(); }).compileComponents();
}); });
it('should create the app', () => { it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent); const fixture = TestBed.createComponent(App);
const app = fixture.componentInstance; const app = fixture.componentInstance;
expect(app).toBeTruthy(); expect(app).toBeTruthy();
}); });
it(`should have the '<%= name %>' title`, () => { it(`should have the '<%= name %>' title`, () => {
const fixture = TestBed.createComponent(AppComponent); const fixture = TestBed.createComponent(App);
const app = fixture.componentInstance; const app = fixture.componentInstance;
expect(app.title).toEqual('<%= name %>'); expect(app.title).toEqual('<%= name %>');
}); });
it('should render title', () => { it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent); const fixture = TestBed.createComponent(App);
fixture.detectChanges(); fixture.detectChanges();
const compiled = fixture.nativeElement as HTMLElement; const compiled = fixture.nativeElement as HTMLElement;
expect(compiled.querySelector('h1')?.textContent).toContain('Hello, <%= name %>'); expect(compiled.querySelector('h1')?.textContent).toContain('Hello, <%= name %>');

View File

@ -11,10 +11,10 @@ import { RouterOutlet } from '@angular/router';<% } %>
%><router-outlet /><% %><router-outlet /><%
} %> } %>
`,<% } else { %> `,<% } else { %>
templateUrl: './app.component.ng.html',<% } if(inlineStyle) { %> templateUrl: './app.ng.html',<% } if(inlineStyle) { %>
styles: [],<% } else { %> styles: [],<% } else { %>
styleUrl: './app.component.<%= style %>'<% } %> styleUrl: './app.<%= style %>'<% } %>
}) })
export class AppComponent { export class App {
title = '<%= name %>'; title = '<%= name %>';
} }

View File

@ -1,6 +1,6 @@
import { bootstrapApplication } from '@angular/platform-browser'; import { bootstrapApplication } from '@angular/platform-browser';
import { appConfig } from './app/app.config'; import { appConfig } from './app/app.config';
import { AppComponent } from './app/app.component'; import { App } from './app/app';
bootstrapApplication(AppComponent, appConfig) bootstrapApplication(App, appConfig)
.catch((err) => console.error(err)); .catch((err) => console.error(err));

View File

@ -55,10 +55,10 @@ describe('Application Schematic', () => {
'/projects/foo/src/main.ts', '/projects/foo/src/main.ts',
'/projects/foo/src/styles.css', '/projects/foo/src/styles.css',
'/projects/foo/src/app/app.module.ts', '/projects/foo/src/app/app.module.ts',
'/projects/foo/src/app/app.component.css', '/projects/foo/src/app/app.css',
'/projects/foo/src/app/app.component.ng.html', '/projects/foo/src/app/app.ng.html',
'/projects/foo/src/app/app.component.spec.ts', '/projects/foo/src/app/app.spec.ts',
'/projects/foo/src/app/app.component.ts', '/projects/foo/src/app/app.ts',
]), ]),
); );
}); });
@ -265,10 +265,10 @@ describe('Application Schematic', () => {
'/src/index.html', '/src/index.html',
'/src/main.ts', '/src/main.ts',
'/src/styles.css', '/src/styles.css',
'/src/app/app.component.css', '/src/app/app.css',
'/src/app/app.component.ng.html', '/src/app/app.ng.html',
'/src/app/app.component.spec.ts', '/src/app/app.spec.ts',
'/src/app/app.component.ts', '/src/app/app.ts',
]), ]),
); );
}); });
@ -446,9 +446,9 @@ describe('Application Schematic', () => {
const files = tree.files; const files = tree.files;
[ [
'/projects/foo/tsconfig.spec.json', '/projects/foo/tsconfig.spec.json',
'/projects/foo/src/app/app.component.css', '/projects/foo/src/app/app.css',
'/projects/foo/src/app/app.component.ng.html', '/projects/foo/src/app/app.ng.html',
'/projects/foo/src/app/app.component.spec.ts', '/projects/foo/src/app/app.spec.ts',
].forEach((x) => expect(files).not.toContain(x)); ].forEach((x) => expect(files).not.toContain(x));
expect(files).toEqual( expect(files).toEqual(
@ -458,7 +458,7 @@ describe('Application Schematic', () => {
'/projects/foo/src/index.html', '/projects/foo/src/index.html',
'/projects/foo/src/main.ts', '/projects/foo/src/main.ts',
'/projects/foo/src/styles.css', '/projects/foo/src/styles.css',
'/projects/foo/src/app/app.component.ts', '/projects/foo/src/app/app.ts',
]), ]),
); );
}); });
@ -472,8 +472,8 @@ describe('Application Schematic', () => {
'/projects/foo/tsconfig.spec.json', '/projects/foo/tsconfig.spec.json',
'/projects/foo/karma.conf.js', '/projects/foo/karma.conf.js',
'/projects/foo/src/test.ts', '/projects/foo/src/test.ts',
'/projects/foo/src/app/app.component.ng.html', '/projects/foo/src/app/app.ng.html',
'/projects/foo/src/app/app.component.spec.ts', '/projects/foo/src/app/app.spec.ts',
].forEach((x) => expect(files).not.toContain(x)); ].forEach((x) => expect(files).not.toContain(x));
expect(files).toEqual( expect(files).toEqual(
@ -483,8 +483,8 @@ describe('Application Schematic', () => {
'/projects/foo/src/index.html', '/projects/foo/src/index.html',
'/projects/foo/src/main.ts', '/projects/foo/src/main.ts',
'/projects/foo/src/styles.css', '/projects/foo/src/styles.css',
'/projects/foo/src/app/app.component.css', '/projects/foo/src/app/app.css',
'/projects/foo/src/app/app.component.ts', '/projects/foo/src/app/app.ts',
]), ]),
); );
}); });
@ -498,8 +498,8 @@ describe('Application Schematic', () => {
'/projects/foo/tsconfig.spec.json', '/projects/foo/tsconfig.spec.json',
'/projects/foo/karma.conf.js', '/projects/foo/karma.conf.js',
'/projects/foo/src/test.ts', '/projects/foo/src/test.ts',
'/projects/foo/src/app/app.component.css', '/projects/foo/src/app/app.css',
'/projects/foo/src/app/app.component.spec.ts', '/projects/foo/src/app/app.spec.ts',
].forEach((x) => expect(files).not.toContain(x)); ].forEach((x) => expect(files).not.toContain(x));
expect(files).toEqual( expect(files).toEqual(
@ -509,8 +509,8 @@ describe('Application Schematic', () => {
'/projects/foo/src/index.html', '/projects/foo/src/index.html',
'/projects/foo/src/main.ts', '/projects/foo/src/main.ts',
'/projects/foo/src/styles.css', '/projects/foo/src/styles.css',
'/projects/foo/src/app/app.component.ng.html', '/projects/foo/src/app/app.ng.html',
'/projects/foo/src/app/app.component.ts', '/projects/foo/src/app/app.ts',
]), ]),
); );
}); });
@ -530,10 +530,10 @@ describe('Application Schematic', () => {
'/projects/foo/src/main.ts', '/projects/foo/src/main.ts',
'/projects/foo/src/styles.css', '/projects/foo/src/styles.css',
'/projects/foo/src/app/app.config.ts', '/projects/foo/src/app/app.config.ts',
'/projects/foo/src/app/app.component.css', '/projects/foo/src/app/app.css',
'/projects/foo/src/app/app.component.ng.html', '/projects/foo/src/app/app.ng.html',
'/projects/foo/src/app/app.component.spec.ts', '/projects/foo/src/app/app.spec.ts',
'/projects/foo/src/app/app.component.ts', '/projects/foo/src/app/app.ts',
]), ]),
); );
}); });
@ -557,7 +557,7 @@ describe('Application Schematic', () => {
it('should create a standalone component', async () => { it('should create a standalone component', async () => {
const options = { ...defaultOptions, standalone: true }; const options = { ...defaultOptions, standalone: true };
const tree = await schematicRunner.runSchematic('application', options, workspaceTree); const tree = await schematicRunner.runSchematic('application', options, workspaceTree);
const component = tree.readContent('/projects/foo/src/app/app.component.ts'); const component = tree.readContent('/projects/foo/src/app/app.ts');
expect(component).not.toContain('standalone'); expect(component).not.toContain('standalone');
}); });
@ -569,7 +569,7 @@ describe('Application Schematic', () => {
expect(tree.files).toContain('/projects/foo/src/app/app.routes.ts'); expect(tree.files).toContain('/projects/foo/src/app/app.routes.ts');
const component = tree.readContent('/projects/foo/src/app/app.component.ts'); const component = tree.readContent('/projects/foo/src/app/app.ts');
expect(component).toContain(`import { RouterOutlet } from '@angular/router';`); expect(component).toContain(`import { RouterOutlet } from '@angular/router';`);
expect(component).toContain(`imports: [RouterOutlet]`); expect(component).toContain(`imports: [RouterOutlet]`);
@ -654,7 +654,7 @@ describe('Application Schematic', () => {
const path = '/projects/foo/src/app/app.module.ts'; const path = '/projects/foo/src/app/app.module.ts';
const content = tree.readContent(path); const content = tree.readContent(path);
expect(content).toMatch(/import { AppComponent } from '\.\/app\.component';/); expect(content).toMatch(/import { App } from '\.\/app';/);
}); });
it('should create all files of an application', async () => { it('should create all files of an application', async () => {
@ -671,10 +671,10 @@ describe('Application Schematic', () => {
'/projects/foo/src/styles.css', '/projects/foo/src/styles.css',
'/projects/foo/src/app/app-routing.module.ts', '/projects/foo/src/app/app-routing.module.ts',
'/projects/foo/src/app/app.module.ts', '/projects/foo/src/app/app.module.ts',
'/projects/foo/src/app/app.component.css', '/projects/foo/src/app/app.css',
'/projects/foo/src/app/app.component.ng.html', '/projects/foo/src/app/app.ng.html',
'/projects/foo/src/app/app.component.spec.ts', '/projects/foo/src/app/app.spec.ts',
'/projects/foo/src/app/app.component.ts', '/projects/foo/src/app/app.ts',
]), ]),
); );
}); });

View File

@ -55,6 +55,9 @@ export default function (options: ComponentOptions): Rule {
options.module = findModuleFromOptions(host, options); options.module = findModuleFromOptions(host, options);
// Schematic templates require a defined type value
options.type ??= '';
const parsedPath = parseName(options.path, options.name); const parsedPath = parseName(options.path, options.name);
options.name = parsedPath.name; options.name = parsedPath.name;
options.path = parsedPath.path; options.path = parsedPath.path;

View File

@ -93,8 +93,7 @@
}, },
"type": { "type": {
"type": "string", "type": "string",
"description": "Append a custom type to the component's filename. For example, if you set the type to `container`, the file will be named `my-component.container.ts`.", "description": "Append a custom type to the component's filename. For example, if you set the type to `container`, the file will be named `my-component.container.ts`."
"default": "Component"
}, },
"skipTests": { "skipTests": {
"type": "boolean", "type": "boolean",

View File

@ -3,5 +3,5 @@
*/ */
export * from './lib/<%= dasherize(name) %>.service'; export * from './lib/<%= dasherize(name) %>.service';
export * from './lib/<%= dasherize(name) %>.component';<% if (!standalone) { %> export * from './lib/<%= dasherize(name) %>';<% if (!standalone) { %>
export * from './lib/<%= dasherize(name) %>.module';<% } %> export * from './lib/<%= dasherize(name) %>.module';<% } %>

View File

@ -55,8 +55,8 @@ describe('Library Schematic', () => {
'/projects/foo/tsconfig.lib.json', '/projects/foo/tsconfig.lib.json',
'/projects/foo/tsconfig.lib.prod.json', '/projects/foo/tsconfig.lib.prod.json',
'/projects/foo/src/my-index.ts', '/projects/foo/src/my-index.ts',
'/projects/foo/src/lib/foo.component.spec.ts', '/projects/foo/src/lib/foo.spec.ts',
'/projects/foo/src/lib/foo.component.ts', '/projects/foo/src/lib/foo.ts',
'/projects/foo/src/lib/foo.service.spec.ts', '/projects/foo/src/lib/foo.service.spec.ts',
'/projects/foo/src/lib/foo.service.ts', '/projects/foo/src/lib/foo.service.ts',
]), ]),
@ -70,7 +70,7 @@ describe('Library Schematic', () => {
it('should create a standalone component', async () => { it('should create a standalone component', async () => {
const tree = await schematicRunner.runSchematic('library', defaultOptions, workspaceTree); const tree = await schematicRunner.runSchematic('library', defaultOptions, workspaceTree);
const componentContent = tree.readContent('/projects/foo/src/lib/foo.component.ts'); const componentContent = tree.readContent('/projects/foo/src/lib/foo.ts');
expect(componentContent).not.toContain('standalone'); expect(componentContent).not.toContain('standalone');
}); });
@ -100,8 +100,8 @@ describe('Library Schematic', () => {
'/some/other/directory/bar/tsconfig.lib.json', '/some/other/directory/bar/tsconfig.lib.json',
'/some/other/directory/bar/tsconfig.lib.prod.json', '/some/other/directory/bar/tsconfig.lib.prod.json',
'/some/other/directory/bar/src/my-index.ts', '/some/other/directory/bar/src/my-index.ts',
'/some/other/directory/bar/src/lib/foo.component.spec.ts', '/some/other/directory/bar/src/lib/foo.spec.ts',
'/some/other/directory/bar/src/lib/foo.component.ts', '/some/other/directory/bar/src/lib/foo.ts',
'/some/other/directory/bar/src/lib/foo.service.spec.ts', '/some/other/directory/bar/src/lib/foo.service.spec.ts',
'/some/other/directory/bar/src/lib/foo.service.ts', '/some/other/directory/bar/src/lib/foo.service.ts',
]), ]),
@ -310,7 +310,7 @@ describe('Library Schematic', () => {
project: 'foo', project: 'foo',
}; };
tree = await schematicRunner.runSchematic('component', componentOptions, tree); tree = await schematicRunner.runSchematic('component', componentOptions, tree);
expect(tree.exists('/projects/foo/src/lib/comp/comp.component.ts')).toBe(true); expect(tree.exists('/projects/foo/src/lib/comp/comp.ts')).toBe(true);
}); });
it(`should support creating scoped libraries`, async () => { it(`should support creating scoped libraries`, async () => {
@ -321,7 +321,7 @@ describe('Library Schematic', () => {
const pkgJsonPath = '/projects/myscope/mylib/package.json'; const pkgJsonPath = '/projects/myscope/mylib/package.json';
expect(tree.files).toContain(pkgJsonPath); expect(tree.files).toContain(pkgJsonPath);
expect(tree.files).toContain('/projects/myscope/mylib/src/lib/mylib.service.ts'); expect(tree.files).toContain('/projects/myscope/mylib/src/lib/mylib.service.ts');
expect(tree.files).toContain('/projects/myscope/mylib/src/lib/mylib.component.ts'); expect(tree.files).toContain('/projects/myscope/mylib/src/lib/mylib.ts');
const pkgJson = JSON.parse(tree.readContent(pkgJsonPath)); const pkgJson = JSON.parse(tree.readContent(pkgJsonPath));
expect(pkgJson.name).toEqual(scopedName); expect(pkgJson.name).toEqual(scopedName);
@ -409,7 +409,7 @@ describe('Library Schematic', () => {
); );
const fileContent = getFileContent(tree, '/projects/foo/src/lib/foo.module.ts'); const fileContent = getFileContent(tree, '/projects/foo/src/lib/foo.module.ts');
expect(fileContent).toMatch(/exports: \[\n(\s*) {2}FooComponent\n\1\]/); expect(fileContent).toMatch(/exports: \[\n(\s*) {2}Foo\n\1\]/);
}); });
it('should create files', async () => { it('should create files', async () => {
@ -429,8 +429,8 @@ describe('Library Schematic', () => {
'/projects/foo/tsconfig.lib.prod.json', '/projects/foo/tsconfig.lib.prod.json',
'/projects/foo/src/my-index.ts', '/projects/foo/src/my-index.ts',
'/projects/foo/src/lib/foo.module.ts', '/projects/foo/src/lib/foo.module.ts',
'/projects/foo/src/lib/foo.component.spec.ts', '/projects/foo/src/lib/foo.spec.ts',
'/projects/foo/src/lib/foo.component.ts', '/projects/foo/src/lib/foo.ts',
'/projects/foo/src/lib/foo.service.spec.ts', '/projects/foo/src/lib/foo.service.spec.ts',
'/projects/foo/src/lib/foo.service.ts', '/projects/foo/src/lib/foo.service.ts',
]), ]),

View File

@ -1,8 +1,8 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';<% if (lazyRoute) { %> import { RouterModule, Routes } from '@angular/router';<% if (lazyRoute) { %>
import { <%= classify(name) %>Component } from './<%= dasherize(name) %>.component';<% } %> import { <%= classify(name) %> } from './<%= dasherize(name) %>';<% } %>
const routes: Routes = [<% if (lazyRoute) { %>{ path: '', component: <%= classify(name) %>Component }<% } %>]; const routes: Routes = [<% if (lazyRoute) { %>{ path: '', component: <%= classify(name) %> }<% } %>];
@NgModule({ @NgModule({
imports: [RouterModule.for<%= routingScope %>(routes)], imports: [RouterModule.for<%= routingScope %>(routes)],

View File

@ -5,7 +5,7 @@ import { Routes, RouterModule } from '@angular/router';<% } %>
import { <%= classify(name) %>RoutingModule } from './<%= dasherize(name) %>-routing.module';<% } %> import { <%= classify(name) %>RoutingModule } from './<%= dasherize(name) %>-routing.module';<% } %>
<% if (lazyRouteWithoutRouteModule) { %> <% if (lazyRouteWithoutRouteModule) { %>
const routes: Routes = [ const routes: Routes = [
{ path: '', component: <%= classify(name) %>Component } { path: '', component: <%= classify(name) %> }
];<% } %> ];<% } %>
@NgModule({ @NgModule({

View File

@ -152,9 +152,9 @@ describe('Module Schematic', () => {
jasmine.arrayContaining([ jasmine.arrayContaining([
'/projects/bar/src/app/foo/foo.module.ts', '/projects/bar/src/app/foo/foo.module.ts',
'/projects/bar/src/app/foo/foo-routing.module.ts', '/projects/bar/src/app/foo/foo-routing.module.ts',
'/projects/bar/src/app/foo/foo.component.ts', '/projects/bar/src/app/foo/foo.ts',
'/projects/bar/src/app/foo/foo.component.ng.html', '/projects/bar/src/app/foo/foo.ng.html',
'/projects/bar/src/app/foo/foo.component.css', '/projects/bar/src/app/foo/foo.css',
]), ]),
); );
@ -170,7 +170,7 @@ describe('Module Schematic', () => {
); );
expect(fooRoutingModuleContent).toMatch(/RouterModule.forChild\(routes\)/); expect(fooRoutingModuleContent).toMatch(/RouterModule.forChild\(routes\)/);
expect(fooRoutingModuleContent).toMatch( expect(fooRoutingModuleContent).toMatch(
/const routes: Routes = \[\r?\n?\s*{ path: '', component: FooComponent }\r?\n?\s*\];/, /const routes: Routes = \[\r?\n?\s*{ path: '', component: Foo }\r?\n?\s*\];/,
); );
}); });
@ -179,7 +179,7 @@ describe('Module Schematic', () => {
'/projects/bar/src/app/app.module.ts', '/projects/bar/src/app/app.module.ts',
` `
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { AppComponent } from './app.component'; import { AppComponent } from './app';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -202,9 +202,9 @@ describe('Module Schematic', () => {
expect(files).toContain('/projects/bar/src/app/foo/foo.module.ts'); expect(files).toContain('/projects/bar/src/app/foo/foo.module.ts');
expect(files).not.toContain('/projects/bar/src/app/foo/foo-routing.module.ts'); expect(files).not.toContain('/projects/bar/src/app/foo/foo-routing.module.ts');
expect(files).toContain('/projects/bar/src/app/foo/foo.component.ts'); expect(files).toContain('/projects/bar/src/app/foo/foo.ts');
expect(files).toContain('/projects/bar/src/app/foo/foo.component.ng.html'); expect(files).toContain('/projects/bar/src/app/foo/foo.ng.html');
expect(files).toContain('/projects/bar/src/app/foo/foo.component.css'); expect(files).toContain('/projects/bar/src/app/foo/foo.css');
const appModuleContent = tree.readContent('/projects/bar/src/app/app.module.ts'); const appModuleContent = tree.readContent('/projects/bar/src/app/app.module.ts');
expect(appModuleContent).toMatch( expect(appModuleContent).toMatch(
@ -214,7 +214,7 @@ describe('Module Schematic', () => {
const fooModuleContent = tree.readContent('/projects/bar/src/app/foo/foo.module.ts'); const fooModuleContent = tree.readContent('/projects/bar/src/app/foo/foo.module.ts');
expect(fooModuleContent).toMatch(/RouterModule.forChild\(routes\)/); expect(fooModuleContent).toMatch(/RouterModule.forChild\(routes\)/);
expect(fooModuleContent).toMatch( expect(fooModuleContent).toMatch(
/const routes: Routes = \[\r?\n?\s*{ path: '', component: FooComponent }\r?\n?\s*\];/, /const routes: Routes = \[\r?\n?\s*{ path: '', component: Foo }\r?\n?\s*\];/,
); );
}); });
@ -230,9 +230,9 @@ describe('Module Schematic', () => {
jasmine.arrayContaining([ jasmine.arrayContaining([
'/projects/bar/src/app/foo.module.ts', '/projects/bar/src/app/foo.module.ts',
'/projects/bar/src/app/foo-routing.module.ts', '/projects/bar/src/app/foo-routing.module.ts',
'/projects/bar/src/app/foo.component.ts', '/projects/bar/src/app/foo.ts',
'/projects/bar/src/app/foo.component.ng.html', '/projects/bar/src/app/foo.ng.html',
'/projects/bar/src/app/foo.component.css', '/projects/bar/src/app/foo.css',
]), ]),
); );
@ -271,14 +271,14 @@ describe('Module Schematic', () => {
'/projects/bar/src/app/foo/foo.module.ts', '/projects/bar/src/app/foo/foo.module.ts',
'/projects/bar/src/app/bar/bar-routing.module.ts', '/projects/bar/src/app/bar/bar-routing.module.ts',
'/projects/bar/src/app/bar/bar.module.ts', '/projects/bar/src/app/bar/bar.module.ts',
'/projects/bar/src/app/bar/bar.component.ts', '/projects/bar/src/app/bar/bar.ts',
]), ]),
); );
const barRoutingModuleContent = tree.readContent( const barRoutingModuleContent = tree.readContent(
'/projects/bar/src/app/bar/bar-routing.module.ts', '/projects/bar/src/app/bar/bar-routing.module.ts',
); );
expect(barRoutingModuleContent).toContain(`path: '', component: BarComponent `); expect(barRoutingModuleContent).toContain(`path: '', component: Bar `);
const fooRoutingModuleContent = tree.readContent( const fooRoutingModuleContent = tree.readContent(
'/projects/bar/src/app/foo/foo-routing.module.ts', '/projects/bar/src/app/foo/foo-routing.module.ts',

View File

@ -58,7 +58,7 @@ describe('Ng New Schematic', () => {
); );
}); });
it('should should set the prefix in angular.json and in app.component.ts', async () => { it('should should set the prefix in angular.json and in app.ts', async () => {
const options = { ...defaultOptions, prefix: 'pre' }; const options = { ...defaultOptions, prefix: 'pre' };
const tree = await schematicRunner.runSchematic('ng-new', options); const tree = await schematicRunner.runSchematic('ng-new', options);
@ -75,7 +75,7 @@ describe('Ng New Schematic', () => {
const tree = await schematicRunner.runSchematic('ng-new', options); const tree = await schematicRunner.runSchematic('ng-new', options);
const moduleContent = tree.readContent('/foo/src/app/app.module.ts'); const moduleContent = tree.readContent('/foo/src/app/app.module.ts');
expect(moduleContent).toMatch(/declarations:\s*\[\s*AppComponent\s*\]/m); expect(moduleContent).toMatch(/declarations:\s*\[\s*App\s*\]/m);
}); });
it('createApplication=false should create an empty workspace', async () => { it('createApplication=false should create an empty workspace', async () => {

View File

@ -1,13 +1,13 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { ServerModule } from '@angular/platform-server'; import { ServerModule } from '@angular/platform-server';
import { provideServerRouting } from '@angular/ssr'; import { provideServerRouting } from '@angular/ssr';
import { AppComponent } from './app.component'; import { App } from './app';
import { AppModule } from './app.module'; import { AppModule } from './app.module';
import { serverRoutes } from './app.routes.server'; import { serverRoutes } from './app.routes.server';
@NgModule({ @NgModule({
imports: [AppModule, ServerModule], imports: [AppModule, ServerModule],
providers: [provideServerRouting(serverRoutes)], providers: [provideServerRouting(serverRoutes)],
bootstrap: [AppComponent], bootstrap: [App],
}) })
export class AppServerModule {} export class AppServerModule {}

View File

@ -1,7 +1,7 @@
import { bootstrapApplication } from '@angular/platform-browser'; import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component'; import { App } from './app/app';
import { config } from './app/app.config.server'; import { config } from './app/app.config.server';
const bootstrap = () => bootstrapApplication(AppComponent, config); const bootstrap = () => bootstrapApplication(App, config);
export default bootstrap; export default bootstrap;

View File

@ -2,13 +2,13 @@ import { NgModule } from '@angular/core';
import { ServerModule } from '@angular/platform-server'; import { ServerModule } from '@angular/platform-server';
import { AppModule } from './app.module'; import { AppModule } from './app.module';
import { AppComponent } from './app.component'; import { App } from './app';
@NgModule({ @NgModule({
imports: [ imports: [
AppModule, AppModule,
ServerModule, ServerModule,
], ],
bootstrap: [AppComponent], bootstrap: [App],
}) })
export class AppServerModule {} export class AppServerModule {}

View File

@ -1,7 +1,7 @@
import { bootstrapApplication } from '@angular/platform-browser'; import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component'; import { App } from './app/app';
import { config } from './app/app.config.server'; import { config } from './app/app.config.server';
const bootstrap = () => bootstrapApplication(AppComponent, config); const bootstrap = () => bootstrapApplication(App, config);
export default bootstrap; export default bootstrap;

View File

@ -124,7 +124,7 @@ describe('Server Schematic', () => {
const filePath = '/projects/bar/src/main.server.ts'; const filePath = '/projects/bar/src/main.server.ts';
expect(tree.exists(filePath)).toBeTrue(); expect(tree.exists(filePath)).toBeTrue();
const contents = tree.readContent(filePath); const contents = tree.readContent(filePath);
expect(contents).toContain(`bootstrapApplication(AppComponent, config)`); expect(contents).toContain(`bootstrapApplication(App, config)`);
}); });
it('should create server app config file', async () => { it('should create server app config file', async () => {

View File

@ -39,7 +39,7 @@ function addSnippet(options: WebWorkerOptions): Rule {
.getDir(options.path) .getDir(options.path)
.subfiles // Find all files that start with the same name, are ts files, .subfiles // Find all files that start with the same name, are ts files,
// and aren't spec or module files. // and aren't spec or module files.
.filter((f) => fileRegExp.test(f) && !/(module|spec)\.ts$/.test(f)) .filter((f) => fileRegExp.test(f) && !/(module|spec|config|routes)\.ts$/.test(f))
// Sort alphabetically for consistency. // Sort alphabetically for consistency.
.sort(); .sort();

View File

@ -70,7 +70,7 @@ describe('Web Worker Schematic', () => {
it('should add snippet to sibling file', async () => { it('should add snippet to sibling file', async () => {
const tree = await schematicRunner.runSchematic('web-worker', defaultOptions, appTree); const tree = await schematicRunner.runSchematic('web-worker', defaultOptions, appTree);
const appComponent = tree.readContent('/projects/bar/src/app/app.component.ts'); const appComponent = tree.readContent('/projects/bar/src/app/app.ts');
expect(appComponent).toContain(`new Worker(new URL('./${defaultOptions.name}.worker`); expect(appComponent).toContain(`new Worker(new URL('./${defaultOptions.name}.worker`);
expect(appComponent).toContain('console.log(`page got message: ${data}`)'); expect(appComponent).toContain('console.log(`page got message: ${data}`)');
}); });

View File

@ -8,5 +8,5 @@ import { ng } from '../../utils/process';
export default async function () { export default async function () {
await ng('build', '--aot=true', '--configuration=development'); await ng('build', '--aot=true', '--configuration=development');
const content = await readFile('dist/test-project/browser/main.js', 'utf-8'); const content = await readFile('dist/test-project/browser/main.js', 'utf-8');
assert.match(content, /AppComponent_Factory/); assert.match(content, /App_Factory/);
} }

View File

@ -7,7 +7,7 @@ import { ngServe } from '../../utils/project';
export default async function () { export default async function () {
const esbuild = getGlobalVariable('argv')['esbuild']; const esbuild = getGlobalVariable('argv')['esbuild'];
const validBundleRegEx = esbuild ? /sent to client/ : /Compiled successfully\./; const validBundleRegEx = esbuild ? /sent to client/ : /Compiled successfully\./;
const lazyBundleRegEx = esbuild ? /chunk-/ : /src_app_lazy_lazy_component_ts\.js/; const lazyBundleRegEx = esbuild ? /chunk-/ : /src_app_lazy_lazy_ts\.js/;
// Disable HMR to support page reload based rebuild testing. // Disable HMR to support page reload based rebuild testing.
const port = await ngServe('--no-hmr'); const port = await ngServe('--no-hmr');
@ -25,7 +25,7 @@ export default async function () {
replaceInFile( replaceInFile(
'src/app/app.routes.ts', 'src/app/app.routes.ts',
'routes: Routes = [];', 'routes: Routes = [];',
`routes: Routes = [{path: 'lazy', loadComponent: () => import('./lazy/lazy.component').then(c => c.LazyComponent)}];`, `routes: Routes = [{path: 'lazy', loadComponent: () => import('./lazy/lazy').then(c => c.Lazy)}];`,
), ),
]); ]);
@ -83,7 +83,7 @@ export default async function () {
await Promise.all([ await Promise.all([
waitForAnyProcessOutputToMatch(validBundleRegEx), waitForAnyProcessOutputToMatch(validBundleRegEx),
writeMultipleFiles({ writeMultipleFiles({
'src/app/app.component.ng.html': '<h1>testingTESTING123</h1>', 'src/app/app.ng.html': '<h1>testingTESTING123</h1>',
}), }),
]); ]);
@ -99,7 +99,7 @@ export default async function () {
await Promise.all([ await Promise.all([
waitForAnyProcessOutputToMatch(validBundleRegEx), waitForAnyProcessOutputToMatch(validBundleRegEx),
writeMultipleFiles({ writeMultipleFiles({
'src/app/app.component.css': ':host { color: blue; }', 'src/app/app.css': ':host { color: blue; }',
}), }),
]); ]);

View File

@ -7,7 +7,7 @@ import { updateJsonFile } from '../../../utils/project';
const snapshots = require('../../../ng-snapshot/package.json'); const snapshots = require('../../../ng-snapshot/package.json');
export default async function () { export default async function () {
await appendToFile('src/app/app.component.ng.html', '<router-outlet></router-outlet>'); await appendToFile('src/app/app.ng.html', '<router-outlet></router-outlet>');
await ng('generate', 'app-shell', '--project', 'test-project'); await ng('generate', 'app-shell', '--project', 'test-project');
const isSnapshotBuild = getGlobalVariable('argv')['ng-snapshots']; const isSnapshotBuild = getGlobalVariable('argv')['ng-snapshots'];

View File

@ -7,7 +7,7 @@ import { updateJsonFile } from '../../../utils/project';
const snapshots = require('../../../ng-snapshot/package.json'); const snapshots = require('../../../ng-snapshot/package.json');
export default async function () { export default async function () {
await appendToFile('src/app/app.component.ng.html', '<router-outlet></router-outlet>'); await appendToFile('src/app/app.ng.html', '<router-outlet></router-outlet>');
await ng('generate', 'service-worker', '--project', 'test-project'); await ng('generate', 'service-worker', '--project', 'test-project');
await ng('generate', 'app-shell', '--project', 'test-project'); await ng('generate', 'app-shell', '--project', 'test-project');

View File

@ -33,7 +33,7 @@ export default async function () {
h1 { background: url('/assets/global-img-absolute.svg'); } h1 { background: url('/assets/global-img-absolute.svg'); }
h2 { background: url('./assets/global-img-relative.png'); } h2 { background: url('./assets/global-img-relative.png'); }
`, `,
'src/app/app.component.css': ` 'src/app/app.css': `
h3 { background: url('/assets/component-img-absolute.svg'); } h3 { background: url('/assets/component-img-absolute.svg'); }
h4 { background: url('../assets/component-img-relative.png'); } h4 { background: url('../assets/component-img-relative.png'); }
`, `,

View File

@ -18,7 +18,7 @@ export default async function () {
'routes: Routes = [];', 'routes: Routes = [];',
`routes: Routes = [{ `routes: Routes = [{
path: 'lazy', path: 'lazy',
loadComponent: () => import('./lazy-comp/lazy-comp.component').then(c => c.LazyCompComponent), loadComponent: () => import('./lazy-comp/lazy-comp').then(c => c.LazyComp),
}];`, }];`,
); );

View File

@ -29,6 +29,6 @@ export default async function () {
await ng('build', '--configuration=development'); await ng('build', '--configuration=development');
await expectFileToMatch( await expectFileToMatch(
'dist/test-project/browser/main.js.map', 'dist/test-project/browser/main.js.map',
'projects/my-lib/src/lib/my-lib.component.ts', 'projects/my-lib/src/lib/my-lib.ts',
); );
} }

View File

@ -12,6 +12,6 @@ export default async function () {
await ng('build', '--configuration=development'); await ng('build', '--configuration=development');
await expectFileToMatch( await expectFileToMatch(
'dist/test-project/browser/main.js.map', 'dist/test-project/browser/main.js.map',
'projects/my-lib/src/lib/my-lib.component.ts', 'projects/my-lib/src/lib/my-lib.ts',
); );
} }

View File

@ -11,7 +11,7 @@ export default async function () {
// Add an unused class as part of the public api. // Add an unused class as part of the public api.
await appendToFile( await appendToFile(
'projects/my-lib/src/lib/my-lib.component.ts', 'projects/my-lib/src/lib/my-lib.ts',
` `
function something() { function something() {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {

View File

@ -6,16 +6,16 @@ export async function libraryConsumptionSetup(): Promise<void> {
// Force an external template // Force an external template
await writeMultipleFiles({ await writeMultipleFiles({
'projects/my-lib/src/lib/my-lib.component.ng.html': `<p>my-lib works!</p>`, 'projects/my-lib/src/lib/my-lib.ng.html': `<p>my-lib works!</p>`,
'projects/my-lib/src/lib/my-lib.component.ts': `import { Component } from '@angular/core'; 'projects/my-lib/src/lib/my-lib.ts': `import { Component } from '@angular/core';
@Component({ @Component({
standalone: true, standalone: true,
selector: 'lib-my-lib', selector: 'lib-my-lib',
templateUrl: './my-lib.component.ng.html', templateUrl: './my-lib.ng.html',
}) })
export class MyLibComponent {}`, export class MyLibComponent {}`,
'./src/app/app.component.ts': ` './src/app/app.ts': `
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { MyLibService, MyLibComponent } from 'my-lib'; import { MyLibService, MyLibComponent } from 'my-lib';
@ -25,7 +25,7 @@ export async function libraryConsumptionSetup(): Promise<void> {
template: '<lib-my-lib></lib-my-lib>', template: '<lib-my-lib></lib-my-lib>',
imports: [MyLibComponent], imports: [MyLibComponent],
}) })
export class AppComponent { export class App {
title = 'test-project'; title = 'test-project';
constructor(myLibService: MyLibService) { constructor(myLibService: MyLibService) {

View File

@ -50,25 +50,25 @@ export default async function () {
` `
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router'; import { RouterModule, Routes } from '@angular/router';
import { OneComponent } from './one/one.component'; import { One} from './one/one';
import { TwoChildOneComponent } from './two-child-one/two-child-one.component'; import { TwoChildOne } from './two-child-one/two-child-one';
import { TwoChildTwoComponent } from './two-child-two/two-child-two.component'; import { TwoChildTwo } from './two-child-two/two-child-two';
const routes: Routes = [ const routes: Routes = [
{ {
path: '', path: '',
component: OneComponent, component: One,
}, },
{ {
path: 'two', path: 'two',
children: [ children: [
{ {
path: 'two-child-one', path: 'two-child-one',
component: TwoChildOneComponent, component: TwoChildOne,
}, },
{ {
path: 'two-child-two', path: 'two-child-two',
component: TwoChildTwoComponent, component: TwoChildTwo,
}, },
], ],
}, },

View File

@ -20,25 +20,25 @@ export default async function () {
'src/app/app.routes.ts', 'src/app/app.routes.ts',
` `
import { Routes } from '@angular/router'; import { Routes } from '@angular/router';
import { OneComponent } from './one/one.component'; import { One } from './one/one';
import { TwoChildOneComponent } from './two-child-one/two-child-one.component'; import { TwoChildOne } from './two-child-one/two-child-one';
import { TwoChildTwoComponent } from './two-child-two/two-child-two.component'; import { TwoChildTwo } from './two-child-two/two-child-two';
export const routes: Routes = [ export const routes: Routes = [
{ {
path: '', path: '',
component: OneComponent, component: One,
}, },
{ {
path: 'two', path: 'two',
children: [ children: [
{ {
path: 'two-child-one', path: 'two-child-one',
component: TwoChildOneComponent, component: TwoChildOne,
}, },
{ {
path: 'two-child-two', path: 'two-child-two',
component: TwoChildTwoComponent, component: TwoChildTwo,
}, },
], ],
}, },
@ -47,17 +47,17 @@ export default async function () {
children: [ children: [
{ {
path: '', path: '',
loadComponent: () => import('./lazy-one/lazy-one.component').then(c => c.LazyOneComponent), loadComponent: () => import('./lazy-one/lazy-one').then(c => c.LazyOne),
}, },
{ {
path: 'lazy-one-child', path: 'lazy-one-child',
loadComponent: () => import('./lazy-one-child/lazy-one-child.component').then(c => c.LazyOneChildComponent), loadComponent: () => import('./lazy-one-child/lazy-one-child').then(c => c.LazyOneChild),
}, },
], ],
}, },
{ {
path: 'lazy-two', path: 'lazy-two',
loadComponent: () => import('./lazy-two/lazy-two.component').then(c => c.LazyTwoComponent), loadComponent: () => import('./lazy-two/lazy-two').then(c => c.LazyTwo),
}, },
]; ];
`, `,

View File

@ -19,7 +19,7 @@ export default async function () {
await installWorkspacePackages(); await installWorkspacePackages();
await writeMultipleFiles({ await writeMultipleFiles({
'src/app/app.component.ts': ` 'src/app/app.ts': `
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { RouterOutlet } from '@angular/router'; import { RouterOutlet } from '@angular/router';
@ -28,10 +28,10 @@ export default async function () {
selector: 'app-root', selector: 'app-root',
standalone: true, standalone: true,
imports: [CommonModule, RouterOutlet], imports: [CommonModule, RouterOutlet],
templateUrl: './app.component.ng.html', templateUrl: './app.ng.html',
styleUrls: ['./app.component.css'] styleUrls: ['./app.css']
}) })
export class AppComponent { export class App {
title = 'test-ssr'; title = 'test-ssr';
constructor() { constructor() {
@ -48,6 +48,6 @@ export default async function () {
message, message,
// When babel is used it will add names to the sourcemap and `constructor` will be used in the stack trace. // When babel is used it will add names to the sourcemap and `constructor` will be used in the stack trace.
// This will currently only happen if AOT and script optimizations are set which enables advanced optimizations. // This will currently only happen if AOT and script optimizations are set which enables advanced optimizations.
/window is not defined[.\s\S]*(?:constructor|_AppComponent) \(.*app\.component\.ts\:\d+:\d+\)/, /window is not defined[.\s\S]*(?:constructor|_App) \(.*app\.ts\:\d+:\d+\)/,
); );
} }

View File

@ -23,7 +23,7 @@ export default async function () {
import { ApplicationConfig } from '@angular/core'; import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router'; import { provideRouter } from '@angular/router';
import {HomeComponent} from './home/home.component'; import {Home} from './home/home';
import { provideClientHydration } from '@angular/platform-browser'; import { provideClientHydration } from '@angular/platform-browser';
import { provideHttpClient, withFetch } from '@angular/common/http'; import { provideHttpClient, withFetch } from '@angular/common/http';
@ -31,7 +31,7 @@ export default async function () {
providers: [ providers: [
provideRouter([{ provideRouter([{
path: '', path: '',
component: HomeComponent, component: Home,
}]), }]),
provideClientHydration(), provideClientHydration(),
provideHttpClient(withFetch()), provideHttpClient(withFetch()),
@ -44,7 +44,7 @@ export default async function () {
'public/media with-space.json': JSON.stringify({ dataFromAssetsWithSpace: true }), 'public/media with-space.json': JSON.stringify({ dataFromAssetsWithSpace: true }),
// Update component to do an HTTP call to asset. // Update component to do an HTTP call to asset.
'src/app/app.component.ts': ` 'src/app/app.ts': `
import { Component, inject } from '@angular/core'; import { Component, inject } from '@angular/core';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { RouterOutlet } from '@angular/router'; import { RouterOutlet } from '@angular/router';
@ -60,7 +60,7 @@ export default async function () {
<router-outlet></router-outlet> <router-outlet></router-outlet>
\`, \`,
}) })
export class AppComponent { export class App {
data: any; data: any;
dataWithSpace: any; dataWithSpace: any;

View File

@ -31,14 +31,14 @@ export default async function () {
} }
await writeMultipleFiles({ await writeMultipleFiles({
'src/app/app.component.css': `div { color: #000 }`, 'src/app/app.css': `div { color: #000 }`,
'src/styles.css': `* { color: #000 }`, 'src/styles.css': `* { color: #000 }`,
'src/main.ts': `import { bootstrapApplication } from '@angular/platform-browser'; 'src/main.ts': `import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component'; import { App } from './app/app';
import { appConfig } from './app/app.config'; import { appConfig } from './app/app.config';
(window as any)['doBootstrap'] = () => { (window as any)['doBootstrap'] = () => {
bootstrapApplication(AppComponent, appConfig).catch((err) => console.error(err)); bootstrapApplication(App, appConfig).catch((err) => console.error(err));
}; };
`, `,
'src/index.html': ` 'src/index.html': `

View File

@ -66,7 +66,7 @@ export default async function () {
} }
await writeMultipleFiles({ await writeMultipleFiles({
'projects/test-project-two/src/app/app.component.css': `div { color: #000 }`, 'projects/test-project-two/src/app/app.css': `div { color: #000 }`,
'projects/test-project-two/src/styles.css': `* { color: #000 }`, 'projects/test-project-two/src/styles.css': `* { color: #000 }`,
'projects/test-project-two/src/main.ts': ` 'projects/test-project-two/src/main.ts': `
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

View File

@ -32,14 +32,14 @@ export default async function () {
await installWorkspacePackages(); await installWorkspacePackages();
await writeMultipleFiles({ await writeMultipleFiles({
'src/app/app.component.css': `div { color: #000 }`, 'src/app/app.css': `div { color: #000 }`,
'src/styles.css': `* { color: #000 }`, 'src/styles.css': `* { color: #000 }`,
'src/main.ts': `import { bootstrapApplication } from '@angular/platform-browser'; 'src/main.ts': `import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component'; import { App } from './app/app';
import { appConfig } from './app/app.config'; import { appConfig } from './app/app.config';
(window as any)['doBootstrap'] = () => { (window as any)['doBootstrap'] = () => {
bootstrapApplication(AppComponent, appConfig).catch((err) => console.error(err)); bootstrapApplication(App, appConfig).catch((err) => console.error(err));
}; };
`, `,
'e2e/src/app.e2e-spec.ts': ` 'e2e/src/app.e2e-spec.ts': `

View File

@ -28,22 +28,22 @@ export default async function () {
'src/app/app.routes.ts', 'src/app/app.routes.ts',
` `
import { Routes } from '@angular/router'; import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component'; import { Home } from './home/home';
import { SsrComponent } from './ssr/ssr.component'; import { Ssr } from './ssr/ssr';
import { SsgComponent } from './ssg/ssg.component'; import { Ssg } from './ssg/ssg';
export const routes: Routes = [ export const routes: Routes = [
{ {
path: '', path: '',
component: HomeComponent, component: Home,
}, },
{ {
path: 'ssg', path: 'ssg',
component: SsgComponent, component: Ssg,
}, },
{ {
path: 'ssr', path: 'ssr',
component: SsrComponent, component: Ssr,
}, },
]; ];
`, `,

View File

@ -53,22 +53,22 @@ export default async function () {
'src/app/app.routes.ts', 'src/app/app.routes.ts',
` `
import { Routes } from '@angular/router'; import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component'; import { Home } from './home/home';
import { SsrComponent } from './ssr/ssr.component'; import { Ssr } from './ssr/ssr';
import { SsgComponent } from './ssg/ssg.component'; import { Ssg } from './ssg/ssg';
export const routes: Routes = [ export const routes: Routes = [
{ {
path: '', path: '',
component: HomeComponent, component: Home,
}, },
{ {
path: 'ssg', path: 'ssg',
component: SsgComponent, component: Ssg,
}, },
{ {
path: 'ssr', path: 'ssr',
component: SsrComponent, component: Ssr,
}, },
]; ];
`, `,

View File

@ -28,22 +28,22 @@ export default async function () {
'src/app/app.routes.ts', 'src/app/app.routes.ts',
` `
import { Routes } from '@angular/router'; import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component'; import { Home } from './home/home';
import { SsrComponent } from './ssr/ssr.component'; import { Ssr } from './ssr/ssr';
import { SsgComponent } from './ssg/ssg.component'; import { Ssg } from './ssg/ssg';
export const routes: Routes = [ export const routes: Routes = [
{ {
path: '', path: '',
component: HomeComponent, component: Home,
}, },
{ {
path: 'ssg', path: 'ssg',
component: SsgComponent, component: Ssg,
}, },
{ {
path: 'ssr', path: 'ssr',
component: SsrComponent, component: Ssr,
}, },
]; ];
`, `,

View File

@ -27,26 +27,26 @@ export default async function () {
await installPackage('h3@1'); await installPackage('h3@1');
await writeMultipleFiles({ await writeMultipleFiles({
// Replace the template of app.component.ng.html as it makes it harder to debug // Replace the template of app.ng.html as it makes it harder to debug
'src/app/app.component.ng.html': '<router-outlet />', 'src/app/app.ng.html': '<router-outlet />',
'src/app/app.routes.ts': ` 'src/app/app.routes.ts': `
import { Routes } from '@angular/router'; import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component'; import { Home } from './home/home';
import { SsrComponent } from './ssr/ssr.component'; import { Ssr } from './ssr/ssr';
import { SsgWithParamsComponent } from './ssg-with-params/ssg-with-params.component'; import { SsgWithParams } from './ssg-with-params/ssg-with-params';
export const routes: Routes = [ export const routes: Routes = [
{ {
path: '', path: '',
component: HomeComponent, component: Home,
}, },
{ {
path: 'ssr', path: 'ssr',
component: SsrComponent, component: Ssr,
}, },
{ {
path: 'ssg/:id', path: 'ssg/:id',
component: SsgWithParamsComponent, component: SsgWithParams,
}, },
]; ];
`, `,

View File

@ -21,38 +21,38 @@ export default async function () {
await installWorkspacePackages(); await installWorkspacePackages();
// Test scenario to verify that the content length, including \r\n, is accurate // Test scenario to verify that the content length, including \r\n, is accurate
await replaceInFile('src/app/app.component.ts', "title = '", "title = 'Title\\r\\n"); await replaceInFile('src/app/app.ts', "title = '", "title = 'Title\\r\\n");
// Ensure text has been updated. // Ensure text has been updated.
assert.match(await readFile('src/app/app.component.ts'), /title = 'Title/); assert.match(await readFile('src/app/app.ts'), /title = 'Title/);
// Add routes // Add routes
await writeFile( await writeFile(
'src/app/app.routes.ts', 'src/app/app.routes.ts',
` `
import { Routes } from '@angular/router'; import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component'; import { Home } from './home/home';
import { CsrComponent } from './csr/csr.component'; import { Csr } from './csr/csr';
import { SsrComponent } from './ssr/ssr.component'; import { Ssr } from './ssr/ssr';
import { SsgComponent } from './ssg/ssg.component'; import { Ssg } from './ssg/ssg';
import { SsgWithParamsComponent } from './ssg-with-params/ssg-with-params.component'; import { SsgWithParams } from './ssg-with-params/ssg-with-params';
export const routes: Routes = [ export const routes: Routes = [
{ {
path: '', path: '',
component: HomeComponent, component: Home,
}, },
{ {
path: 'ssg', path: 'ssg',
component: SsgComponent, component: Ssg,
}, },
{ {
path: 'ssr', path: 'ssr',
component: SsrComponent, component: Ssr,
}, },
{ {
path: 'csr', path: 'csr',
component: CsrComponent, component: Csr,
}, },
{ {
path: 'redirect', path: 'redirect',
@ -60,7 +60,7 @@ export default async function () {
}, },
{ {
path: 'ssg/:id', path: 'ssg/:id',
component: SsgWithParamsComponent, component: SsgWithParams,
}, },
]; ];
`, `,

View File

@ -21,7 +21,7 @@ export default async function () {
// Add asset // Add asset
'public/media.json': JSON.stringify({ dataFromAssets: true }), 'public/media.json': JSON.stringify({ dataFromAssets: true }),
// Update component to do an HTTP call to asset and API. // Update component to do an HTTP call to asset and API.
'src/app/app.component.ts': ` 'src/app/app.ts': `
import { Component, inject } from '@angular/core'; import { Component, inject } from '@angular/core';
import { JsonPipe } from '@angular/common'; import { JsonPipe } from '@angular/common';
import { RouterOutlet } from '@angular/router'; import { RouterOutlet } from '@angular/router';
@ -37,7 +37,7 @@ export default async function () {
<router-outlet></router-outlet> <router-outlet></router-outlet>
\`, \`,
}) })
export class AppComponent { export class App {
assetsData: any; assetsData: any;
apiData: any; apiData: any;
@ -59,7 +59,7 @@ export default async function () {
import { ApplicationConfig } from '@angular/core'; import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router'; import { provideRouter } from '@angular/router';
import { HomeComponent } from './home/home.component'; import { Home } from './home/home';
import { provideClientHydration } from '@angular/platform-browser'; import { provideClientHydration } from '@angular/platform-browser';
import { provideHttpClient, withFetch } from '@angular/common/http'; import { provideHttpClient, withFetch } from '@angular/common/http';
@ -67,7 +67,7 @@ export default async function () {
providers: [ providers: [
provideRouter([{ provideRouter([{
path: 'home', path: 'home',
component: HomeComponent, component: Home,
}]), }]),
provideClientHydration(), provideClientHydration(),
provideHttpClient(withFetch()), provideHttpClient(withFetch()),

View File

@ -28,21 +28,21 @@ export default async function () {
'src/app/app.routes.ts', 'src/app/app.routes.ts',
` `
import { Routes } from '@angular/router'; import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component'; import { Home } from './home/home';
import { SsgComponent } from './ssg/ssg.component'; import { Ssg } from './ssg/ssg';
export const routes: Routes = [ export const routes: Routes = [
{ {
path: '', path: '',
component: HomeComponent, component: Home,
}, },
{ {
path: 'ssg', path: 'ssg',
component: SsgComponent, component: Ssg,
}, },
{ {
path: '**', path: '**',
component: HomeComponent, component: Home,
}, },
]; ];
`, `,

View File

@ -30,18 +30,18 @@ export default async function () {
'src/app/app.routes.ts', 'src/app/app.routes.ts',
` `
import { Routes } from '@angular/router'; import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component'; import { Home } from './home/home';
import { SsgComponent } from './ssg/ssg.component'; import { Ssg } from './ssg/ssg';
import { SsgWithParamsComponent } from './ssg-with-params/ssg-with-params.component'; import { SsgWithParams } from './ssg-with-params/ssg-with-params';
export const routes: Routes = [ export const routes: Routes = [
{ {
path: '', path: '',
component: HomeComponent, component: Home,
}, },
{ {
path: 'ssg', path: 'ssg',
component: SsgComponent, component: Ssg,
}, },
{ {
path: 'ssg-redirect', path: 'ssg-redirect',
@ -49,11 +49,11 @@ export default async function () {
}, },
{ {
path: 'ssg/:id', path: 'ssg/:id',
component: SsgWithParamsComponent, component: SsgWithParams,
}, },
{ {
path: '**', path: '**',
component: HomeComponent, component: Home,
}, },
]; ];
`, `,

View File

@ -31,7 +31,7 @@ export default async function () {
export const routes: Routes = [ export const routes: Routes = [
{ {
path: '', path: '',
loadComponent: () => import('./home/home.component').then(c => c.HomeComponent), loadComponent: () => import('./home/home').then(c => c.Home),
}, },
{ {
path: 'ssg', path: 'ssg',
@ -39,11 +39,11 @@ export default async function () {
}, },
{ {
path: 'ssr', path: 'ssr',
loadComponent: () => import('./ssr/ssr.component').then(c => c.SsrComponent), loadComponent: () => import('./ssr/ssr').then(c => c.Ssr),
}, },
{ {
path: 'csr', path: 'csr',
loadComponent: () => import('./csr/csr.component').then(c => c.CsrComponent), loadComponent: () => import('./csr/csr').then(c => c.Csr),
}, },
]; ];
`, `,
@ -72,21 +72,21 @@ export default async function () {
export const routes: Routes = [ export const routes: Routes = [
{ {
path: '', path: '',
loadComponent: () => import('./ssg/ssg.component').then(c => c.SsgComponent), loadComponent: () => import('./ssg-component/ssg-component').then(c => c.SsgComponent),
}, },
{ {
path: 'one', path: 'one',
loadComponent: () => import('./ssg-one/ssg-one.component').then(c => c.SsgOneComponent), loadComponent: () => import('./ssg-one/ssg-one').then(c => c.SsgOne),
}, },
{ {
path: 'two', path: 'two',
loadComponent: () => import('./ssg-two/ssg-two.component').then(c => c.SsgTwoComponent), loadComponent: () => import('./ssg-two/ssg-two').then(c => c.SsgTwo),
}, },
];`, ];`,
}); });
// Generate components for the above routes // Generate components for the above routes
const componentNames: string[] = ['home', 'ssg', 'csr', 'ssr', 'ssg-one', 'ssg-two']; const componentNames: string[] = ['home', 'ssg-component', 'csr', 'ssr', 'ssg-one', 'ssg-two'];
for (const componentName of componentNames) { for (const componentName of componentNames) {
await silentNg('generate', 'component', componentName); await silentNg('generate', 'component', componentName);
@ -95,18 +95,18 @@ export default async function () {
// Add a cross-dependency // Add a cross-dependency
await Promise.all([ await Promise.all([
replaceInFile( replaceInFile(
'src/app/ssg-one/ssg-one.component.ts', 'src/app/ssg-one/ssg-one.ts',
`OneComponent {`, `One {`,
`OneComponent { `One {
async ngOnInit() { async ngOnInit() {
await import('../cross-dep'); await import('../cross-dep');
} }
`, `,
), ),
replaceInFile( replaceInFile(
'src/app/ssg-two/ssg-two.component.ts', 'src/app/ssg-two/ssg-two.ts',
`TwoComponent {`, `Two {`,
`TwoComponent { `Two {
async ngOnInit() { async ngOnInit() {
await import('../cross-dep'); await import('../cross-dep');
} }
@ -129,58 +129,39 @@ const RESPONSE_EXPECTS: Record<
} }
> = { > = {
'/': { '/': {
matches: [/<link rel="modulepreload" href="(home\.component-[a-zA-Z0-9]{8}\.js)">/], matches: [/<link rel="modulepreload" href="(home-[a-zA-Z0-9]{8}\.js)">/],
notMatches: [/ssg\.component/, /ssr\.component/, /csr\.component/, /cross-dep-/], notMatches: [/ssg\-component/, /ssr/, /csr/, /cross-dep-/],
}, },
'/ssg': { '/ssg': {
matches: [ matches: [
/<link rel="modulepreload" href="(ssg\.routes-[a-zA-Z0-9]{8}\.js)">/, /<link rel="modulepreload" href="(ssg\.routes-[a-zA-Z0-9]{8}\.js)">/,
/<link rel="modulepreload" href="(ssg\.component-[a-zA-Z0-9]{8}\.js)">/, /<link rel="modulepreload" href="(ssg-component-[a-zA-Z0-9]{8}\.js)">/,
],
notMatches: [
/home\.component/,
/ssr\.component/,
/csr\.component/,
/ssg-one\.component/,
/ssg-two\.component/,
/cross-dep-/,
], ],
notMatches: [/home/, /ssr/, /csr/, /ssg-one/, /ssg-two/, /cross-dep-/],
}, },
'/ssg/one': { '/ssg/one': {
matches: [ matches: [
/<link rel="modulepreload" href="(ssg\.routes-[a-zA-Z0-9]{8}\.js)">/, /<link rel="modulepreload" href="(ssg\.routes-[a-zA-Z0-9]{8}\.js)">/,
/<link rel="modulepreload" href="(ssg-one\.component-[a-zA-Z0-9]{8}\.js)">/, /<link rel="modulepreload" href="(ssg-one-[a-zA-Z0-9]{8}\.js)">/,
/<link rel="modulepreload" href="(cross-dep-[a-zA-Z0-9]{8}\.js)">/, /<link rel="modulepreload" href="(cross-dep-[a-zA-Z0-9]{8}\.js)">/,
], ],
notMatches: [ notMatches: [/home/, /ssr/, /csr/, /ssg-two/, /ssg\-component/],
/home\.component/,
/ssr\.component/,
/csr\.component/,
/ssg-two\.component/,
/ssg\.component/,
],
}, },
'/ssg/two': { '/ssg/two': {
matches: [ matches: [
/<link rel="modulepreload" href="(ssg\.routes-[a-zA-Z0-9]{8}\.js)">/, /<link rel="modulepreload" href="(ssg\.routes-[a-zA-Z0-9]{8}\.js)">/,
/<link rel="modulepreload" href="(ssg-two\.component-[a-zA-Z0-9]{8}\.js)">/, /<link rel="modulepreload" href="(ssg-two-[a-zA-Z0-9]{8}\.js)">/,
/<link rel="modulepreload" href="(cross-dep-[a-zA-Z0-9]{8}\.js)">/, /<link rel="modulepreload" href="(cross-dep-[a-zA-Z0-9]{8}\.js)">/,
], ],
notMatches: [ notMatches: [/home/, /ssr/, /csr/, /ssg-one/, /ssg\-component/],
/home\.component/,
/ssr\.component/,
/csr\.component/,
/ssg-one\.component/,
/ssg\.component/,
],
}, },
'/ssr': { '/ssr': {
matches: [/<link rel="modulepreload" href="(ssr\.component-[a-zA-Z0-9]{8}\.js)">/], matches: [/<link rel="modulepreload" href="(ssr-[a-zA-Z0-9]{8}\.js)">/],
notMatches: [/home\.component/, /ssg\.component/, /csr\.component/], notMatches: [/home/, /ssg\-component/, /csr/],
}, },
'/csr': { '/csr': {
matches: [/<link rel="modulepreload" href="(csr\.component-[a-zA-Z0-9]{8}\.js)">/], matches: [/<link rel="modulepreload" href="(csr-[a-zA-Z0-9]{8}\.js)">/],
notMatches: [/home\.component/, /ssg\.component/, /ssr\.component/, /cross-dep-/], notMatches: [/home/, /ssg\-component/, /ssr/, /cross-dep-/],
}, },
}; };

View File

@ -10,7 +10,7 @@ export default async function () {
@import 'variables'; @import 'variables';
h1 { color: $primary-color; } h1 { color: $primary-color; }
`, `,
'src/app/app.component.scss': ` 'src/app/app.scss': `
@import 'variables'; @import 'variables';
h2 { color: $primary-color; } h2 { color: $primary-color; }
`, `,
@ -19,16 +19,16 @@ export default async function () {
@import 'variables'; @import 'variables';
h5 { color: @primary-color; } h5 { color: @primary-color; }
`, `,
'src/app/app.component.less': ` 'src/app/app.less': `
@import 'variables'; @import 'variables';
h6 { color: @primary-color; } h6 { color: @primary-color; }
`, `,
}); });
await replaceInFile( await replaceInFile(
'src/app/app.component.ts', 'src/app/app.ts',
`styleUrl: './app.component.css\'`, `styleUrl: './app.css\'`,
`styleUrls: ['./app.component.scss', './app.component.less']`, `styleUrls: ['./app.scss', './app.less']`,
); );
await updateJsonFile('angular.json', (workspaceJson) => { await updateJsonFile('angular.json', (workspaceJson) => {

View File

@ -17,7 +17,7 @@ export default function () {
body { background-color: blue; } body { background-color: blue; }
`, `,
'src/imported-styles.less': 'p { background-color: red; }', 'src/imported-styles.less': 'p { background-color: red; }',
'src/app/app.component.less': ` 'src/app/app.less': `
.outer { .outer {
.inner { .inner {
background: #fff; background: #fff;
@ -25,16 +25,14 @@ export default function () {
} }
`, `,
}) })
.then(() => deleteFile('src/app/app.component.css')) .then(() => deleteFile('src/app/app.css'))
.then(() => .then(() =>
updateJsonFile('angular.json', (workspaceJson) => { updateJsonFile('angular.json', (workspaceJson) => {
const appArchitect = workspaceJson.projects['test-project'].architect; const appArchitect = workspaceJson.projects['test-project'].architect;
appArchitect.build.options.styles = [{ input: 'src/styles.less' }]; appArchitect.build.options.styles = [{ input: 'src/styles.less' }];
}), }),
) )
.then(() => .then(() => replaceInFile('src/app/app.ts', './app.css', './app.less'))
replaceInFile('src/app/app.component.ts', './app.component.css', './app.component.less'),
)
.then(() => ng('build', '--source-map', '--configuration=development')) .then(() => ng('build', '--source-map', '--configuration=development'))
.then(() => .then(() =>
expectFileToMatch( expectFileToMatch(

View File

@ -15,7 +15,7 @@ export default async function () {
body { background-color: blue; } body { background-color: blue; }
`, `,
'src/imported-styles.scss': 'p { background-color: red; }', 'src/imported-styles.scss': 'p { background-color: red; }',
'src/app/app.component.scss': ` 'src/app/app.scss': `
.outer { .outer {
.inner { .inner {
background: #fff; background: #fff;
@ -24,12 +24,12 @@ export default async function () {
`, `,
}); });
await deleteFile('src/app/app.component.css'); await deleteFile('src/app/app.css');
await updateJsonFile('angular.json', (workspaceJson) => { await updateJsonFile('angular.json', (workspaceJson) => {
const appArchitect = workspaceJson.projects['test-project'].architect; const appArchitect = workspaceJson.projects['test-project'].architect;
appArchitect.build.options.styles = [{ input: 'src/styles.scss' }]; appArchitect.build.options.styles = [{ input: 'src/styles.scss' }];
}); });
await replaceInFile('src/app/app.component.ts', './app.component.css', './app.component.scss'); await replaceInFile('src/app/app.ts', './app.css', './app.scss');
await ng('build', '--configuration=development'); await ng('build', '--configuration=development');

View File

@ -19,7 +19,7 @@ export default async function () {
p p
background-color: red background-color: red
`, `,
'src/app/app.component.sass': ` 'src/app/app.sass': `
.outer .outer
.inner .inner
background: #fff background: #fff
@ -31,8 +31,8 @@ export default async function () {
appArchitect.build.options.styles = [{ input: 'src/styles.sass' }]; appArchitect.build.options.styles = [{ input: 'src/styles.sass' }];
}); });
await deleteFile('src/app/app.component.css'); await deleteFile('src/app/app.css');
await replaceInFile('src/app/app.component.ts', './app.component.css', './app.component.sass'); await replaceInFile('src/app/app.ts', './app.css', './app.sass');
await ng('build', '--source-map', '--configuration=development'); await ng('build', '--source-map', '--configuration=development');

View File

@ -16,7 +16,7 @@ export default async function () {
@include button.core-styles; @include button.core-styles;
`, `,
'src/app/app.component.scss': ` 'src/app/app.scss': `
@use '@material/button/button'; @use '@material/button/button';
@include button.core-styles; @include button.core-styles;
@ -28,8 +28,8 @@ export default async function () {
appArchitect.build.options.styles = ['src/styles.scss']; appArchitect.build.options.styles = ['src/styles.scss'];
}); });
await deleteFile('src/app/app.component.css'); await deleteFile('src/app/app.css');
await replaceInFile('src/app/app.component.ts', './app.component.css', './app.component.scss'); await replaceInFile('src/app/app.ts', './app.css', './app.scss');
await ng('build', '--configuration=development'); await ng('build', '--configuration=development');
} }

View File

@ -15,7 +15,7 @@ export default async function () {
body { background-color: blue; } body { background-color: blue; }
`, `,
'src/imported-styles.scss': 'p { background-color: red; }', 'src/imported-styles.scss': 'p { background-color: red; }',
'src/app/app.component.scss': ` 'src/app/app.scss': `
.outer { .outer {
.inner { .inner {
background: #fff; background: #fff;
@ -29,8 +29,8 @@ export default async function () {
appArchitect.build.options.styles = [{ input: 'src/styles.scss' }]; appArchitect.build.options.styles = [{ input: 'src/styles.scss' }];
}); });
await deleteFile('src/app/app.component.css'); await deleteFile('src/app/app.css');
await replaceInFile('src/app/app.component.ts', './app.component.css', './app.component.scss'); await replaceInFile('src/app/app.ts', './app.css', './app.scss');
await ng('build', '--source-map', '--configuration=development'); await ng('build', '--source-map', '--configuration=development');

View File

@ -12,7 +12,7 @@ export default async function () {
await silentExec('npx', 'tailwindcss@2', 'init'); await silentExec('npx', 'tailwindcss@2', 'init');
// Add Tailwind directives to a component style // Add Tailwind directives to a component style
await writeFile('src/app/app.component.css', '@tailwind base; @tailwind components;'); await writeFile('src/app/app.css', '@tailwind base; @tailwind components;');
// Add Tailwind directives to a global style // Add Tailwind directives to a global style
await writeFile('src/styles.css', '@tailwind base; @tailwind components;'); await writeFile('src/styles.css', '@tailwind base; @tailwind components;');

View File

@ -16,7 +16,7 @@ export default async function () {
await silentExec('npx', 'tailwindcss@3', 'init'); await silentExec('npx', 'tailwindcss@3', 'init');
// Add Tailwind directives to a component style // Add Tailwind directives to a component style
await writeFile('src/app/app.component.css', '@tailwind base; @tailwind components;'); await writeFile('src/app/app.css', '@tailwind base; @tailwind components;');
// Add Tailwind directives to a global style // Add Tailwind directives to a global style
await writeFile( await writeFile(

View File

@ -19,7 +19,7 @@ export default async function () {
'src/app/shared/index.ts': `export * from './meaning'`, 'src/app/shared/index.ts': `export * from './meaning'`,
}); });
await replaceInFile('src/main.ts', './app/app.component', '@root/app/app.component'); await replaceInFile('src/main.ts', './app/app', '@root/app/app');
await ng('build', '--configuration=development'); await ng('build', '--configuration=development');
await updateTsConfig((json) => { await updateTsConfig((json) => {
@ -27,7 +27,7 @@ export default async function () {
}); });
await appendToFile( await appendToFile(
'src/app/app.component.ts', 'src/app/app.ts',
` `
import { meaning } from 'app/shared/meaning'; import { meaning } from 'app/shared/meaning';
import { meaning as meaning2 } from '@shared'; import { meaning as meaning2 } from '@shared';

View File

@ -49,16 +49,12 @@ export default async function () {
// Use WASM file in project // Use WASM file in project
await prependToFile( await prependToFile(
'src/app/app.component.ts', 'src/app/app.ts',
` `
import { multiply, subtract1 } from './multiply.wasm'; import { multiply, subtract1 } from './multiply.wasm';
`, `,
); );
await replaceInFile( await replaceInFile('src/app/app.ts', "'test-project'", 'multiply(4, 5) + subtract1(88)');
'src/app/app.component.ts',
"'test-project'",
'multiply(4, 5) + subtract1(88)',
);
// Remove Zone.js from polyfills and make zoneless // Remove Zone.js from polyfills and make zoneless
await updateJsonFile('angular.json', (json) => { await updateJsonFile('angular.json', (json) => {

View File

@ -16,7 +16,7 @@ export default async function () {
const useWebpackBuilder = !getGlobalVariable('argv')['esbuild']; const useWebpackBuilder = !getGlobalVariable('argv')['esbuild'];
const workerPath = 'src/app/app.worker.ts'; const workerPath = 'src/app/app.worker.ts';
const snippetPath = 'src/app/app.component.ts'; const snippetPath = 'src/app/app.ts';
const projectTsConfig = 'tsconfig.json'; const projectTsConfig = 'tsconfig.json';
const workerTsConfig = 'tsconfig.worker.json'; const workerTsConfig = 'tsconfig.worker.json';
@ -52,7 +52,7 @@ export default async function () {
// console.warn has to be used because chrome only captures warnings and errors by default // console.warn has to be used because chrome only captures warnings and errors by default
// https://github.com/angular/protractor/issues/2207 // https://github.com/angular/protractor/issues/2207
await replaceInFile('src/app/app.component.ts', 'console.log', 'console.warn'); await replaceInFile('src/app/app.ts', 'console.log', 'console.warn');
await writeFile( await writeFile(
'e2e/app.e2e-spec.ts', 'e2e/app.e2e-spec.ts',

View File

@ -27,7 +27,7 @@ export default async function () {
import { ApplicationConfig } from '@angular/core'; import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router'; import { provideRouter } from '@angular/router';
import { HomeComponent } from './home/home.component'; import { Home } from './home/home';
import { provideClientHydration } from '@angular/platform-browser'; import { provideClientHydration } from '@angular/platform-browser';
import { provideHttpClient, withFetch } from '@angular/common/http'; import { provideHttpClient, withFetch } from '@angular/common/http';
@ -35,7 +35,7 @@ export default async function () {
providers: [ providers: [
provideRouter([{ provideRouter([{
path: '', path: '',
component: HomeComponent, component: Home,
}]), }]),
provideClientHydration(), provideClientHydration(),
provideHttpClient(withFetch()), provideHttpClient(withFetch()),
@ -45,7 +45,7 @@ export default async function () {
// Add asset // Add asset
'public/media.json': JSON.stringify({ dataFromAssets: true }), 'public/media.json': JSON.stringify({ dataFromAssets: true }),
// Update component to do an HTTP call to asset. // Update component to do an HTTP call to asset.
'src/app/app.component.ts': ` 'src/app/app.ts': `
import { Component, inject } from '@angular/core'; import { Component, inject } from '@angular/core';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { RouterOutlet } from '@angular/router'; import { RouterOutlet } from '@angular/router';
@ -60,7 +60,7 @@ export default async function () {
<router-outlet></router-outlet> <router-outlet></router-outlet>
\`, \`,
}) })
export class AppComponent { export class App {
data: any; data: any;
constructor() { constructor() {
const http = inject(HttpClient); const http = inject(HttpClient);

View File

@ -9,10 +9,10 @@ export default function () {
return ( return (
ng('generate', 'component', 'test-component') ng('generate', 'component', 'test-component')
.then(() => expectFileToExist(componentDir)) .then(() => expectFileToExist(componentDir))
.then(() => expectFileToExist(join(componentDir, 'test-component.component.ts'))) .then(() => expectFileToExist(join(componentDir, 'test-component.ts')))
.then(() => expectFileToExist(join(componentDir, 'test-component.component.spec.ts'))) .then(() => expectFileToExist(join(componentDir, 'test-component.spec.ts')))
.then(() => expectFileToExist(join(componentDir, 'test-component.component.ng.html'))) .then(() => expectFileToExist(join(componentDir, 'test-component.ng.html')))
.then(() => expectFileToExist(join(componentDir, 'test-component.component.css'))) .then(() => expectFileToExist(join(componentDir, 'test-component.css')))
// Try to run the unit tests. // Try to run the unit tests.
.then(() => ng('test', '--watch=false')) .then(() => ng('test', '--watch=false'))

View File

@ -19,10 +19,10 @@ export default async function () {
// Ensure component is created in the correct location relative to the workspace root // Ensure component is created in the correct location relative to the workspace root
const componentDirectory = join(childDirectory, 'test-component'); const componentDirectory = join(childDirectory, 'test-component');
await expectFileToExist(join(componentDirectory, 'test-component.component.ts')); await expectFileToExist(join(componentDirectory, 'test-component.ts'));
await expectFileToExist(join(componentDirectory, 'test-component.component.spec.ts')); await expectFileToExist(join(componentDirectory, 'test-component.spec.ts'));
await expectFileToExist(join(componentDirectory, 'test-component.component.ng.html')); await expectFileToExist(join(componentDirectory, 'test-component.ng.html'));
await expectFileToExist(join(componentDirectory, 'test-component.component.css')); await expectFileToExist(join(componentDirectory, 'test-component.css'));
// Ensure unit test execute and pass // Ensure unit test execute and pass
await ng('test', '--watch=false'); await ng('test', '--watch=false');

View File

@ -16,10 +16,10 @@ export default function () {
) )
.then(() => ng('generate', 'component', 'test-component')) .then(() => ng('generate', 'component', 'test-component'))
.then(() => expectFileToExist(appDir)) .then(() => expectFileToExist(appDir))
.then(() => expectFileToExist(join(appDir, 'test-component.component.ts'))) .then(() => expectFileToExist(join(appDir, 'test-component.ts')))
.then(() => expectFileToExist(join(appDir, 'test-component.component.spec.ts'))) .then(() => expectFileToExist(join(appDir, 'test-component.spec.ts')))
.then(() => expectFileToExist(join(appDir, 'test-component.component.ng.html'))) .then(() => expectFileToExist(join(appDir, 'test-component.ng.html')))
.then(() => expectFileToExist(join(appDir, 'test-component.component.css'))) .then(() => expectFileToExist(join(appDir, 'test-component.css')))
// Try to run the unit tests. // Try to run the unit tests.
.then(() => ng('test', '--watch=false')) .then(() => ng('test', '--watch=false'))

View File

@ -18,14 +18,12 @@ export default function () {
) )
.then(() => ng('generate', 'component', 'test-component')) .then(() => ng('generate', 'component', 'test-component'))
.then(() => expectFileToExist(componentDir)) .then(() => expectFileToExist(componentDir))
.then(() => expectFileToExist(join(componentDir, 'test-component.component.ts'))) .then(() => expectFileToExist(join(componentDir, 'test-component.ts')))
.then(() => expectFileToExist(join(componentDir, 'test-component.component.spec.ts'))) .then(() => expectFileToExist(join(componentDir, 'test-component.spec.ts')))
.then(() => .then(() =>
expectToFail(() => expectToFail(() => expectFileToExist(join(componentDir, 'test-component.ng.html'))),
expectFileToExist(join(componentDir, 'test-component.component.ng.html')),
),
) )
.then(() => expectFileToExist(join(componentDir, 'test-component.component.css'))) .then(() => expectFileToExist(join(componentDir, 'test-component.css')))
// Try to run the unit tests. // Try to run the unit tests.
.then(() => ng('test', '--watch=false')) .then(() => ng('test', '--watch=false'))

View File

@ -17,10 +17,10 @@ export default function () {
) )
.then(() => ng('generate', 'component', 'test-component')) .then(() => ng('generate', 'component', 'test-component'))
.then(() => expectFileToExist(componentDir)) .then(() => expectFileToExist(componentDir))
.then(() => expectFileToExist(join(componentDir, 'test-component.component.ts'))) .then(() => expectFileToExist(join(componentDir, 'test-component.ts')))
.then(() => expectFileToExist(join(componentDir, 'test-component.component.spec.ts'))) .then(() => expectFileToExist(join(componentDir, 'test-component.spec.ts')))
.then(() => expectFileToExist(join(componentDir, 'test-component.component.ng.html'))) .then(() => expectFileToExist(join(componentDir, 'test-component.ng.html')))
.then(() => expectFileToExist(join(componentDir, 'test-component.component.css'))) .then(() => expectFileToExist(join(componentDir, 'test-component.css')))
// Try to run the unit tests. // Try to run the unit tests.
.then(() => ng('test', '--watch=false')) .then(() => ng('test', '--watch=false'))

View File

@ -14,19 +14,19 @@ export default async function () {
await ng('generate', 'component', `${upperDirs}/test-component`); await ng('generate', 'component', `${upperDirs}/test-component`);
// Ensure component is created in the correct location relative to the workspace root // Ensure component is created in the correct location relative to the workspace root
await expectFileToExist(join(componentDirectory, 'test-component.component.ts')); await expectFileToExist(join(componentDirectory, 'test-component.ts'));
await expectFileToExist(join(componentDirectory, 'test-component.component.spec.ts')); await expectFileToExist(join(componentDirectory, 'test-component.spec.ts'));
await expectFileToExist(join(componentDirectory, 'test-component.component.ng.html')); await expectFileToExist(join(componentDirectory, 'test-component.ng.html'));
await expectFileToExist(join(componentDirectory, 'test-component.component.css')); await expectFileToExist(join(componentDirectory, 'test-component.css'));
// Generate another component // Generate another component
await ng('generate', 'component', `${upperDirs}/Test-Component-Two`); await ng('generate', 'component', `${upperDirs}/Test-Component-Two`);
// Ensure component is created in the correct location relative to the workspace root // Ensure component is created in the correct location relative to the workspace root
await expectFileToExist(join(componentTwoDirectory, 'test-component-two.component.ts')); await expectFileToExist(join(componentTwoDirectory, 'test-component-two.ts'));
await expectFileToExist(join(componentTwoDirectory, 'test-component-two.component.spec.ts')); await expectFileToExist(join(componentTwoDirectory, 'test-component-two.spec.ts'));
await expectFileToExist(join(componentTwoDirectory, 'test-component-two.component.ng.html')); await expectFileToExist(join(componentTwoDirectory, 'test-component-two.ng.html'));
await expectFileToExist(join(componentTwoDirectory, 'test-component-two.component.css')); await expectFileToExist(join(componentTwoDirectory, 'test-component-two.css'));
// Ensure unit test execute and pass // Ensure unit test execute and pass
await ng('test', '--watch=false'); await ng('test', '--watch=false');

View File

@ -17,11 +17,9 @@ export default function () {
}), }),
) )
.then(() => ng('generate', 'component', 'test-component')) .then(() => ng('generate', 'component', 'test-component'))
.then(() => .then(() => expectFileToMatch(join(testCompDir, 'test-component.ts'), /selector: 'pre-/))
expectFileToMatch(join(testCompDir, 'test-component.component.ts'), /selector: 'pre-/),
)
.then(() => ng('g', 'c', 'alias')) .then(() => ng('g', 'c', 'alias'))
.then(() => expectFileToMatch(join(aliasCompDir, 'alias.component.ts'), /selector: 'pre-/)) .then(() => expectFileToMatch(join(aliasCompDir, 'alias.ts'), /selector: 'pre-/))
// Try to run the unit tests. // Try to run the unit tests.
.then(() => ng('test', '--watch=false')) .then(() => ng('test', '--watch=false'))

View File

@ -16,10 +16,10 @@ export default function () {
) )
.then(() => ng('generate', 'component', 'test-component')) .then(() => ng('generate', 'component', 'test-component'))
.then(() => expectFileToExist(compDir)) .then(() => expectFileToExist(compDir))
.then(() => expectFileToExist(join(compDir, 'test-component.component.ts'))) .then(() => expectFileToExist(join(compDir, 'test-component.ts')))
.then(() => expectFileToExist(join(compDir, 'test-component.component.spec.ts'))) .then(() => expectFileToExist(join(compDir, 'test-component.spec.ts')))
.then(() => expectFileToExist(join(compDir, 'test-component.component.ng.html'))) .then(() => expectFileToExist(join(compDir, 'test-component.ng.html')))
.then(() => expectFileToExist(join(compDir, 'test-component.component.css'))) .then(() => expectFileToExist(join(compDir, 'test-component.css')))
// Try to run the unit tests. // Try to run the unit tests.
.then(() => ng('test', '--watch=false')) .then(() => ng('test', '--watch=false'))

View File

@ -12,8 +12,8 @@ export default async function () {
// Generate component in application to verify that it's minimal // Generate component in application to verify that it's minimal
const { stdout } = await ng('generate', 'component', 'foo'); const { stdout } = await ng('generate', 'component', 'foo');
if (!stdout.includes('foo.component.scss')) { if (!stdout.includes('foo.scss')) {
throw new Error('Expected "foo.component.scss" to exist.'); throw new Error('Expected "foo.scss" to exist.');
} }
// Generate another project with different settings // Generate another project with different settings
@ -23,6 +23,7 @@ export default async function () {
config.projects['test-project-two'].schematics = { config.projects['test-project-two'].schematics = {
'@schematics/angular:component': { '@schematics/angular:component': {
style: 'less', style: 'less',
type: 'Component',
}, },
}; };
}); });

View File

@ -15,24 +15,21 @@ export default async function () {
// Setup an i18n enabled component // Setup an i18n enabled component
await ng('generate', 'component', 'i18n-test'); await ng('generate', 'component', 'i18n-test');
await writeFile( await writeFile(join('src/app/i18n-test', 'i18n-test.ng.html'), '<p i18n>Hello world</p>');
join('src/app/i18n-test', 'i18n-test.component.ng.html'),
'<p i18n>Hello world</p>',
);
await writeFile( await writeFile(
'src/app/app.component.ts', 'src/app/app.ts',
` `
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { I18nTestComponent } from './i18n-test/i18n-test.component'; import { I18nTest } from './i18n-test/i18n-test';
@Component({ @Component({
standalone: true, standalone: true,
selector: 'app-root', selector: 'app-root',
imports: [I18nTestComponent], imports: [I18nTest],
template: '<app-i18n-test />' template: '<app-i18n-test />'
}) })
export class AppComponent {} export class App {}
`, `,
); );

View File

@ -7,24 +7,17 @@ import { readNgVersion } from '../../utils/version';
export default async function () { export default async function () {
// Setup a library // Setup a library
await ng('generate', 'library', 'i18n-lib-test'); await ng('generate', 'library', 'i18n-lib-test');
await replaceInFile( await replaceInFile('projects/i18n-lib-test/src/lib/i18n-lib-test.ts', '<p>', '<p i18n>');
'projects/i18n-lib-test/src/lib/i18n-lib-test.component.ts',
'<p>',
'<p i18n>',
);
// Build library // Build library
await ng('build', 'i18n-lib-test', '--configuration=development'); await ng('build', 'i18n-lib-test', '--configuration=development');
// Consume library in application // Consume library in application
await replaceInFile('src/app/app.component.ts', 'imports: [', 'imports: [I18nLibTestComponent,'); await replaceInFile('src/app/app.ts', 'imports: [', 'imports: [I18nLibTest,');
await prependToFile( await prependToFile('src/app/app.ts', `import { I18nLibTest } from 'i18n-lib-test';`);
'src/app/app.component.ts',
`import { I18nLibTestComponent } from 'i18n-lib-test';`,
);
await writeFile( await writeFile(
'src/app/app.component.ng.html', 'src/app/app.ng.html',
` `
<p i18n>Hello world</p> <p i18n>Hello world</p>
<lib-i18n-lib-test></lib-i18n-lib-test> <lib-i18n-lib-test></lib-i18n-lib-test>
@ -42,11 +35,8 @@ export default async function () {
await ng('extract-i18n'); await ng('extract-i18n');
await expectFileToMatch('messages.xlf', 'Hello world'); await expectFileToMatch('messages.xlf', 'Hello world');
await expectFileToMatch('messages.xlf', 'i18n-lib-test works!'); await expectFileToMatch('messages.xlf', 'i18n-lib-test works!');
await expectFileToMatch('messages.xlf', 'src/app/app.component.ng.html'); await expectFileToMatch('messages.xlf', 'src/app/app.ng.html');
await expectFileToMatch( await expectFileToMatch('messages.xlf', 'projects/i18n-lib-test/src/lib/i18n-lib-test.ts');
'messages.xlf',
'projects/i18n-lib-test/src/lib/i18n-lib-test.component.ts',
);
await uninstallPackage('@angular/localize'); await uninstallPackage('@angular/localize');
} }

View File

@ -9,24 +9,21 @@ import { readNgVersion } from '../../utils/version';
export default async function () { export default async function () {
// Setup an i18n enabled component // Setup an i18n enabled component
await ng('generate', 'component', 'i18n-test'); await ng('generate', 'component', 'i18n-test');
await writeFile( await writeFile(join('src/app/i18n-test', 'i18n-test.ng.html'), '<p i18n>Hello world</p>');
join('src/app/i18n-test', 'i18n-test.component.ng.html'),
'<p i18n>Hello world</p>',
);
// Actually use the generated component to ensure it is present in the application output // Actually use the generated component to ensure it is present in the application output
await writeFile( await writeFile(
'src/app/app.component.ts', 'src/app/app.ts',
` `
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { I18nTestComponent } from './i18n-test/i18n-test.component'; import { I18nTest } from './i18n-test/i18n-test';
@Component({ @Component({
standalone: true, standalone: true,
selector: 'app-root', selector: 'app-root',
imports: [I18nTestComponent], imports: [I18nTest],
template: '<app-i18n-test />' template: '<app-i18n-test />'
}) })
export class AppComponent {} export class App {}
`, `,
); );

View File

@ -17,7 +17,7 @@ export default async function () {
: readNgVersion(); : readNgVersion();
}); });
await appendToFile('src/app/app.component.ng.html', '<router-outlet></router-outlet>'); await appendToFile('src/app/app.ng.html', '<router-outlet></router-outlet>');
// Add app-shell and service-worker // Add app-shell and service-worker
await silentNg('generate', 'app-shell'); await silentNg('generate', 'app-shell');

View File

@ -23,7 +23,7 @@ export default async function () {
: readNgVersion(); : readNgVersion();
}); });
await appendToFile('src/app/app.component.ng.html', '<router-outlet></router-outlet>'); await appendToFile('src/app/app.ng.html', '<router-outlet></router-outlet>');
await ng('generate', 'app-shell', '--project', 'test-project'); await ng('generate', 'app-shell', '--project', 'test-project');
if (isSnapshotBuild) { if (isSnapshotBuild) {
@ -62,7 +62,7 @@ export default async function () {
}); });
await writeFile( await writeFile(
'src/app/app-shell/app-shell.component.ng.html', 'src/app/app-shell/app-shell.ng.html',
'<h1 i18n="An introduction header for this sample">Hello i18n!</h1>', '<h1 i18n="An introduction header for this sample">Hello i18n!</h1>',
); );
@ -70,7 +70,7 @@ export default async function () {
// Extraction of i18n only works on browser targets. // Extraction of i18n only works on browser targets.
// Let's add the same translation that there is in the app-shell // Let's add the same translation that there is in the app-shell
await writeFile( await writeFile(
'src/app/app.component.ng.html', 'src/app/app.ng.html',
'<h1 i18n="An introduction header for this sample">Hello i18n!</h1>', '<h1 i18n="An introduction header for this sample">Hello i18n!</h1>',
); );
@ -79,9 +79,9 @@ export default async function () {
await expectFileToMatch('src/locale/messages.xlf', `source-language="en-US"`); await expectFileToMatch('src/locale/messages.xlf', `source-language="en-US"`);
await expectFileToMatch('src/locale/messages.xlf', `An introduction header for this sample`); await expectFileToMatch('src/locale/messages.xlf', `An introduction header for this sample`);
// Clean up app.component.ng.html so that we can easily // Clean up app.ng.html so that we can easily
// find the translation text // find the translation text
await writeFile('src/app/app.component.ng.html', '<router-outlet></router-outlet>'); await writeFile('src/app/app.ng.html', '<router-outlet></router-outlet>');
for (const { lang, translation } of langTranslations) { for (const { lang, translation } of langTranslations) {
if (lang != 'en-US') { if (lang != 'en-US') {

View File

@ -98,7 +98,7 @@ export const baseHrefs: { [l: string]: string } = {
export async function setupI18nConfig() { export async function setupI18nConfig() {
// Add component with i18n content, both translations and localeData (plural, dates). // Add component with i18n content, both translations and localeData (plural, dates).
await writeFile( await writeFile(
'src/app/app.component.ts', 'src/app/app.ts',
` `
import { Component, Inject, LOCALE_ID } from '@angular/core'; import { Component, Inject, LOCALE_ID } from '@angular/core';
import { DatePipe } from '@angular/common'; import { DatePipe } from '@angular/common';
@ -108,9 +108,9 @@ export async function setupI18nConfig() {
selector: 'app-root', selector: 'app-root',
imports: [DatePipe, RouterOutlet], imports: [DatePipe, RouterOutlet],
standalone: true, standalone: true,
templateUrl: './app.component.ng.html' templateUrl: './app.ng.html'
}) })
export class AppComponent { export class App {
constructor(@Inject(LOCALE_ID) public locale: string) { } constructor(@Inject(LOCALE_ID) public locale: string) { }
title = 'i18n'; title = 'i18n';
jan = new Date(2000, 0, 1); jan = new Date(2000, 0, 1);
@ -119,7 +119,7 @@ export async function setupI18nConfig() {
`, `,
); );
await writeFile( await writeFile(
`src/app/app.component.ng.html`, `src/app/app.ng.html`,
` `
<p id="hello" i18n="An introduction header for this sample">Hello {{ title }}! </p> <p id="hello" i18n="An introduction header for this sample">Hello {{ title }}! </p>
<p id="locale">{{ locale }}</p> <p id="locale">{{ locale }}</p>
@ -140,7 +140,7 @@ export async function setupI18nConfig() {
<trans-unit id="4286451273117902052" datatype="html"> <trans-unit id="4286451273117902052" datatype="html">
<source>Hello <x id="INTERPOLATION" equiv-text="{{ title }}"/>! </source> <source>Hello <x id="INTERPOLATION" equiv-text="{{ title }}"/>! </source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.ng.html</context> <context context-type="sourcefile">src/app/app.ng.html</context>
<context context-type="linenumber">2,3</context> <context context-type="linenumber">2,3</context>
</context-group> </context-group>
<note priority="1" from="description">An introduction header for this sample</note> <note priority="1" from="description">An introduction header for this sample</note>
@ -148,14 +148,14 @@ export async function setupI18nConfig() {
<trans-unit id="4606963464835766483" datatype="html"> <trans-unit id="4606963464835766483" datatype="html">
<source>Updated <x id="ICU" equiv-text="{minutes, plural, =0 {just now} =1 {one minute ago} other {{{minutes}} minutes ago}}" xid="1887283401472369100"/></source> <source>Updated <x id="ICU" equiv-text="{minutes, plural, =0 {just now} =1 {one minute ago} other {{{minutes}} minutes ago}}" xid="1887283401472369100"/></source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.ng.html</context> <context context-type="sourcefile">src/app/app.ng.html</context>
<context context-type="linenumber">5,6</context> <context context-type="linenumber">5,6</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="2002272803511843863" datatype="html"> <trans-unit id="2002272803511843863" datatype="html">
<source>{VAR_PLURAL, plural, =0 {just now} =1 {one minute ago} other {<x id="INTERPOLATION"/> minutes ago}}</source> <source>{VAR_PLURAL, plural, =0 {just now} =1 {one minute ago} other {<x id="INTERPOLATION"/> minutes ago}}</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.ng.html</context> <context context-type="sourcefile">src/app/app.ng.html</context>
<context context-type="linenumber">5,6</context> <context context-type="linenumber">5,6</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
@ -168,7 +168,7 @@ export async function setupI18nConfig() {
// ng serve support: https://github.com/angular/angular-cli/issues/16248 // ng serve support: https://github.com/angular/angular-cli/issues/16248
await writeFile('src/app/dynamic.ts', `export const abc = 5;`); await writeFile('src/app/dynamic.ts', `export const abc = 5;`);
await appendToFile( await appendToFile(
'src/app/app.component.ts', 'src/app/app.ts',
` `
(async () => { await import('./dynamic'); })(); (async () => { await import('./dynamic'); })();
`, `,

View File

@ -11,7 +11,7 @@ export default async function () {
} }
// Workaround for https://github.com/angular/angular/issues/32192 // Workaround for https://github.com/angular/angular/issues/32192
await replaceInFile('src/app/app.component.ng.html', /class="material-icons"/g, ''); await replaceInFile('src/app/app.ng.html', /class="material-icons"/g, '');
await ng('build'); await ng('build');

View File

@ -15,5 +15,5 @@ export default async function () {
throw new Error(`Expected stderr to contain: "${warningMatch}".`); throw new Error(`Expected stderr to contain: "${warningMatch}".`);
} }
await expectFileToExist('src/app/test-component/test-component.component.sass'); await expectFileToExist('src/app/test-component/test-component.sass');
} }

View File

@ -5,12 +5,12 @@ export default async function () {
await ng('generate', 'service', 'user'); await ng('generate', 'service', 'user');
// Update the application to use the new service // Update the application to use the new service
await prependToFile('src/app/app.component.ts', "import { UserService } from './user.service';"); await prependToFile('src/app/app.ts', "import { UserService } from './user.service';");
await replaceInFile( await replaceInFile(
'src/app/app.component.ts', 'src/app/app.ts',
'export class AppComponent {', 'export class App {',
'export class AppComponent {\n constructor(user: UserService) {}', 'export class App {\n constructor(user: UserService) {}',
); );
// Execute the application's tests with emitDecoratorMetadata disabled (default) // Execute the application's tests with emitDecoratorMetadata disabled (default)

View File

@ -5,25 +5,25 @@ import { expectToFail } from '../../utils/utils';
export default async function () { export default async function () {
// Update the application to use a forward reference // Update the application to use a forward reference
await replaceInFile( await replaceInFile(
'src/app/app.component.ts', 'src/app/app.ts',
"import { Component } from '@angular/core';", "import { Component } from '@angular/core';",
"import { Component, Inject, Injectable, forwardRef } from '@angular/core';", "import { Component, Inject, Injectable, forwardRef } from '@angular/core';",
); );
await appendToFile('src/app/app.component.ts', '\n@Injectable() export class Lock { }\n'); await appendToFile('src/app/app.ts', '\n@Injectable() export class Lock { }\n');
await replaceInFile( await replaceInFile(
'src/app/app.component.ts', 'src/app/app.ts',
'export class AppComponent {', 'export class App {',
'export class AppComponent {\n constructor(@Inject(forwardRef(() => Lock)) lock: Lock) {}', 'export class App {\n constructor(@Inject(forwardRef(() => Lock)) lock: Lock) {}',
); );
// Update the application's unit tests to include the new injectable // Update the application's unit tests to include the new injectable
await replaceInFile( await replaceInFile(
'src/app/app.component.spec.ts', 'src/app/app.spec.ts',
"import { AppComponent } from './app.component';", "import { App } from './app';",
"import { AppComponent, Lock } from './app.component';", "import { App, Lock } from './app';",
); );
await replaceInFile( await replaceInFile(
'src/app/app.component.spec.ts', 'src/app/app.spec.ts',
'TestBed.configureTestingModule({', 'TestBed.configureTestingModule({',
'TestBed.configureTestingModule({ providers: [Lock],', 'TestBed.configureTestingModule({ providers: [Lock],',
); );

View File

@ -16,7 +16,7 @@ export default async function () {
await replaceInFile( await replaceInFile(
'src/app/app.routes.ts', 'src/app/app.routes.ts',
'routes: Routes = [];', 'routes: Routes = [];',
`routes: Routes = [{path: 'lazy', loadComponent: () => import('./lazy/lazy.component').then(c => c.LazyComponent)}];`, `routes: Routes = [{path: 'lazy', loadComponent: () => import('./lazy/lazy').then(c => c.Lazy)}];`,
); );
// Add lazy route e2e // Add lazy route e2e

View File

@ -5,7 +5,7 @@ import { expectToFail } from '../../utils/utils';
export default async function () { export default async function () {
// This test is already in build-angular, but that doesn't run on Windows. // This test is already in build-angular, but that doesn't run on Windows.
await silentNg('test', '--no-watch', '--code-coverage'); await silentNg('test', '--no-watch', '--code-coverage');
await expectFileToExist('coverage/test-project/app.component.ts.html'); await expectFileToExist('coverage/test-project/app.ts.html');
// Delete coverage directory // Delete coverage directory
await rimraf('coverage'); await rimraf('coverage');
@ -13,10 +13,10 @@ export default async function () {
'test', 'test',
'--no-watch', '--no-watch',
'--code-coverage', '--code-coverage',
`--code-coverage-exclude='src/**/app.component.ts'`, `--code-coverage-exclude='src/**/app.ts'`,
); );
// Doesn't include excluded. // Doesn't include excluded.
await expectFileToExist('coverage/test-project/index.html'); await expectFileToExist('coverage/test-project/index.html');
await expectToFail(() => expectFileToExist('coverage/test-project/app.component.ts.html')); await expectToFail(() => expectFileToExist('coverage/test-project/app.ts.html'));
} }

View File

@ -6,7 +6,7 @@ export default function () {
// TODO(architect): Delete this test. It is now in devkit/build-angular. // TODO(architect): Delete this test. It is now in devkit/build-angular.
// Fails on single run with broken compilation. // Fails on single run with broken compilation.
return writeFile('src/app.component.spec.ts', '<p> definitely not typescript </p>').then(() => return writeFile('src/app.spec.ts', '<p> definitely not typescript </p>').then(() =>
expectToFail(() => ng('test', '--watch=false')), expectToFail(() => ng('test', '--watch=false')),
); );
} }

View File

@ -3,12 +3,12 @@ import { writeFile } from '../../utils/fs';
export default async function () { export default async function () {
await writeFile( await writeFile(
'src/app/app.component.spec.ts', 'src/app/app.spec.ts',
` `
import { TestBed } from '@angular/core/testing'; import { TestBed } from '@angular/core/testing';
import { AppComponent } from './app.component'; import { App } from './app';
describe('AppComponent', () => { describe('App', () => {
beforeAll(() => { beforeAll(() => {
jasmine.clock().install(); jasmine.clock().install();
}); });
@ -18,11 +18,11 @@ export default async function () {
}); });
beforeEach(() => TestBed.configureTestingModule({ beforeEach(() => TestBed.configureTestingModule({
imports: [AppComponent] imports: [App]
})); }));
it('should create the app', () => { it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent); const fixture = TestBed.createComponent(App);
expect(fixture.componentInstance).toBeTruthy(); expect(fixture.componentInstance).toBeTruthy();
}); });
}); });

View File

@ -16,31 +16,31 @@ export default async function () {
declare var stringScriptGlobal: any; declare var stringScriptGlobal: any;
declare var inputScriptGlobal: any; declare var inputScriptGlobal: any;
`, `,
'src/app/app.component.ts': ` 'src/app/app.ts': `
import { Component } from '@angular/core'; import { Component } from '@angular/core';
@Component({ selector: 'app-root', template: '', standalone: false }) @Component({ selector: 'app-root', template: '', standalone: false })
export class AppComponent { export class App {
stringScriptGlobalProp = stringScriptGlobal; stringScriptGlobalProp = stringScriptGlobal;
inputScriptGlobalProp = inputScriptGlobal; inputScriptGlobalProp = inputScriptGlobal;
} }
`, `,
'src/app/app.component.spec.ts': ` 'src/app/app.spec.ts': `
import { TestBed } from '@angular/core/testing'; import { TestBed } from '@angular/core/testing';
import { AppComponent } from './app.component'; import { App } from './app';
describe('AppComponent', () => { describe('App', () => {
beforeEach(() => TestBed.configureTestingModule({ beforeEach(() => TestBed.configureTestingModule({
declarations: [AppComponent] declarations: [App]
})); }));
it('should have access to string-script.js', () => { it('should have access to string-script.js', () => {
let app = TestBed.createComponent(AppComponent).debugElement.componentInstance; let app = TestBed.createComponent(App).debugElement.componentInstance;
expect(app.stringScriptGlobalProp).toEqual('string-scripts.js'); expect(app.stringScriptGlobalProp).toEqual('string-scripts.js');
}); });
it('should have access to input-script.js', () => { it('should have access to input-script.js', () => {
let app = TestBed.createComponent(AppComponent).debugElement.componentInstance; let app = TestBed.createComponent(App).debugElement.componentInstance;
expect(app.inputScriptGlobalProp).toEqual('input-scripts.js'); expect(app.inputScriptGlobalProp).toEqual('input-scripts.js');
}); });
}); });

View File

@ -6,7 +6,7 @@ import { assertIsError } from '../../utils/utils';
export default async function () { export default async function () {
await writeFile( await writeFile(
'src/app/app.component.spec.ts', 'src/app/app.spec.ts',
` `
it('should fail', () => { it('should fail', () => {
expect(undefined).toBeTruthy(); expect(undefined).toBeTruthy();
@ -20,7 +20,7 @@ export default async function () {
throw new Error('ng test should have failed.'); throw new Error('ng test should have failed.');
} catch (error) { } catch (error) {
assertIsError(error); assertIsError(error);
assert.match(error.message, /\(src\/app\/app\.component\.spec\.ts:3:27/); assert.match(error.message, /\(src\/app\/app\.spec\.ts:3:27/);
assert.doesNotMatch(error.message, /_karma_webpack_/); assert.doesNotMatch(error.message, /_karma_webpack_/);
} }

View File

@ -19,14 +19,14 @@ export default async function () {
await installWorkspacePackages(); await installWorkspacePackages();
await writeMultipleFiles({ await writeMultipleFiles({
// Replace the template of app.component.ng.html as it makes it harder to debug // Replace the template of app.ng.html as it makes it harder to debug
'src/app/app.component.ng.html': '<router-outlet />', 'src/app/app.ng.html': '<router-outlet />',
'src/app/app.routes.ts': ` 'src/app/app.routes.ts': `
import { Routes } from '@angular/router'; import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component'; import { Home } from './home/home';
export const routes: Routes = [ export const routes: Routes = [
{ path: 'home', component: HomeComponent } { path: 'home', component: Home }
]; ];
`, `,
'src/app/app.routes.server.ts': ` 'src/app/app.routes.server.ts': `
@ -87,7 +87,7 @@ export default async function () {
// Modify the home component and validate the change. // Modify the home component and validate the change.
await modifyFileAndWaitUntilUpdated( await modifyFileAndWaitUntilUpdated(
'src/app/home/home.component.ng.html', 'src/app/home/home.ng.html',
'home works', 'home works',
'yay home works!!!', 'yay home works!!!',
true, true,

View File

@ -20,14 +20,14 @@ export default async function () {
await installPackage('fastify@5'); await installPackage('fastify@5');
await writeMultipleFiles({ await writeMultipleFiles({
// Replace the template of app.component.ng.html as it makes it harder to debug // Replace the template of app.ng.html as it makes it harder to debug
'src/app/app.component.ng.html': '<router-outlet />', 'src/app/app.ng.html': '<router-outlet />',
'src/app/app.routes.ts': ` 'src/app/app.routes.ts': `
import { Routes } from '@angular/router'; import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component'; import { Home } from './home/home';
export const routes: Routes = [ export const routes: Routes = [
{ path: 'home', component: HomeComponent } { path: 'home', component: Home }
]; ];
`, `,
'src/app/app.routes.server.ts': ` 'src/app/app.routes.server.ts': `
@ -87,7 +87,7 @@ export default async function () {
// Modify the home component and validate the change. // Modify the home component and validate the change.
await modifyFileAndWaitUntilUpdated( await modifyFileAndWaitUntilUpdated(
'src/app/home/home.component.ng.html', 'src/app/home/home.ng.html',
'home works', 'home works',
'yay home works!!!', 'yay home works!!!',
true, true,

View File

@ -20,14 +20,14 @@ export default async function () {
await installPackage('h3@1'); await installPackage('h3@1');
await writeMultipleFiles({ await writeMultipleFiles({
// Replace the template of app.component.ng.html as it makes it harder to debug // Replace the template of app.ng.html as it makes it harder to debug
'src/app/app.component.ng.html': '<router-outlet />', 'src/app/app.ng.html': '<router-outlet />',
'src/app/app.routes.ts': ` 'src/app/app.routes.ts': `
import { Routes } from '@angular/router'; import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component'; import { Home } from './home/home';
export const routes: Routes = [ export const routes: Routes = [
{ path: 'home', component: HomeComponent } { path: 'home', component: Home }
]; ];
`, `,
'src/app/app.routes.server.ts': ` 'src/app/app.routes.server.ts': `
@ -78,7 +78,7 @@ export default async function () {
// Modify the home component and validate the change. // Modify the home component and validate the change.
await modifyFileAndWaitUntilUpdated( await modifyFileAndWaitUntilUpdated(
'src/app/home/home.component.ng.html', 'src/app/home/home.ng.html',
'home works', 'home works',
'yay home works!!!', 'yay home works!!!',
true, true,

View File

@ -20,14 +20,14 @@ export default async function () {
await installPackage('hono@4'); await installPackage('hono@4');
await writeMultipleFiles({ await writeMultipleFiles({
// Replace the template of app.component.ng.html as it makes it harder to debug // Replace the template of app.ng.html as it makes it harder to debug
'src/app/app.component.ng.html': '<router-outlet />', 'src/app/app.ng.html': '<router-outlet />',
'src/app/app.routes.ts': ` 'src/app/app.routes.ts': `
import { Routes } from '@angular/router'; import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component'; import { Home } from './home/home';
export const routes: Routes = [ export const routes: Routes = [
{ path: 'home', component: HomeComponent } { path: 'home', component: Home }
]; ];
`, `,
'src/app/app.routes.server.ts': ` 'src/app/app.routes.server.ts': `
@ -70,7 +70,7 @@ export default async function () {
// Modify the home component and validate the change. // Modify the home component and validate the change.
await modifyFileAndWaitUntilUpdated( await modifyFileAndWaitUntilUpdated(
'src/app/home/home.component.ng.html', 'src/app/home/home.ng.html',
'home works', 'home works',
'yay home works!!!', 'yay home works!!!',
true, true,

View File

@ -22,7 +22,7 @@ export default async function () {
// Create Error. // Create Error.
await appendToFile( await appendToFile(
'src/app/app.component.ts', 'src/app/app.ts',
` `
(() => { (() => {
throw new Error('something happened!'); throw new Error('something happened!');
@ -37,7 +37,7 @@ export default async function () {
// The error is also sent in the browser, so we don't need to scrap the stderr. // The error is also sent in the browser, so we don't need to scrap the stderr.
match( match(
text, text,
/something happened.+at eval \(.+[\\/]+e2e-test[\\/]+test-project[\\/]+src[\\/]+app[\\/]+app\.component\.ts:\d+:\d+\)/, /something happened.+at eval \(.+[\\/]+e2e-test[\\/]+test-project[\\/]+src[\\/]+app[\\/]+app\.ts:\d+:\d+\)/,
); );
doesNotMatch(text, /vite-root/); doesNotMatch(text, /vite-root/);
} }

View File

@ -18,14 +18,14 @@ export default async function () {
await installWorkspacePackages(); await installWorkspacePackages();
await writeMultipleFiles({ await writeMultipleFiles({
// Replace the template of app.component.ng.html as it makes it harder to debug // Replace the template of app.ng.html as it makes it harder to debug
'src/app/app.component.ng.html': '<router-outlet />', 'src/app/app.ng.html': '<router-outlet />',
'src/app/app.routes.ts': ` 'src/app/app.routes.ts': `
import { Routes } from '@angular/router'; import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component'; import { Home } from './home/home';
export const routes: Routes = [ export const routes: Routes = [
{ path: 'home', component: HomeComponent } { path: 'home', component: Home }
]; ];
`, `,
'src/app/app.routes.server.ts': ` 'src/app/app.routes.server.ts': `