Skip to content

Commit

Permalink
feat(@schematics/angular): production builds by default
Browse files Browse the repository at this point in the history
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`
  • Loading branch information
alan-agius4 authored and filipesilva committed Mar 10, 2021
1 parent a5877bf commit 1de6d71
Show file tree
Hide file tree
Showing 16 changed files with 128 additions and 108 deletions.
2 changes: 1 addition & 1 deletion packages/angular/pwa/pwa/index_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ describe('PWA Schematic', () => {
schematicRunner.runSchematicAsync('ng-add', defaultOptions, appTree).toPromise().then(tree => {
const configText = tree.readContent('/angular.json');
const config = JSON.parse(configText);
const swFlag = config.projects.bar.architect.build.configurations.production.serviceWorker;
const swFlag = config.projects.bar.architect.build.options.serviceWorker;
expect(swFlag).toEqual(true);
done();
}, done.fail);
Expand Down
56 changes: 40 additions & 16 deletions packages/schematics/angular/app-shell/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ function addUniversalTarget(options: AppShellOptions): Rule {
}

function addAppShellConfigToWorkspace(options: AppShellOptions): Rule {
return () => {
return (host, context) => {
if (!options.route) {
throw new SchematicsException(`Route is not defined`);
}
Expand All @@ -166,20 +166,44 @@ function addAppShellConfigToWorkspace(options: AppShellOptions): Rule {
return;
}

// Validation of targets is handled already in the main function.
// Duplicate keys means that we have configurations in both server and build builders.
const serverConfigKeys = project.targets.get('server')?.configurations ?? {};
const buildConfigKeys = project.targets.get('build')?.configurations ?? {};

const configurationNames = Object.keys({
...serverConfigKeys,
...buildConfigKeys,
});

const configurations: Record<string, {}> = {};
for (const key of configurationNames) {
if (!serverConfigKeys[key]) {
context.logger.warn(`Skipped adding "${key}" configuration to "app-shell" target as it's missing from "server" target.`);

continue;
}

if (!buildConfigKeys[key]) {
context.logger.warn(`Skipped adding "${key}" configuration to "app-shell" target as it's missing from "build" target.`);

continue;
}

configurations[key] = {
browserTarget: `${options.clientProject}:build:${key}`,
serverTarget: `${options.clientProject}:server:${key}`,
};
}

project.targets.add({
name: 'app-shell',
builder: Builders.AppShell,
defaultConfiguration: configurations['production'] ? 'production' : undefined,
options: {
browserTarget: `${options.clientProject}:build`,
serverTarget: `${options.clientProject}:server`,
route: options.route,
},
configurations: {
production: {
browserTarget: `${options.clientProject}:build:production`,
serverTarget: `${options.clientProject}:server:production`,
},
},
configurations,
});
});
};
Expand Down Expand Up @@ -242,9 +266,9 @@ function addServerRoutes(options: AppShellOptions): Rule {
if (!isImported(moduleSource, 'Routes', '@angular/router')) {
const recorder = host.beginUpdate(modulePath);
const routesChange = insertImport(moduleSource,
modulePath,
'Routes',
'@angular/router');
modulePath,
'Routes',
'@angular/router');
if (routesChange) {
applyToUpdateRecorder(recorder, [routesChange]);
}
Expand All @@ -263,16 +287,16 @@ function addServerRoutes(options: AppShellOptions): Rule {
if (!isImported(moduleSource, 'RouterModule', '@angular/router')) {
const recorder = host.beginUpdate(modulePath);
const routerModuleChange = insertImport(moduleSource,
modulePath,
'RouterModule',
'@angular/router');
modulePath,
'RouterModule',
'@angular/router');

if (routerModuleChange) {
applyToUpdateRecorder(recorder, [routerModuleChange]);
}

const metadataChange = addSymbolToNgModuleMetadata(
moduleSource, modulePath, 'imports', 'RouterModule.forRoot(routes)');
moduleSource, modulePath, 'imports', 'RouterModule.forRoot(routes)');
if (metadataChange) {
applyToUpdateRecorder(recorder, metadataChange);
}
Expand Down
4 changes: 2 additions & 2 deletions packages/schematics/angular/app-shell/index_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ describe('App Shell Schematic', () => {
const content = tree.readContent(filePath);
const workspace = JSON.parse(content);
const target = workspace.projects.bar.architect['app-shell'];
expect(target.options.browserTarget).toEqual('bar:build');
expect(target.options.serverTarget).toEqual('bar:server');
expect(target.options.route).toEqual('shell');
expect(target.configurations.development.browserTarget).toEqual('bar:build:development');
expect(target.configurations.development.serverTarget).toEqual('bar:server:development');
expect(target.configurations.production.browserTarget).toEqual('bar:build:production');
expect(target.configurations.production.serverTarget).toEqual('bar:server:production');
});
Expand Down
16 changes: 11 additions & 5 deletions packages/schematics/angular/application/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ function addAppToWorkspaceFile(options: ApplicationOptions, appDir: string): Rul
targets: {
build: {
builder: Builders.Browser,
defaultConfiguration: 'production',
options: {
outputPath: `dist/${options.name}`,
index: `${sourceRoot}/index.html`,
Expand All @@ -190,30 +191,35 @@ function addAppToWorkspaceFile(options: ApplicationOptions, appDir: string): Rul
},
configurations: {
production: {
budgets,
fileReplacements: [{
replace: `${sourceRoot}/environments/environment.ts`,
with: `${sourceRoot}/environments/environment.prod.ts`,
}],
buildOptimizer: true,
optimization: true,
outputHashing: 'all',
sourceMap: false,
namedChunks: false,
extractLicenses: true,
vendorChunk: false,
buildOptimizer: true,
budgets,
},
development: {
vendorChunk: true,
},
},
},
serve: {
builder: Builders.DevServer,
options: {
browserTarget: `${options.name}:build`,
},
defaultConfiguration: 'development',
options: {},
configurations: {
production: {
browserTarget: `${options.name}:build:production`,
},
development: {
browserTarget: `${options.name}:build:development`,
},
},
},
'extract-i18n': {
Expand Down
5 changes: 4 additions & 1 deletion packages/schematics/angular/e2e/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,17 @@ export default function (options: E2eOptions): Rule {
project.targets.add({
name: 'e2e',
builder: Builders.Protractor,
defaultConfiguration: 'development',
options: {
protractorConfig: `${root}/protractor.conf.js`,
devServerTarget: `${options.relatedAppName}:serve`,
},
configurations: {
production: {
devServerTarget: `${options.relatedAppName}:serve:production`,
},
development: {
devServerTarget: `${options.relatedAppName}:serve:development`,
},
},
});

Expand Down
6 changes: 3 additions & 3 deletions packages/schematics/angular/e2e/index_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,9 @@ describe('Application Schematic', () => {
const tree = await schematicRunner.runSchematicAsync('e2e', defaultOptions, applicationTree)
.toPromise();
const workspace = JSON.parse(tree.readContent('/angular.json'));
const e2eOptions = workspace.projects.foo.architect.e2e.options;
expect(e2eOptions.protractorConfig).toEqual('projects/foo/e2e/protractor.conf.js');
expect(e2eOptions.devServerTarget).toEqual('foo:serve');
const { options, configurations } = workspace.projects.foo.architect.e2e;
expect(options.protractorConfig).toEqual('projects/foo/e2e/protractor.conf.js');
expect(configurations.development.devServerTarget).toEqual('foo:serve:development');
});
});

Expand Down
5 changes: 4 additions & 1 deletion packages/schematics/angular/library/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,14 +95,17 @@ function addLibToWorkspaceFile(
targets: {
build: {
builder: Builders.NgPackagr,
defaultConfiguration: 'production',
options: {
tsConfig: `${projectRoot}/tsconfig.lib.json`,
project: `${projectRoot}/ng-package.json`,
},
configurations: {
production: {
tsConfig: `${projectRoot}/tsconfig.lib.prod.json`,
},
development: {
tsConfig: `${projectRoot}/tsconfig.lib.json`,
},
},
},
test: {
Expand Down
14 changes: 7 additions & 7 deletions packages/schematics/angular/library/index_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -309,22 +309,22 @@ describe('Library Schematic', () => {
const config = getJsonFileContent(tree, '/angular.json');
const project = config.projects.foo;
expect(project.root).toEqual('foo');
const buildOpt = project.architect.build.options;
expect(buildOpt.project).toEqual('foo/ng-package.json');
expect(buildOpt.tsConfig).toEqual('foo/tsconfig.lib.json');
const { options, configurations } = project.architect.build;
expect(options.project).toEqual('foo/ng-package.json');
expect(configurations.production.tsConfig).toEqual('foo/tsconfig.lib.prod.json');

const appTsConfig = getJsonFileContent(tree, '/foo/tsconfig.lib.json');
expect(appTsConfig.extends).toEqual('../tsconfig.json');
const libTsConfig = getJsonFileContent(tree, '/foo/tsconfig.lib.json');
expect(libTsConfig.extends).toEqual('../tsconfig.json');
const specTsConfig = getJsonFileContent(tree, '/foo/tsconfig.spec.json');
expect(specTsConfig.extends).toEqual('../tsconfig.json');
});

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

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

it(`should add 'ng-packagr' builder`, async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ describe('Migration to version 9', () => {
tree,
)
.toPromise();

tree.overwrite('angular.json', tree.readContent('angular.json').replace(/development/g, 'production'));
});

describe('i18n configuration', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ describe('Migration to version 9', () => {
);

tree.overwrite('tsconfig.app.json', tsConfig);

tree.overwrite('angular.json', tree.readContent('angular.json').replace(/development/g, 'production'));
});

describe('scripts and style options', () => {
Expand Down Expand Up @@ -277,6 +279,8 @@ describe('Migration to version 9', () => {
tree,
)
.toPromise();

tree.overwrite('angular.json', tree.readContent('angular.json').replace(/development/g, 'production'));
});

it('should add optimization option when not defined', async () => {
Expand Down
17 changes: 4 additions & 13 deletions packages/schematics/angular/service-worker/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,21 +130,12 @@ export default function (options: ServiceWorkerOptions): Rule {
if (!buildTarget) {
throw targetBuildNotFoundError();
}
const buildOptions =
(buildTarget.options || {}) as unknown as BrowserBuilderOptions;
let buildConfiguration;
if (options.configuration && buildTarget.configurations) {
buildConfiguration =
buildTarget.configurations[options.configuration] as unknown as BrowserBuilderOptions | undefined;
}

const config = buildConfiguration || buildOptions;
const buildOptions = (buildTarget.options || {}) as unknown as BrowserBuilderOptions;
const root = project.root;
buildOptions.serviceWorker = true;
buildOptions.ngswConfigPath = join(normalize(root), 'ngsw-config.json');

config.serviceWorker = true;
config.ngswConfigPath = join(normalize(root), 'ngsw-config.json');

let { resourcesOutputPath = '' } = config;
let { resourcesOutputPath = '' } = buildOptions;
if (resourcesOutputPath) {
resourcesOutputPath = normalize(`/${resourcesOutputPath}`);
}
Expand Down
28 changes: 7 additions & 21 deletions packages/schematics/angular/service-worker/index_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ describe('Service Worker Schematic', () => {
const defaultOptions: ServiceWorkerOptions = {
project: 'bar',
target: 'build',
configuration: 'production',
configuration: '',
};

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

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

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

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

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

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

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

const { projects } = JSON.parse(tree.readContent('/angular.json'));
expect(projects.foo.architect.build.configurations.production.ngswConfigPath)
.toBe('ngsw-config.json');
expect(projects.foo.architect.build.options.ngswConfigPath).toBe('ngsw-config.json');
});
});
2 changes: 1 addition & 1 deletion packages/schematics/angular/service-worker/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"configuration": {
"type": "string",
"description": "The configuration to apply service worker to.",
"default": "production"
"x-deprecated": "No longer has an effect."
}
},
"required": [
Expand Down
Loading

0 comments on commit 1de6d71

Please sign in to comment.