Skip to content

Commit f1f4932

Browse files
clydinalexeagle
authored andcommitted
refactor(@angular-devkit/build-angular): standardize builder transforms
1 parent 5ec27db commit f1f4932

File tree

5 files changed

+54
-58
lines changed

5 files changed

+54
-58
lines changed

packages/angular_devkit/build_angular/src/browser/index.ts

+30-36
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import {
2323
import { NodeJsSyncHost } from '@angular-devkit/core/node';
2424
import * as fs from 'fs';
2525
import * as path from 'path';
26-
import { Observable, combineLatest, from, of, zip } from 'rxjs';
26+
import { from, of, zip } from 'rxjs';
2727
import { catchError, concatMap, map, switchMap } from 'rxjs/operators';
2828
import * as webpack from 'webpack';
2929
import { NgBuildAnalyticsPlugin } from '../../plugins/webpack/analytics';
@@ -44,6 +44,7 @@ import {
4444
statsToString,
4545
statsWarningsToString,
4646
} from '../angular-cli-files/utilities/stats';
47+
import { ExecutionTransformer } from '../transforms';
4748
import { deleteOutputDir } from '../utils';
4849
import { generateBrowserWebpackConfigFromContext } from '../utils/webpack-browser-config';
4950
import { Schema as BrowserBuilderSchema } from './schema';
@@ -77,7 +78,7 @@ export function createBrowserLoggingCallback(
7778
export async function buildBrowserWebpackConfigFromContext(
7879
options: BrowserBuilderSchema,
7980
context: BuilderContext,
80-
host: virtualFs.Host<fs.Stats>,
81+
host: virtualFs.Host<fs.Stats> = new NodeJsSyncHost(),
8182
): Promise<{ workspace: experimental.workspace.Workspace, config: webpack.Configuration[] }> {
8283
return generateBrowserWebpackConfigFromContext(
8384
options,
@@ -126,53 +127,48 @@ function getCompilerConfig(wco: WebpackConfigOptions): webpack.Configuration {
126127
return {};
127128
}
128129

129-
export type BrowserConfigTransformFn = (
130-
workspace: experimental.workspace.Workspace,
131-
config: webpack.Configuration,
132-
) => Observable<webpack.Configuration>;
130+
async function initialize(
131+
options: BrowserBuilderSchema,
132+
context: BuilderContext,
133+
host: virtualFs.Host<fs.Stats>,
134+
webpackConfigurationTransform?: ExecutionTransformer<webpack.Configuration>,
135+
): Promise<{ workspace: experimental.workspace.Workspace, config: webpack.Configuration[] }> {
136+
const { config, workspace } = await buildBrowserWebpackConfigFromContext(options, context, host);
137+
138+
let transformedConfig;
139+
if (webpackConfigurationTransform) {
140+
transformedConfig = [];
141+
for (const c of config) {
142+
transformedConfig.push(await webpackConfigurationTransform(c));
143+
}
144+
}
145+
146+
if (options.deleteOutputPath) {
147+
await deleteOutputDir(
148+
normalize(context.workspaceRoot),
149+
normalize(options.outputPath),
150+
host,
151+
).toPromise();
152+
}
133153

154+
return { config: transformedConfig || config, workspace };
155+
}
134156

135157
export function buildWebpackBrowser(
136158
options: BrowserBuilderSchema,
137159
context: BuilderContext,
138160
transforms: {
139-
config?: BrowserConfigTransformFn,
140-
output?: (output: BrowserBuilderOutput) => Observable<BuilderOutput>,
161+
webpackConfiguration?: ExecutionTransformer<webpack.Configuration>,
141162
logging?: WebpackLoggingCallback,
142163
} = {},
143164
) {
144165
const host = new NodeJsSyncHost();
145166
const root = normalize(context.workspaceRoot);
146167

147-
const configFn = transforms.config;
148-
const outputFn = transforms.output;
149168
const loggingFn = transforms.logging
150169
|| createBrowserLoggingCallback(!!options.verbose, context.logger);
151170

152-
// This makes a host observable into a cold one. This is because we want to wait until
153-
// subscription before calling buildBrowserWebpackConfigFromContext, which can throw.
154-
return of(null).pipe(
155-
switchMap(() => from(buildBrowserWebpackConfigFromContext(options, context, host))),
156-
switchMap(({ workspace, config }) => {
157-
if (configFn) {
158-
return combineLatest(config.map(config => configFn(workspace, config))).pipe(
159-
map(config => ({ workspace, config })),
160-
);
161-
} else {
162-
return of({ workspace, config });
163-
}
164-
}),
165-
switchMap(({ workspace, config }) => {
166-
if (options.deleteOutputPath) {
167-
return deleteOutputDir(
168-
root,
169-
normalize(options.outputPath),
170-
host,
171-
).pipe(map(() => ({ workspace, config })));
172-
} else {
173-
return of({ workspace, config });
174-
}
175-
}),
171+
return from(initialize(options, context, host, transforms.webpackConfiguration)).pipe(
176172
switchMap(({ workspace, config: configs }) => {
177173
const projectName = context.target
178174
? context.target.project : workspace.getDefaultProjectName();
@@ -237,11 +233,9 @@ export function buildWebpackBrowser(
237233
// If we use differential loading, both configs have the same outputs
238234
outputPath: path.resolve(context.workspaceRoot, options.outputPath),
239235
} as BrowserBuilderOutput)),
240-
concatMap(output => outputFn ? outputFn(output) : of(output)),
241236
);
242237
}),
243238
);
244239
}
245240

246-
247241
export default createBuilder<json.JsonObject & BrowserBuilderSchema>(buildWebpackBrowser);

packages/angular_devkit/build_angular/src/dev-server/index.ts

+5-12
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@ import * as webpack from 'webpack';
2727
import * as WebpackDevServer from 'webpack-dev-server';
2828
import { checkPort } from '../angular-cli-files/utilities/check-port';
2929
import {
30-
BrowserConfigTransformFn,
3130
buildBrowserWebpackConfigFromContext,
3231
createBrowserLoggingCallback,
3332
} from '../browser';
3433
import { Schema as BrowserBuilderSchema } from '../browser/schema';
34+
import { ExecutionTransformer } from '../transforms';
3535
import { normalizeOptimization } from '../utils';
3636
import { Schema } from './schema';
3737
const open = require('open');
@@ -75,8 +75,7 @@ export function serveWebpackBrowser(
7575
options: DevServerBuilderSchema,
7676
context: BuilderContext,
7777
transforms: {
78-
browserConfig?: BrowserConfigTransformFn,
79-
serverConfig?: ServerConfigTransformFn,
78+
webpackConfiguration?: ExecutionTransformer<webpack.Configuration>,
8079
logging?: WebpackLoggingCallback,
8180
} = {},
8281
): Observable<DevServerBuilderOutput> {
@@ -123,22 +122,17 @@ export function serveWebpackBrowser(
123122

124123
// No differential loading for dev-server, hence there is just one config
125124
let webpackConfig = webpackConfigResult.config[0];
126-
const workspace = webpackConfigResult.workspace;
127-
128-
if (transforms.browserConfig) {
129-
webpackConfig = await transforms.browserConfig(workspace, webpackConfig).toPromise();
130-
}
131125

132126
const port = await checkPort(options.port || 0, options.host || 'localhost', 4200);
133-
let webpackDevServerConfig = buildServerConfig(
127+
const webpackDevServerConfig = webpackConfig.devServer = buildServerConfig(
134128
root,
135129
options,
136130
browserOptions,
137131
context.logger,
138132
);
139133

140-
if (transforms.serverConfig) {
141-
webpackDevServerConfig = await transforms.serverConfig(workspace, webpackConfig).toPromise();
134+
if (transforms.webpackConfiguration) {
135+
webpackConfig = await transforms.webpackConfiguration(webpackConfig);
142136
}
143137

144138
return { browserOptions, webpackConfig, webpackDevServerConfig, port };
@@ -208,7 +202,6 @@ export function serveWebpackBrowser(
208202
`);
209203

210204
openAddress = serverAddress + webpackDevServerConfig.publicPath;
211-
webpackConfig.devServer = webpackDevServerConfig;
212205

213206
return runWebpackDevServer(webpackConfig, context, { logging: loggingFn });
214207
}),

packages/angular_devkit/build_angular/src/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
// See https://github.com/angular/angular-cli/issues/9691#issuecomment-367322703 for details.
1313
// We need to add a require here to satisfy the dependency checker.
1414
// require('ajv');
15-
15+
export * from './transforms';
1616
export * from './app-shell';
1717
export * from './browser';
1818
export {

packages/angular_devkit/build_angular/src/karma/index.ts

+10-9
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
getWorkerConfig,
1919
} from '../angular-cli-files/models/webpack-configs';
2020
import { Schema as BrowserBuilderOptions } from '../browser/schema';
21+
import { ExecutionTransformer } from '../transforms';
2122
import { generateBrowserWebpackConfigFromContext } from '../utils/webpack-browser-config';
2223
import { Schema as KarmaBuilderOptions } from './schema';
2324

@@ -27,12 +28,10 @@ type KarmaConfigOptions = import ('karma').ConfigOptions & {
2728
configFile?: string;
2829
};
2930

30-
type WebpackConfigurationTransformer =
31-
(configuration: webpack.Configuration) => webpack.Configuration;
32-
3331
async function initialize(
3432
options: KarmaBuilderOptions,
3533
context: BuilderContext,
34+
webpackConfigurationTransformer?: ExecutionTransformer<webpack.Configuration>,
3635
// tslint:disable-next-line:no-implicit-dependencies
3736
): Promise<[typeof import ('karma'), webpack.Configuration]> {
3837
const { config } = await generateBrowserWebpackConfigFromContext(
@@ -53,18 +52,22 @@ async function initialize(
5352
// tslint:disable-next-line:no-implicit-dependencies
5453
const karma = await import('karma');
5554

56-
return [karma, config[0]];
55+
return [
56+
karma,
57+
webpackConfigurationTransformer ? await webpackConfigurationTransformer(config[0]) : config[0],
58+
];
5759
}
5860

5961
export function execute(
6062
options: KarmaBuilderOptions,
6163
context: BuilderContext,
6264
transforms: {
63-
webpackConfiguration?: WebpackConfigurationTransformer,
65+
webpackConfiguration?: ExecutionTransformer<webpack.Configuration>,
66+
// The karma options transform cannot be async without a refactor of the builder implementation
6467
karmaOptions?: (options: KarmaConfigOptions) => KarmaConfigOptions,
6568
} = {},
6669
): Observable<BuilderOutput> {
67-
return from(initialize(options, context)).pipe(
70+
return from(initialize(options, context, transforms.webpackConfiguration)).pipe(
6871
switchMap(([karma, webpackConfig]) => new Observable<BuilderOutput>(subscriber => {
6972
const karmaOptions: KarmaConfigOptions = {};
7073

@@ -93,9 +96,7 @@ export function execute(
9396

9497
karmaOptions.buildWebpack = {
9598
options,
96-
webpackConfig: transforms.webpackConfiguration
97-
? transforms.webpackConfiguration(webpackConfig)
98-
: webpackConfig,
99+
webpackConfig,
99100
// Pass onto Karma to emit BuildEvents.
100101
successCb: () => subscriber.next({ success: true }),
101102
failureCb: () => subscriber.next({ success: false }),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
export type ExecutionTransformer<T> = (input: T) => T | Promise<T>;

0 commit comments

Comments
 (0)