Skip to content

Commit 755f3a0

Browse files
aparzijkrems
authored andcommitted
feat(@schematics/angular): add option to setup new workspace or application as zoneless mode
1 parent 5f473af commit 755f3a0

File tree

12 files changed

+118
-10
lines changed

12 files changed

+118
-10
lines changed

packages/schematics/angular/application/files/module-files/src/app/app.component.spec.ts.template

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { TestBed } from '@angular/core/testing';<% if (routing) { %>
1+
<% if(experimentalZoneless) { %> import { provideExperimentalZonelessChangeDetection } from '@angular/core'; <% } %>import { TestBed } from '@angular/core/testing';<% if (routing) { %>
22
import { RouterModule } from '@angular/router';<% } %>
33
import { AppComponent } from './app.component';
44

@@ -11,6 +11,7 @@ describe('AppComponent', () => {
1111
declarations: [
1212
AppComponent
1313
],
14+
<% if(experimentalZoneless) { %>providers: [provideExperimentalZonelessChangeDetection()]<% } %>
1415
}).compileComponents();
1516
});
1617

packages/schematics/angular/application/files/module-files/src/app/app.module.ts.template

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { NgModule } from '@angular/core';
1+
import { NgModule<% if(experimentalZoneless) { %>, provideExperimentalZonelessChangeDetection<% } %> } from '@angular/core';
22
import { BrowserModule } from '@angular/platform-browser';
33
<% if (routing) { %>
44
import { AppRoutingModule } from './app-routing.module';<% } %>
@@ -12,7 +12,7 @@ import { AppComponent } from './app.component';
1212
BrowserModule<% if (routing) { %>,
1313
AppRoutingModule<% } %>
1414
],
15-
providers: [],
15+
providers: [<% if (experimentalZoneless) { %>provideExperimentalZonelessChangeDetection()<% } %>],
1616
bootstrap: [AppComponent]
1717
})
1818
export class AppModule { }
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
<% if(!!viewEncapsulation) { %>import { ViewEncapsulation } from '@angular/core';
22
<% }%>import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
3-
43
import { AppModule } from './app/app.module';
54

65
platformBrowserDynamic().bootstrapModule(AppModule, {
7-
ngZoneEventCoalescing: true<% if(!!viewEncapsulation) { %>,
6+
<% if(!experimentalZoneless) { %>ngZoneEventCoalescing: true,<% } %><% if(!!viewEncapsulation) { %>
87
defaultEncapsulation: ViewEncapsulation.<%= viewEncapsulation %><% } %>
98
})
109
.catch(err => console.error(err));

packages/schematics/angular/application/files/standalone-files/src/app/app.component.spec.ts.template

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
<% if(experimentalZoneless) { %> import { provideExperimentalZonelessChangeDetection } from '@angular/core'; <% } %>
12
import { TestBed } from '@angular/core/testing';
23
import { AppComponent } from './app.component';
34

45
describe('AppComponent', () => {
56
beforeEach(async () => {
67
await TestBed.configureTestingModule({
78
imports: [AppComponent],
9+
<% if(experimentalZoneless) { %>providers: [provideExperimentalZonelessChangeDetection()]<% } %>
810
}).compileComponents();
911
});
1012

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';<% if (routing) { %>
1+
import { ApplicationConfig, <% if(!experimentalZoneless) { %>provideZoneChangeDetection<% } else { %>provideExperimentalZonelessChangeDetection<% } %> } from '@angular/core';<% if (routing) { %>
22
import { provideRouter } from '@angular/router';
33

44
import { routes } from './app.routes';<% } %>
55

66
export const appConfig: ApplicationConfig = {
7-
providers: [provideZoneChangeDetection({ eventCoalescing: true })<% if (routing) { %>, provideRouter(routes)<% } %>]
7+
providers: [
8+
<% if(experimentalZoneless) { %>provideExperimentalZonelessChangeDetection()<% } else { %>provideZoneChangeDetection({ eventCoalescing: true })<% } %><% if (routing) {%>, provideRouter(routes)<% } %>
9+
]
810
};

packages/schematics/angular/application/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ function addAppToWorkspaceFile(
239239
outputPath: `dist/${folderName}`,
240240
index: `${sourceRoot}/index.html`,
241241
browser: `${sourceRoot}/main.ts`,
242-
polyfills: ['zone.js'],
242+
polyfills: options.experimentalZoneless ? [] : ['zone.js'],
243243
tsConfig: `${projectRoot}tsconfig.app.json`,
244244
inlineStyleLanguage,
245245
assets: [{ 'glob': '**/*', 'input': `${projectRoot}public` }],
@@ -279,7 +279,7 @@ function addAppToWorkspaceFile(
279279
: {
280280
builder: Builders.Karma,
281281
options: {
282-
polyfills: ['zone.js', 'zone.js/testing'],
282+
polyfills: options.experimentalZoneless ? [] : ['zone.js', 'zone.js/testing'],
283283
tsConfig: `${projectRoot}tsconfig.spec.json`,
284284
inlineStyleLanguage,
285285
assets: [{ 'glob': '**/*', 'input': `${projectRoot}public` }],

packages/schematics/angular/application/index_spec.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -698,5 +698,77 @@ describe('Application Schematic', () => {
698698
}),
699699
);
700700
});
701+
702+
it('should add provideExperimentalZonelessChangeDetection() in app.module.ts when experimentalZoneless is true', async () => {
703+
const tree = await schematicRunner.runSchematic(
704+
'application',
705+
{
706+
...defaultOptions,
707+
experimentalZoneless: true,
708+
standalone: false,
709+
},
710+
workspaceTree,
711+
);
712+
const path = '/projects/foo/src/app/app.module.ts';
713+
const fileContent = tree.readContent(path);
714+
expect(fileContent).toContain('provideExperimentalZonelessChangeDetection()');
715+
});
716+
717+
it('should not add provideExperimentalZonelessChangeDetection() in app.module.ts when experimentalZoneless is false', async () => {
718+
const tree = await schematicRunner.runSchematic(
719+
'application',
720+
{
721+
...defaultOptions,
722+
experimentalZoneless: false,
723+
standalone: false,
724+
},
725+
workspaceTree,
726+
);
727+
const path = '/projects/foo/src/app/app.module.ts';
728+
const fileContent = tree.readContent(path);
729+
expect(fileContent).not.toContain('provideExperimentalZonelessChangeDetection()');
730+
});
731+
732+
it('should add provideExperimentalZonelessChangeDetection() when experimentalZoneless is true', async () => {
733+
const tree = await schematicRunner.runSchematic(
734+
'application',
735+
{
736+
...defaultOptions,
737+
experimentalZoneless: true,
738+
},
739+
workspaceTree,
740+
);
741+
const path = '/projects/foo/src/app/app.config.ts';
742+
const fileContent = tree.readContent(path);
743+
expect(fileContent).toContain('provideExperimentalZonelessChangeDetection()');
744+
});
745+
746+
it('should not add provideExperimentalZonelessChangeDetection() when experimentalZoneless is false', async () => {
747+
const tree = await schematicRunner.runSchematic(
748+
'application',
749+
{
750+
...defaultOptions,
751+
experimentalZoneless: false,
752+
},
753+
workspaceTree,
754+
);
755+
const path = '/projects/foo/src/app/app.config.ts';
756+
const fileContent = tree.readContent(path);
757+
expect(fileContent).not.toContain('provideExperimentalZonelessChangeDetection()');
758+
});
759+
760+
it('should not add provideZoneChangeDetection when experimentalZoneless is true', async () => {
761+
const tree = await schematicRunner.runSchematic(
762+
'application',
763+
{
764+
...defaultOptions,
765+
experimentalZoneless: true,
766+
},
767+
workspaceTree,
768+
);
769+
const path = '/projects/foo/src/app/app.config.ts';
770+
const fileContent = tree.readContent(path);
771+
expect(fileContent).not.toContain('provideZoneChangeDetection');
772+
});
701773
});
702774
});

packages/schematics/angular/application/schema.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,11 @@
117117
"type": "boolean",
118118
"default": false,
119119
"x-user-analytics": "ep.ng_ssr"
120+
},
121+
"experimentalZoneless": {
122+
"description": "Create an application that does not utilize zone.js.",
123+
"type": "boolean",
124+
"default": false
120125
}
121126
},
122127
"required": ["name"]

packages/schematics/angular/ng-new/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ export default function (options: NgNewOptions): Rule {
5757
minimal: options.minimal,
5858
standalone: options.standalone,
5959
ssr: options.ssr,
60+
experimentalZoneless: options.experimentalZoneless,
6061
};
6162

6263
return chain([

packages/schematics/angular/ng-new/schema.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,11 @@
138138
"description": "Creates an application with Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering) enabled.",
139139
"type": "boolean",
140140
"x-user-analytics": "ep.ng_ssr"
141+
},
142+
"experimentalZoneless": {
143+
"description": "Create an application that does not utilize zone.js.",
144+
"type": "boolean",
145+
"default": false
141146
}
142147
},
143148
"required": ["name", "version"]

packages/schematics/angular/service-worker/index_spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ describe('Service Worker Schematic', () => {
131131
provideServiceWorker('ngsw-worker.js', {
132132
enabled: !isDevMode(),
133133
registrationStrategy: 'registerWhenStable:30000'
134-
})
134+
})
135135
`);
136136
});
137137

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { ng } from '../../../utils/process';
2+
import { useCIChrome } from '../../../utils/project';
3+
4+
export default async function () {
5+
await ng('generate', 'app', 'standalone', '--experimental-zoneless', '--standalone');
6+
await useCIChrome('standalone', 'projects/standalone');
7+
await ng('test', 'standalone', '--watch=false');
8+
await ng('build', 'standalone');
9+
10+
await ng(
11+
'generate',
12+
'app',
13+
'ngmodules',
14+
'--experimental-zoneless',
15+
'--no-standalone',
16+
'--skip-install',
17+
);
18+
await useCIChrome('ngmodules', 'projects/ngmodules');
19+
await ng('test', 'ngmodules', '--watch=false');
20+
await ng('build', 'ngmodules');
21+
}

0 commit comments

Comments
 (0)