Skip to content

Commit 1de6d71

Browse files
alan-agius4filipesilva
authored andcommitted
feat(@schematics/angular): production builds by default
With this change we do several changes to the `angular.json` configuration for `build` , `server` and `app-shell` targets so that these are `production` by default. - build, server and app-shell targets are configured to run production by default. - We add a new configuration named `development` to run the mentioned builder targets in development. Ex: `ng build --configuration development`. - When adding `universal` or `app-shell`, we generate the full set of configurations as per the `buiid` target. Previously, we only generated the `production` configuration. - We added a helper script in `package.json` to run build in watch mode. `npm run watch` which is a shortcut for `ng build --watch --configuration development`
1 parent a5877bf commit 1de6d71

File tree

16 files changed

+128
-108
lines changed

16 files changed

+128
-108
lines changed

packages/angular/pwa/pwa/index_spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ describe('PWA Schematic', () => {
5252
schematicRunner.runSchematicAsync('ng-add', defaultOptions, appTree).toPromise().then(tree => {
5353
const configText = tree.readContent('/angular.json');
5454
const config = JSON.parse(configText);
55-
const swFlag = config.projects.bar.architect.build.configurations.production.serviceWorker;
55+
const swFlag = config.projects.bar.architect.build.options.serviceWorker;
5656
expect(swFlag).toEqual(true);
5757
done();
5858
}, done.fail);

packages/schematics/angular/app-shell/index.ts

+40-16
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ function addUniversalTarget(options: AppShellOptions): Rule {
155155
}
156156

157157
function addAppShellConfigToWorkspace(options: AppShellOptions): Rule {
158-
return () => {
158+
return (host, context) => {
159159
if (!options.route) {
160160
throw new SchematicsException(`Route is not defined`);
161161
}
@@ -166,20 +166,44 @@ function addAppShellConfigToWorkspace(options: AppShellOptions): Rule {
166166
return;
167167
}
168168

169+
// Validation of targets is handled already in the main function.
170+
// Duplicate keys means that we have configurations in both server and build builders.
171+
const serverConfigKeys = project.targets.get('server')?.configurations ?? {};
172+
const buildConfigKeys = project.targets.get('build')?.configurations ?? {};
173+
174+
const configurationNames = Object.keys({
175+
...serverConfigKeys,
176+
...buildConfigKeys,
177+
});
178+
179+
const configurations: Record<string, {}> = {};
180+
for (const key of configurationNames) {
181+
if (!serverConfigKeys[key]) {
182+
context.logger.warn(`Skipped adding "${key}" configuration to "app-shell" target as it's missing from "server" target.`);
183+
184+
continue;
185+
}
186+
187+
if (!buildConfigKeys[key]) {
188+
context.logger.warn(`Skipped adding "${key}" configuration to "app-shell" target as it's missing from "build" target.`);
189+
190+
continue;
191+
}
192+
193+
configurations[key] = {
194+
browserTarget: `${options.clientProject}:build:${key}`,
195+
serverTarget: `${options.clientProject}:server:${key}`,
196+
};
197+
}
198+
169199
project.targets.add({
170200
name: 'app-shell',
171201
builder: Builders.AppShell,
202+
defaultConfiguration: configurations['production'] ? 'production' : undefined,
172203
options: {
173-
browserTarget: `${options.clientProject}:build`,
174-
serverTarget: `${options.clientProject}:server`,
175204
route: options.route,
176205
},
177-
configurations: {
178-
production: {
179-
browserTarget: `${options.clientProject}:build:production`,
180-
serverTarget: `${options.clientProject}:server:production`,
181-
},
182-
},
206+
configurations,
183207
});
184208
});
185209
};
@@ -242,9 +266,9 @@ function addServerRoutes(options: AppShellOptions): Rule {
242266
if (!isImported(moduleSource, 'Routes', '@angular/router')) {
243267
const recorder = host.beginUpdate(modulePath);
244268
const routesChange = insertImport(moduleSource,
245-
modulePath,
246-
'Routes',
247-
'@angular/router');
269+
modulePath,
270+
'Routes',
271+
'@angular/router');
248272
if (routesChange) {
249273
applyToUpdateRecorder(recorder, [routesChange]);
250274
}
@@ -263,16 +287,16 @@ function addServerRoutes(options: AppShellOptions): Rule {
263287
if (!isImported(moduleSource, 'RouterModule', '@angular/router')) {
264288
const recorder = host.beginUpdate(modulePath);
265289
const routerModuleChange = insertImport(moduleSource,
266-
modulePath,
267-
'RouterModule',
268-
'@angular/router');
290+
modulePath,
291+
'RouterModule',
292+
'@angular/router');
269293

270294
if (routerModuleChange) {
271295
applyToUpdateRecorder(recorder, [routerModuleChange]);
272296
}
273297

274298
const metadataChange = addSymbolToNgModuleMetadata(
275-
moduleSource, modulePath, 'imports', 'RouterModule.forRoot(routes)');
299+
moduleSource, modulePath, 'imports', 'RouterModule.forRoot(routes)');
276300
if (metadataChange) {
277301
applyToUpdateRecorder(recorder, metadataChange);
278302
}

packages/schematics/angular/app-shell/index_spec.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,9 @@ describe('App Shell Schematic', () => {
6868
const content = tree.readContent(filePath);
6969
const workspace = JSON.parse(content);
7070
const target = workspace.projects.bar.architect['app-shell'];
71-
expect(target.options.browserTarget).toEqual('bar:build');
72-
expect(target.options.serverTarget).toEqual('bar:server');
7371
expect(target.options.route).toEqual('shell');
72+
expect(target.configurations.development.browserTarget).toEqual('bar:build:development');
73+
expect(target.configurations.development.serverTarget).toEqual('bar:server:development');
7474
expect(target.configurations.production.browserTarget).toEqual('bar:build:production');
7575
expect(target.configurations.production.serverTarget).toEqual('bar:server:production');
7676
});

packages/schematics/angular/application/index.ts

+11-5
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ function addAppToWorkspaceFile(options: ApplicationOptions, appDir: string): Rul
172172
targets: {
173173
build: {
174174
builder: Builders.Browser,
175+
defaultConfiguration: 'production',
175176
options: {
176177
outputPath: `dist/${options.name}`,
177178
index: `${sourceRoot}/index.html`,
@@ -190,30 +191,35 @@ function addAppToWorkspaceFile(options: ApplicationOptions, appDir: string): Rul
190191
},
191192
configurations: {
192193
production: {
194+
budgets,
193195
fileReplacements: [{
194196
replace: `${sourceRoot}/environments/environment.ts`,
195197
with: `${sourceRoot}/environments/environment.prod.ts`,
196198
}],
199+
buildOptimizer: true,
197200
optimization: true,
198201
outputHashing: 'all',
199202
sourceMap: false,
200203
namedChunks: false,
201204
extractLicenses: true,
202205
vendorChunk: false,
203-
buildOptimizer: true,
204-
budgets,
206+
},
207+
development: {
208+
vendorChunk: true,
205209
},
206210
},
207211
},
208212
serve: {
209213
builder: Builders.DevServer,
210-
options: {
211-
browserTarget: `${options.name}:build`,
212-
},
214+
defaultConfiguration: 'development',
215+
options: {},
213216
configurations: {
214217
production: {
215218
browserTarget: `${options.name}:build:production`,
216219
},
220+
development: {
221+
browserTarget: `${options.name}:build:development`,
222+
},
217223
},
218224
},
219225
'extract-i18n': {

packages/schematics/angular/e2e/index.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,17 @@ export default function (options: E2eOptions): Rule {
4848
project.targets.add({
4949
name: 'e2e',
5050
builder: Builders.Protractor,
51+
defaultConfiguration: 'development',
5152
options: {
5253
protractorConfig: `${root}/protractor.conf.js`,
53-
devServerTarget: `${options.relatedAppName}:serve`,
5454
},
5555
configurations: {
5656
production: {
5757
devServerTarget: `${options.relatedAppName}:serve:production`,
5858
},
59+
development: {
60+
devServerTarget: `${options.relatedAppName}:serve:development`,
61+
},
5962
},
6063
});
6164

packages/schematics/angular/e2e/index_spec.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,9 @@ describe('Application Schematic', () => {
9494
const tree = await schematicRunner.runSchematicAsync('e2e', defaultOptions, applicationTree)
9595
.toPromise();
9696
const workspace = JSON.parse(tree.readContent('/angular.json'));
97-
const e2eOptions = workspace.projects.foo.architect.e2e.options;
98-
expect(e2eOptions.protractorConfig).toEqual('projects/foo/e2e/protractor.conf.js');
99-
expect(e2eOptions.devServerTarget).toEqual('foo:serve');
97+
const { options, configurations } = workspace.projects.foo.architect.e2e;
98+
expect(options.protractorConfig).toEqual('projects/foo/e2e/protractor.conf.js');
99+
expect(configurations.development.devServerTarget).toEqual('foo:serve:development');
100100
});
101101
});
102102

packages/schematics/angular/library/index.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,17 @@ function addLibToWorkspaceFile(
9595
targets: {
9696
build: {
9797
builder: Builders.NgPackagr,
98+
defaultConfiguration: 'production',
9899
options: {
99-
tsConfig: `${projectRoot}/tsconfig.lib.json`,
100100
project: `${projectRoot}/ng-package.json`,
101101
},
102102
configurations: {
103103
production: {
104104
tsConfig: `${projectRoot}/tsconfig.lib.prod.json`,
105105
},
106+
development: {
107+
tsConfig: `${projectRoot}/tsconfig.lib.json`,
108+
},
106109
},
107110
},
108111
test: {

packages/schematics/angular/library/index_spec.ts

+7-7
Original file line numberDiff line numberDiff line change
@@ -309,22 +309,22 @@ describe('Library Schematic', () => {
309309
const config = getJsonFileContent(tree, '/angular.json');
310310
const project = config.projects.foo;
311311
expect(project.root).toEqual('foo');
312-
const buildOpt = project.architect.build.options;
313-
expect(buildOpt.project).toEqual('foo/ng-package.json');
314-
expect(buildOpt.tsConfig).toEqual('foo/tsconfig.lib.json');
312+
const { options, configurations } = project.architect.build;
313+
expect(options.project).toEqual('foo/ng-package.json');
314+
expect(configurations.production.tsConfig).toEqual('foo/tsconfig.lib.prod.json');
315315

316-
const appTsConfig = getJsonFileContent(tree, '/foo/tsconfig.lib.json');
317-
expect(appTsConfig.extends).toEqual('../tsconfig.json');
316+
const libTsConfig = getJsonFileContent(tree, '/foo/tsconfig.lib.json');
317+
expect(libTsConfig.extends).toEqual('../tsconfig.json');
318318
const specTsConfig = getJsonFileContent(tree, '/foo/tsconfig.spec.json');
319319
expect(specTsConfig.extends).toEqual('../tsconfig.json');
320320
});
321321

322-
it(`should add 'production' configuration`, async () => {
322+
it(`should add 'development' configuration`, async () => {
323323
const tree = await schematicRunner.runSchematicAsync('library', defaultOptions, workspaceTree)
324324
.toPromise();
325325

326326
const workspace = JSON.parse(tree.readContent('/angular.json'));
327-
expect(workspace.projects.foo.architect.build.configurations.production).toBeDefined();
327+
expect(workspace.projects.foo.architect.build.configurations.development).toBeDefined();
328328
});
329329

330330
it(`should add 'ng-packagr' builder`, async () => {

packages/schematics/angular/migrations/update-9/update-i18n_spec.ts

+2
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ describe('Migration to version 9', () => {
4949
tree,
5050
)
5151
.toPromise();
52+
53+
tree.overwrite('angular.json', tree.readContent('angular.json').replace(/development/g, 'production'));
5254
});
5355

5456
describe('i18n configuration', () => {

packages/schematics/angular/migrations/update-9/update-workspace-config_spec.ts

+4
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ describe('Migration to version 9', () => {
9393
);
9494

9595
tree.overwrite('tsconfig.app.json', tsConfig);
96+
97+
tree.overwrite('angular.json', tree.readContent('angular.json').replace(/development/g, 'production'));
9698
});
9799

98100
describe('scripts and style options', () => {
@@ -277,6 +279,8 @@ describe('Migration to version 9', () => {
277279
tree,
278280
)
279281
.toPromise();
282+
283+
tree.overwrite('angular.json', tree.readContent('angular.json').replace(/development/g, 'production'));
280284
});
281285

282286
it('should add optimization option when not defined', async () => {

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

+4-13
Original file line numberDiff line numberDiff line change
@@ -130,21 +130,12 @@ export default function (options: ServiceWorkerOptions): Rule {
130130
if (!buildTarget) {
131131
throw targetBuildNotFoundError();
132132
}
133-
const buildOptions =
134-
(buildTarget.options || {}) as unknown as BrowserBuilderOptions;
135-
let buildConfiguration;
136-
if (options.configuration && buildTarget.configurations) {
137-
buildConfiguration =
138-
buildTarget.configurations[options.configuration] as unknown as BrowserBuilderOptions | undefined;
139-
}
140-
141-
const config = buildConfiguration || buildOptions;
133+
const buildOptions = (buildTarget.options || {}) as unknown as BrowserBuilderOptions;
142134
const root = project.root;
135+
buildOptions.serviceWorker = true;
136+
buildOptions.ngswConfigPath = join(normalize(root), 'ngsw-config.json');
143137

144-
config.serviceWorker = true;
145-
config.ngswConfigPath = join(normalize(root), 'ngsw-config.json');
146-
147-
let { resourcesOutputPath = '' } = config;
138+
let { resourcesOutputPath = '' } = buildOptions;
148139
if (resourcesOutputPath) {
149140
resourcesOutputPath = normalize(`/${resourcesOutputPath}`);
150141
}

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

+7-21
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ describe('Service Worker Schematic', () => {
1919
const defaultOptions: ServiceWorkerOptions = {
2020
project: 'bar',
2121
target: 'build',
22-
configuration: 'production',
22+
configuration: '',
2323
};
2424

2525
let appTree: UnitTestTree;
@@ -45,25 +45,13 @@ describe('Service Worker Schematic', () => {
4545
.toPromise();
4646
});
4747

48-
it('should update the production configuration', async () => {
48+
it('should add `serviceWorker` option to build target', async () => {
4949
const tree = await schematicRunner.runSchematicAsync('service-worker', defaultOptions, appTree)
5050
.toPromise();
5151
const configText = tree.readContent('/angular.json');
52-
const config = JSON.parse(configText);
53-
const swFlag = config.projects.bar.architect
54-
.build.configurations.production.serviceWorker;
55-
expect(swFlag).toEqual(true);
56-
});
52+
const buildConfig = JSON.parse(configText).projects.bar.architect.build;
5753

58-
it('should update the target options if no configuration is set', async () => {
59-
const options = { ...defaultOptions, configuration: '' };
60-
const tree = await schematicRunner.runSchematicAsync('service-worker', options, appTree)
61-
.toPromise();
62-
const configText = tree.readContent('/angular.json');
63-
const config = JSON.parse(configText);
64-
const swFlag = config.projects.bar.architect
65-
.build.options.serviceWorker;
66-
expect(swFlag).toEqual(true);
54+
expect(buildConfig.options.serviceWorker).toBeTrue();
6755
});
6856

6957
it('should add the necessary dependency', async () => {
@@ -162,8 +150,7 @@ describe('Service Worker Schematic', () => {
162150
expect(tree.exists(path)).toEqual(true);
163151

164152
const { projects } = JSON.parse(tree.readContent('/angular.json'));
165-
expect(projects.bar.architect.build.configurations.production.ngswConfigPath)
166-
.toBe('projects/bar/ngsw-config.json');
153+
expect(projects.bar.architect.build.options.ngswConfigPath).toBe('projects/bar/ngsw-config.json');
167154
});
168155

169156
it('should add $schema in ngsw-config.json with correct relative path', async () => {
@@ -214,7 +201,7 @@ describe('Service Worker Schematic', () => {
214201

215202
it('should add resourcesOutputPath to root assets when specified', async () => {
216203
const config = JSON.parse(appTree.readContent('/angular.json'));
217-
config.projects.bar.architect.build.configurations.production.resourcesOutputPath = 'outDir';
204+
config.projects.bar.architect.build.options.resourcesOutputPath = 'outDir';
218205
appTree.overwrite('/angular.json', JSON.stringify(config));
219206
const tree = await schematicRunner.runSchematicAsync('service-worker', defaultOptions, appTree)
220207
.toPromise();
@@ -243,7 +230,6 @@ describe('Service Worker Schematic', () => {
243230
expect(tree.exists('/ngsw-config.json')).toBe(true);
244231

245232
const { projects } = JSON.parse(tree.readContent('/angular.json'));
246-
expect(projects.foo.architect.build.configurations.production.ngswConfigPath)
247-
.toBe('ngsw-config.json');
233+
expect(projects.foo.architect.build.options.ngswConfigPath).toBe('ngsw-config.json');
248234
});
249235
});

packages/schematics/angular/service-worker/schema.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"configuration": {
2121
"type": "string",
2222
"description": "The configuration to apply service worker to.",
23-
"default": "production"
23+
"x-deprecated": "No longer has an effect."
2424
}
2525
},
2626
"required": [

0 commit comments

Comments
 (0)