Skip to content

Commit ffd153a

Browse files
clydinvikerman
authored andcommitted
refactor(@angular-devkit/build-angular): use project metadata in builders
This eliminates the need to manually read a workspace file and removes the use of the experimental workspace API from the package.
1 parent 0d104c0 commit ffd153a

File tree

5 files changed

+71
-129
lines changed

5 files changed

+71
-129
lines changed

packages/angular_devkit/build_angular/src/app-shell/index.ts

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
createBuilder,
1212
targetFromTargetString,
1313
} from '@angular-devkit/architect';
14-
import { JsonObject, experimental, join, normalize, resolve, schema } from '@angular-devkit/core';
14+
import { JsonObject, join, normalize, resolve, schema } from '@angular-devkit/core';
1515
import { NodeJsSyncHost } from '@angular-devkit/core/node';
1616
import * as fs from 'fs';
1717
import * as path from 'path';
@@ -81,21 +81,17 @@ async function _renderUniversal(
8181

8282
if (browserOptions.serviceWorker) {
8383
const host = new NodeJsSyncHost();
84-
// Create workspace.
85-
const registry = new schema.CoreSchemaRegistry();
86-
registry.addPostTransform(schema.transforms.addUndefinedDefaults);
87-
88-
const workspace = await experimental.workspace.Workspace.fromPath(
89-
host,
90-
normalize(context.workspaceRoot),
91-
registry,
92-
);
93-
const projectName = context.target ? context.target.project : workspace.getDefaultProjectName();
9484

85+
const projectName = context.target && context.target.project;
9586
if (!projectName) {
96-
throw new Error('Must either have a target from the context or a default project.');
87+
throw new Error('The builder requires a target.');
9788
}
98-
const projectRoot = resolve(workspace.root, normalize(workspace.getProject(projectName).root));
89+
90+
const projectMetadata = await context.getProjectMetadata(projectName);
91+
const projectRoot = resolve(
92+
normalize(context.workspaceRoot),
93+
normalize((projectMetadata.root as string) || ''),
94+
);
9995

10096
await augmentAppWithServiceWorker(
10197
host,

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

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import {
1313
runWebpack,
1414
} from '@angular-devkit/build-webpack';
1515
import {
16-
experimental,
1716
getSystemPath,
1817
join,
1918
json,
@@ -108,7 +107,7 @@ export async function buildBrowserWebpackConfigFromContext(
108107
options: BrowserBuilderSchema,
109108
context: BuilderContext,
110109
host: virtualFs.Host<fs.Stats> = new NodeJsSyncHost(),
111-
): Promise<{ workspace: experimental.workspace.Workspace; config: webpack.Configuration[] }> {
110+
): Promise<{ config: webpack.Configuration[], projectRoot: string, projectSourceRoot?: string }> {
112111
return generateBrowserWebpackConfigFromContext(
113112
options,
114113
context,
@@ -160,8 +159,12 @@ async function initialize(
160159
context: BuilderContext,
161160
host: virtualFs.Host<fs.Stats>,
162161
webpackConfigurationTransform?: ExecutionTransformer<webpack.Configuration>,
163-
): Promise<{ workspace: experimental.workspace.Workspace; config: webpack.Configuration[] }> {
164-
const { config, workspace } = await buildBrowserWebpackConfigFromContext(options, context, host);
162+
): Promise<{ config: webpack.Configuration[]; projectRoot: string; projectSourceRoot?: string }> {
163+
const { config, projectRoot, projectSourceRoot } = await buildBrowserWebpackConfigFromContext(
164+
options,
165+
context,
166+
host,
167+
);
165168

166169
let transformedConfig;
167170
if (webpackConfigurationTransform) {
@@ -179,7 +182,7 @@ async function initialize(
179182
).toPromise();
180183
}
181184

182-
return { config: transformedConfig || config, workspace };
185+
return { config: transformedConfig || config, projectRoot, projectSourceRoot };
183186
}
184187

185188
// tslint:disable-next-line: no-big-function
@@ -203,23 +206,10 @@ export function buildWebpackBrowser(
203206

204207
return from(initialize(options, context, host, transforms.webpackConfiguration)).pipe(
205208
// tslint:disable-next-line: no-big-function
206-
switchMap(({ workspace, config: configs }) => {
207-
const projectName = context.target
208-
? context.target.project
209-
: workspace.getDefaultProjectName();
210-
211-
if (!projectName) {
212-
throw new Error('Must either have a target from the context or a default project.');
213-
}
214-
215-
const projectRoot = resolve(
216-
workspace.root,
217-
normalize(workspace.getProject(projectName).root),
218-
);
219-
209+
switchMap(({ config: configs, projectRoot }) => {
220210
const tsConfig = readTsconfig(options.tsConfig, context.workspaceRoot);
221211
const target = tsConfig.options.target || ScriptTarget.ES5;
222-
const buildBrowserFeatures = new BuildBrowserFeatures(getSystemPath(projectRoot), target);
212+
const buildBrowserFeatures = new BuildBrowserFeatures(projectRoot, target);
223213

224214
const isDifferentialLoadingNeeded = buildBrowserFeatures.isDifferentialLoadingNeeded();
225215

@@ -570,7 +560,7 @@ export function buildWebpackBrowser(
570560
augmentAppWithServiceWorker(
571561
host,
572562
root,
573-
projectRoot,
563+
normalize(projectRoot),
574564
resolve(root, normalize(options.outputPath)),
575565
options.baseHref || '/',
576566
options.ngswConfigPath,

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

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,8 @@ import {
1313
runWebpackDevServer,
1414
} from '@angular-devkit/build-webpack';
1515
import {
16-
experimental,
17-
getSystemPath,
1816
json,
1917
logging,
20-
normalize,
21-
resolve,
2218
tags,
2319
} from '@angular-devkit/core';
2420
import { NodeJsSyncHost } from '@angular-devkit/core/node';
@@ -98,7 +94,7 @@ export function serveWebpackBrowser(
9894
webpackConfig: webpack.Configuration;
9995
webpackDevServerConfig: WebpackDevServer.Configuration;
10096
port: number;
101-
workspace: experimental.workspace.Workspace;
97+
projectRoot: string;
10298
}> {
10399
// Get the browser configuration from the target name.
104100
const rawBrowserOptions = await context.getTargetOptions(browserTarget);
@@ -149,12 +145,12 @@ export function serveWebpackBrowser(
149145
webpackConfig,
150146
webpackDevServerConfig,
151147
port,
152-
workspace: webpackConfigResult.workspace,
148+
projectRoot: webpackConfigResult.projectRoot,
153149
};
154150
}
155151

156152
return from(setup()).pipe(
157-
switchMap(({ browserOptions, webpackConfig, webpackDevServerConfig, port, workspace }) => {
153+
switchMap(({ browserOptions, webpackConfig, webpackDevServerConfig, port, projectRoot }) => {
158154
options.port = port;
159155

160156
// Resolve public host and client address.
@@ -192,21 +188,9 @@ export function serveWebpackBrowser(
192188

193189
if (browserOptions.index) {
194190
const { scripts = [], styles = [], baseHref, tsConfig } = browserOptions;
195-
const projectName = context.target
196-
? context.target.project
197-
: workspace.getDefaultProjectName();
198-
199-
if (!projectName) {
200-
throw new Error('Must either have a target from the context or a default project.');
201-
}
202-
const projectRoot = resolve(
203-
workspace.root,
204-
normalize(workspace.getProject(projectName).root),
205-
);
206-
207191
const { options: compilerOptions } = readTsconfig(tsConfig, context.workspaceRoot);
208192
const target = compilerOptions.target || ts.ScriptTarget.ES5;
209-
const buildBrowserFeatures = new BuildBrowserFeatures(getSystemPath(projectRoot), target);
193+
const buildBrowserFeatures = new BuildBrowserFeatures(projectRoot, target);
210194

211195
const entrypoints = generateEntryPoints({ scripts, styles });
212196
const moduleEntrypoints = buildBrowserFeatures.isDifferentialLoadingNeeded()

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

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88
import { BuilderContext, BuilderOutput, createBuilder } from '@angular-devkit/architect';
9-
import { experimental, getSystemPath, join } from '@angular-devkit/core';
9+
import { getSystemPath, join, normalize } from '@angular-devkit/core';
1010
import { dirname, resolve } from 'path';
1111
import { Observable, from } from 'rxjs';
1212
import { defaultIfEmpty, switchMap } from 'rxjs/operators';
@@ -40,8 +40,8 @@ async function initialize(
4040
context: BuilderContext,
4141
webpackConfigurationTransformer?: ExecutionTransformer<webpack.Configuration>,
4242
// tslint:disable-next-line:no-implicit-dependencies
43-
): Promise<[experimental.workspace.Workspace, typeof import('karma'), webpack.Configuration]> {
44-
const { config, workspace } = await generateBrowserWebpackConfigFromContext(
43+
): Promise<[typeof import('karma'), webpack.Configuration]> {
44+
const { config } = await generateBrowserWebpackConfigFromContext(
4545
// only two properties are missing:
4646
// * `outputPath` which is fixed for tests
4747
// * `budgets` which might be incorrect due to extra dev libs
@@ -60,7 +60,6 @@ async function initialize(
6060
const karma = await import('karma');
6161

6262
return [
63-
workspace,
6463
karma,
6564
webpackConfigurationTransformer ? await webpackConfigurationTransformer(config[0]) : config[0],
6665
];
@@ -80,7 +79,7 @@ export function execute(
8079

8180
return from(initialize(options, context, transforms.webpackConfiguration)).pipe(
8281
switchMap(
83-
([workspace, karma, webpackConfig]) =>
82+
([karma, webpackConfig]) =>
8483
new Observable<BuilderOutput>(subscriber => {
8584
const karmaOptions: KarmaConfigOptions = {};
8685

@@ -111,12 +110,10 @@ export function execute(
111110
options.include &&
112111
options.include.length > 0
113112
) {
114-
const mainFilePath = getSystemPath(join(workspace.root, options.main));
115-
const files = findTests(
116-
options.include,
117-
dirname(mainFilePath),
118-
getSystemPath(workspace.root),
113+
const mainFilePath = getSystemPath(
114+
join(normalize(context.workspaceRoot), options.main),
119115
);
116+
const files = findTests(options.include, dirname(mainFilePath), context.workspaceRoot);
120117
// early exit, no reason to start karma
121118
if (!files.length) {
122119
subscriber.error(

packages/angular_devkit/build_angular/src/utils/webpack-browser-config.ts

Lines changed: 40 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,10 @@
77
*/
88
import { BuilderContext } from '@angular-devkit/architect';
99
import {
10-
experimental,
1110
getSystemPath,
1211
logging,
1312
normalize,
1413
resolve,
15-
schema,
1614
virtualFs,
1715
} from '@angular-devkit/core';
1816
import { NodeJsSyncHost } from '@angular-devkit/core/node';
@@ -60,9 +58,10 @@ export async function generateWebpackConfig(
6058
// However this config generation is used by multiple builders such as dev-server
6159
const scriptTarget = tsConfig.options.target || ts.ScriptTarget.ES5;
6260
const buildBrowserFeatures = new BuildBrowserFeatures(projectRoot, scriptTarget);
63-
const differentialLoading = context.builder.builderName === 'browser'
64-
&& !options.watch
65-
&& buildBrowserFeatures.isDifferentialLoadingNeeded();
61+
const differentialLoading =
62+
context.builder.builderName === 'browser' &&
63+
!options.watch &&
64+
buildBrowserFeatures.isDifferentialLoadingNeeded();
6665

6766
const scriptTargets = [scriptTarget];
6867

@@ -73,29 +72,32 @@ export async function generateWebpackConfig(
7372
// For differential loading, we can have several targets
7473
return scriptTargets.map(scriptTarget => {
7574
let buildOptions: NormalizedBrowserBuilderSchema = { ...options };
76-
const supportES2015
77-
= scriptTarget !== ts.ScriptTarget.ES3 && scriptTarget !== ts.ScriptTarget.ES5;
75+
const supportES2015 =
76+
scriptTarget !== ts.ScriptTarget.ES3 && scriptTarget !== ts.ScriptTarget.ES5;
7877

7978
if (differentialLoading && fullDifferential) {
8079
buildOptions = {
8180
...options,
82-
...(
83-
// FIXME: we do create better webpack config composition to achieve the below
84-
// When DL is enabled and supportES2015 is true it means that we are on the second build
85-
// This also means that we don't need to include styles and assets multiple times
86-
supportES2015
87-
? {}
88-
: {
81+
...// FIXME: we do create better webpack config composition to achieve the below
82+
// When DL is enabled and supportES2015 is true it means that we are on the second build
83+
// This also means that we don't need to include styles and assets multiple times
84+
(supportES2015
85+
? {}
86+
: {
8987
styles: options.extractCss ? [] : options.styles,
9088
assets: [],
91-
}
92-
),
89+
}),
9390
es5BrowserSupport: undefined,
9491
esVersionInFileName: true,
9592
scriptTargetOverride: scriptTarget,
9693
};
9794
} else if (differentialLoading && !fullDifferential) {
98-
buildOptions = { ...options, esVersionInFileName: true, scriptTargetOverride: ts.ScriptTarget.ES5, es5BrowserSupport: undefined };
95+
buildOptions = {
96+
...options,
97+
esVersionInFileName: true,
98+
scriptTargetOverride: ts.ScriptTarget.ES5,
99+
es5BrowserSupport: undefined,
100+
};
99101
}
100102

101103
const wco: BrowserWebpackConfigOptions = {
@@ -145,75 +147,48 @@ export async function generateWebpackConfig(
145147
});
146148
}
147149

148-
149-
export async function generateBrowserWebpackConfigFromWorkspace(
150+
export async function generateBrowserWebpackConfigFromContext(
150151
options: BrowserBuilderSchema,
151152
context: BuilderContext,
152-
projectName: string,
153-
workspace: experimental.workspace.Workspace,
154-
host: virtualFs.Host<fs.Stats>,
155153
webpackPartialGenerator: (wco: BrowserWebpackConfigOptions) => webpack.Configuration[],
156-
logger: logging.LoggerApi,
157-
): Promise<webpack.Configuration[]> {
158-
// TODO: Use a better interface for workspace access.
159-
const projectRoot = resolve(workspace.root, normalize(workspace.getProject(projectName).root));
160-
const projectSourceRoot = workspace.getProject(projectName).sourceRoot;
154+
host: virtualFs.Host<fs.Stats> = new NodeJsSyncHost(),
155+
): Promise<{ config: webpack.Configuration[]; projectRoot: string; projectSourceRoot?: string }> {
156+
const projectName = context.target && context.target.project;
157+
if (!projectName) {
158+
throw new Error('The builder requires a target.');
159+
}
160+
161+
const workspaceRoot = normalize(context.workspaceRoot);
162+
const projectMetadata = await context.getProjectMetadata(projectName);
163+
const projectRoot = resolve(workspaceRoot, normalize((projectMetadata.root as string) || ''));
164+
const projectSourceRoot = projectMetadata.sourceRoot as string | undefined;
161165
const sourceRoot = projectSourceRoot
162-
? resolve(workspace.root, normalize(projectSourceRoot))
166+
? resolve(workspaceRoot, normalize(projectSourceRoot))
163167
: undefined;
164168

165169
const normalizedOptions = normalizeBrowserSchema(
166170
host,
167-
workspace.root,
171+
workspaceRoot,
168172
projectRoot,
169173
sourceRoot,
170174
options,
171175
);
172176

173-
return generateWebpackConfig(
177+
const config = await generateWebpackConfig(
174178
context,
175-
getSystemPath(workspace.root),
179+
getSystemPath(workspaceRoot),
176180
getSystemPath(projectRoot),
177181
sourceRoot && getSystemPath(sourceRoot),
178182
normalizedOptions,
179183
webpackPartialGenerator,
180-
logger,
181-
);
182-
}
183-
184-
185-
export async function generateBrowserWebpackConfigFromContext(
186-
options: BrowserBuilderSchema,
187-
context: BuilderContext,
188-
webpackPartialGenerator: (wco: BrowserWebpackConfigOptions) => webpack.Configuration[],
189-
host: virtualFs.Host<fs.Stats> = new NodeJsSyncHost(),
190-
): Promise<{ workspace: experimental.workspace.Workspace, config: webpack.Configuration[] }> {
191-
const registry = new schema.CoreSchemaRegistry();
192-
registry.addPostTransform(schema.transforms.addUndefinedDefaults);
193-
194-
const workspace = await experimental.workspace.Workspace.fromPath(
195-
host,
196-
normalize(context.workspaceRoot),
197-
registry,
198-
);
199-
200-
const projectName = context.target ? context.target.project : workspace.getDefaultProjectName();
201-
202-
if (!projectName) {
203-
throw new Error('Must either have a target from the context or a default project.');
204-
}
205-
206-
const config = await generateBrowserWebpackConfigFromWorkspace(
207-
options,
208-
context,
209-
projectName,
210-
workspace,
211-
host,
212-
webpackPartialGenerator,
213184
context.logger,
214185
);
215186

216-
return { workspace, config };
187+
return {
188+
config,
189+
projectRoot: getSystemPath(projectRoot),
190+
projectSourceRoot: sourceRoot && getSystemPath(sourceRoot),
191+
};
217192
}
218193

219194
export function getIndexOutputFile(options: BrowserBuilderSchema): string {

0 commit comments

Comments
 (0)