Skip to content

Commit 93ecc46

Browse files
committed
feat(@schematics/angular): add option to setup new workspace or application as zoneless mode
1 parent c0b76e3 commit 93ecc46

File tree

11 files changed

+86
-8
lines changed

11 files changed

+86
-8
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

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: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -698,5 +698,47 @@ describe('Application Schematic', () => {
698698
}),
699699
);
700700
});
701+
702+
it('should add provideExperimentalZonelessChangeDetection() when experimentalZoneless is true', async () => {
703+
const tree = await schematicRunner.runSchematic(
704+
'application',
705+
{
706+
...defaultOptions,
707+
experimentalZoneless: true,
708+
},
709+
workspaceTree,
710+
);
711+
const path = '/projects/foo/src/app/app.config.ts';
712+
const fileContent = tree.readContent(path);
713+
expect(fileContent).toContain('provideExperimentalZonelessChangeDetection()');
714+
});
715+
716+
it('should not add provideExperimentalZonelessChangeDetection() when experimentalZoneless is false', async () => {
717+
const tree = await schematicRunner.runSchematic(
718+
'application',
719+
{
720+
...defaultOptions,
721+
experimentalZoneless: false,
722+
},
723+
workspaceTree,
724+
);
725+
const path = '/projects/foo/src/app/app.config.ts';
726+
const fileContent = tree.readContent(path);
727+
expect(fileContent).not.toContain('provideExperimentalZonelessChangeDetection()');
728+
});
729+
730+
it('should not add provideZoneChangeDetection when experimentalZoneless is true', async () => {
731+
const tree = await schematicRunner.runSchematic(
732+
'application',
733+
{
734+
...defaultOptions,
735+
experimentalZoneless: true,
736+
},
737+
workspaceTree,
738+
);
739+
const path = '/projects/foo/src/app/app.config.ts';
740+
const fileContent = tree.readContent(path);
741+
expect(fileContent).not.toContain('provideZoneChangeDetection');
742+
});
701743
});
702744
});

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

0 commit comments

Comments
 (0)