Skip to content

Commit 11c6abd

Browse files
alan-agius4filipesilva
authored andcommitted
refactor(@angular-devkit/build-angular): clean up differential loading config generation
Closes #16098
1 parent f10f910 commit 11c6abd

File tree

3 files changed

+74
-76
lines changed

3 files changed

+74
-76
lines changed

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

+57-49
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*/
88
import { BuilderContext, BuilderOutput, createBuilder } from '@angular-devkit/architect';
99
import { EmittedFiles, WebpackLoggingCallback, runWebpack } from '@angular-devkit/build-webpack';
10-
import { join, json, normalize, tags, virtualFs } from '@angular-devkit/core';
10+
import { getSystemPath, join, json, normalize, resolve, tags, virtualFs } from '@angular-devkit/core';
1111
import { NodeJsSyncHost } from '@angular-devkit/core/node';
1212
import * as fs from 'fs';
1313
import * as ora from 'ora';
@@ -50,7 +50,6 @@ import { augmentAppWithServiceWorker } from '../utils/service-worker';
5050
import { assertCompatibleAngularVersion } from '../utils/version';
5151
import {
5252
BrowserWebpackConfigOptions,
53-
generateBrowserWebpackConfigFromContext,
5453
generateI18nBrowserWebpackConfigFromContext,
5554
getIndexInputFile,
5655
getIndexOutputFile,
@@ -97,25 +96,15 @@ interface ConfigFromContextReturn {
9796
config: webpack.Configuration;
9897
projectRoot: string;
9998
projectSourceRoot?: string;
99+
i18n: I18nOptions;
100100
}
101101

102-
export async function buildBrowserWebpackConfigFromContext(
103-
options: BrowserBuilderSchema,
104-
context: BuilderContext,
105-
host: virtualFs.Host<fs.Stats>,
106-
i18n: boolean,
107-
): Promise<ConfigFromContextReturn & { i18n: I18nOptions }>;
108-
export async function buildBrowserWebpackConfigFromContext(
109-
options: BrowserBuilderSchema,
110-
context: BuilderContext,
111-
host?: virtualFs.Host<fs.Stats>,
112-
): Promise<ConfigFromContextReturn>;
113102
export async function buildBrowserWebpackConfigFromContext(
114103
options: BrowserBuilderSchema,
115104
context: BuilderContext,
116105
host: virtualFs.Host<fs.Stats> = new NodeJsSyncHost(),
117-
i18n = false,
118-
): Promise<ConfigFromContextReturn & { i18n?: I18nOptions }> {
106+
differentialLoadingMode = false,
107+
): Promise<ConfigFromContextReturn> {
119108
const webpackPartialGenerator = (wco: BrowserWebpackConfigOptions) => [
120109
getCommonConfig(wco),
121110
getBrowserConfig(wco),
@@ -126,16 +115,13 @@ export async function buildBrowserWebpackConfigFromContext(
126115
wco.buildOptions.webWorkerTsConfig ? getWorkerConfig(wco) : {},
127116
];
128117

129-
if (i18n) {
130-
return generateI18nBrowserWebpackConfigFromContext(
131-
options,
132-
context,
133-
webpackPartialGenerator,
134-
host,
135-
);
136-
}
137-
138-
return generateBrowserWebpackConfigFromContext(options, context, webpackPartialGenerator, host);
118+
return generateI18nBrowserWebpackConfigFromContext(
119+
options,
120+
context,
121+
webpackPartialGenerator,
122+
host,
123+
differentialLoadingMode,
124+
);
139125
}
140126

141127
function getAnalyticsConfig(
@@ -177,6 +163,7 @@ async function initialize(
177163
options: BrowserBuilderSchema,
178164
context: BuilderContext,
179165
host: virtualFs.Host<fs.Stats>,
166+
differentialLoadingMode: boolean,
180167
webpackConfigurationTransform?: ExecutionTransformer<webpack.Configuration>,
181168
): Promise<{
182169
config: webpack.Configuration;
@@ -194,7 +181,7 @@ async function initialize(
194181
projectRoot,
195182
projectSourceRoot,
196183
i18n,
197-
} = await buildBrowserWebpackConfigFromContext(adjustedOptions, context, host, true);
184+
} = await buildBrowserWebpackConfigFromContext(adjustedOptions, context, host, differentialLoadingMode);
198185

199186
// Validate asset option values if processed directly
200187
if (options.assets?.length && !adjustedOptions.assets?.length) {
@@ -235,39 +222,60 @@ export function buildWebpackBrowser(
235222
): Observable<BrowserBuilderOutput> {
236223
const host = new NodeJsSyncHost();
237224
const root = normalize(context.workspaceRoot);
225+
226+
const projectName = context.target && context.target.project;
227+
if (!projectName) {
228+
throw new Error('The builder requires a target.');
229+
}
230+
238231
const baseOutputPath = path.resolve(context.workspaceRoot, options.outputPath);
239232
let outputPaths: undefined | Map<string, string>;
240233

241234
// Check Angular version.
242235
assertCompatibleAngularVersion(context.workspaceRoot, context.logger);
243236

244-
return from(initialize(options, context, host, transforms.webpackConfiguration)).pipe(
245-
// tslint:disable-next-line: no-big-function
246-
switchMap(({ config, projectRoot, projectSourceRoot, i18n }) => {
247-
const tsConfig = readTsconfig(options.tsConfig, context.workspaceRoot);
248-
const target = tsConfig.options.target || ScriptTarget.ES5;
249-
const buildBrowserFeatures = new BuildBrowserFeatures(projectRoot, target);
250-
const isDifferentialLoadingNeeded = buildBrowserFeatures.isDifferentialLoadingNeeded();
251-
252-
if (target > ScriptTarget.ES2015 && isDifferentialLoadingNeeded) {
253-
context.logger.warn(tags.stripIndent`
237+
return from(context.getProjectMetadata(projectName))
238+
.pipe(
239+
switchMap(async projectMetadata => {
240+
const sysProjectRoot = getSystemPath(
241+
resolve(normalize(context.workspaceRoot),
242+
normalize((projectMetadata.root as string) ?? '')),
243+
);
244+
245+
const { options: compilerOptions } = readTsconfig(options.tsConfig, context.workspaceRoot);
246+
const target = compilerOptions.target || ScriptTarget.ES5;
247+
const buildBrowserFeatures = new BuildBrowserFeatures(sysProjectRoot);
248+
const isDifferentialLoadingNeeded = buildBrowserFeatures.isDifferentialLoadingNeeded(target);
249+
const differentialLoadingMode = !options.watch && isDifferentialLoadingNeeded;
250+
251+
if (target > ScriptTarget.ES2015 && isDifferentialLoadingNeeded) {
252+
context.logger.warn(tags.stripIndent`
254253
WARNING: Using differential loading with targets ES5 and ES2016 or higher may
255254
cause problems. Browsers with support for ES2015 will load the ES2016+ scripts
256255
referenced with script[type="module"] but they may not support ES2016+ syntax.
257256
`);
258-
}
259-
260-
const useBundleDownleveling = isDifferentialLoadingNeeded && !options.watch;
261-
const startTime = Date.now();
262-
263-
return runWebpack(config, context, {
264-
webpackFactory: require('webpack') as typeof webpack,
265-
logging:
266-
transforms.logging ||
267-
(useBundleDownleveling
268-
? () => {}
269-
: createWebpackLoggingCallback(!!options.verbose, context.logger)),
270-
}).pipe(
257+
}
258+
259+
return {
260+
...(await initialize(options, context, host, differentialLoadingMode, transforms.webpackConfiguration)),
261+
buildBrowserFeatures,
262+
isDifferentialLoadingNeeded,
263+
target,
264+
};
265+
}),
266+
// tslint:disable-next-line: no-big-function
267+
switchMap(({ config, projectRoot, projectSourceRoot, i18n, buildBrowserFeatures, isDifferentialLoadingNeeded, target }) => {
268+
const useBundleDownleveling = isDifferentialLoadingNeeded && !options.watch;
269+
const startTime = Date.now();
270+
271+
return runWebpack(config, context, {
272+
webpackFactory: require('webpack') as typeof webpack,
273+
logging:
274+
transforms.logging ||
275+
(useBundleDownleveling
276+
? () => { }
277+
: createWebpackLoggingCallback(!!options.verbose, context.logger)),
278+
}).pipe(
271279
// tslint:disable-next-line: no-big-function
272280
concatMap(async buildEvent => {
273281
const { webpackStats: webpackRawStats, success, emittedFiles = [] } = buildEvent;

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

+2-3
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,6 @@ export function serveWebpackBrowser(
120120
browserOptions,
121121
context,
122122
host,
123-
true,
124123
);
125124
let webpackConfig = config;
126125

@@ -194,10 +193,10 @@ export function serveWebpackBrowser(
194193
const { scripts = [], styles = [], baseHref, tsConfig } = browserOptions;
195194
const { options: compilerOptions } = readTsconfig(tsConfig, context.workspaceRoot);
196195
const target = compilerOptions.target || ts.ScriptTarget.ES5;
197-
const buildBrowserFeatures = new BuildBrowserFeatures(projectRoot, target);
196+
const buildBrowserFeatures = new BuildBrowserFeatures(projectRoot);
198197

199198
const entrypoints = generateEntryPoints({ scripts, styles });
200-
const moduleEntrypoints = buildBrowserFeatures.isDifferentialLoadingNeeded()
199+
const moduleEntrypoints = buildBrowserFeatures.isDifferentialLoadingNeeded(target)
201200
? generateEntryPoints({ scripts: [], styles })
202201
: [];
203202

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

+15-24
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import {
2727
import { WebpackConfigOptions } from '../utils/build-options';
2828
import { readTsconfig } from '../utils/read-tsconfig';
2929
import { getEsVersionForFileName } from '../webpack/utils/helpers';
30-
import { BuildBrowserFeatures } from './build-browser-features';
3130
import { profilingEnabled } from './environment-options';
3231
import { I18nOptions, configureI18nBuild } from './i18n-options';
3332

@@ -36,13 +35,13 @@ const SpeedMeasurePlugin = require('speed-measure-webpack-plugin');
3635
export type BrowserWebpackConfigOptions = WebpackConfigOptions<NormalizedBrowserBuilderSchema>;
3736

3837
export async function generateWebpackConfig(
39-
context: BuilderContext,
4038
workspaceRoot: string,
4139
projectRoot: string,
4240
sourceRoot: string | undefined,
4341
options: NormalizedBrowserBuilderSchema,
4442
webpackPartialGenerator: (wco: BrowserWebpackConfigOptions) => webpack.Configuration[],
4543
logger: logging.LoggerApi,
44+
differentialLoadingMode: boolean,
4645
): Promise<webpack.Configuration> {
4746
// Ensure Build Optimizer is only used with AOT.
4847
if (options.buildOptimizer && !options.aot) {
@@ -66,27 +65,11 @@ export async function generateWebpackConfig(
6665

6766
// tslint:disable-next-line:no-implicit-dependencies
6867
const ts = await import('typescript');
69-
70-
// At the moment, only the browser builder supports differential loading
71-
// However this config generation is used by multiple builders such as dev-server
7268
const scriptTarget = tsConfig.options.target || ts.ScriptTarget.ES5;
73-
const buildBrowserFeatures = new BuildBrowserFeatures(projectRoot, scriptTarget);
74-
const differentialLoading =
75-
context.builder.builderName === 'browser' &&
76-
!options.watch &&
77-
buildBrowserFeatures.isDifferentialLoadingNeeded();
78-
79-
let buildOptions: NormalizedBrowserBuilderSchema = { ...options };
80-
if (differentialLoading) {
81-
buildOptions = {
82-
...options,
83-
// Under downlevel differential loading we copy the assets outside of webpack.
84-
assets: [],
85-
esVersionInFileName: true,
86-
};
87-
}
8869

8970
const supportES2015 = scriptTarget !== ts.ScriptTarget.JSON && scriptTarget > ts.ScriptTarget.ES5;
71+
72+
const buildOptions: NormalizedBrowserBuilderSchema = { ...options };
9073
const wco: BrowserWebpackConfigOptions = {
9174
root: workspaceRoot,
9275
logger: logger.createChild('webpackConfigOptions'),
@@ -96,7 +79,7 @@ export async function generateWebpackConfig(
9679
tsConfig,
9780
tsConfigPath,
9881
supportES2015,
99-
differentialLoadingMode: differentialLoading,
82+
differentialLoadingMode,
10083
};
10184

10285
wco.buildOptions.progress = defaultProgress(wco.buildOptions.progress);
@@ -123,7 +106,7 @@ export async function generateWebpackConfig(
123106
if (profilingEnabled) {
124107
const esVersionInFileName = getEsVersionForFileName(
125108
tsConfig.options.target,
126-
wco.buildOptions.esVersionInFileName,
109+
wco.differentialLoadingMode,
127110
);
128111

129112
const smp = new SpeedMeasurePlugin({
@@ -145,9 +128,16 @@ export async function generateI18nBrowserWebpackConfigFromContext(
145128
context: BuilderContext,
146129
webpackPartialGenerator: (wco: BrowserWebpackConfigOptions) => webpack.Configuration[],
147130
host: virtualFs.Host<fs.Stats> = new NodeJsSyncHost(),
131+
differentialLoadingMode = false,
148132
): Promise<{ config: webpack.Configuration; projectRoot: string; projectSourceRoot?: string, i18n: I18nOptions }> {
149133
const { buildOptions, i18n } = await configureI18nBuild(context, options);
150-
const result = await generateBrowserWebpackConfigFromContext(buildOptions, context, webpackPartialGenerator, host);
134+
const result = await generateBrowserWebpackConfigFromContext(
135+
buildOptions,
136+
context,
137+
webpackPartialGenerator,
138+
host,
139+
differentialLoadingMode,
140+
);
151141
const config = result.config;
152142

153143
if (i18n.shouldInline) {
@@ -208,6 +198,7 @@ export async function generateBrowserWebpackConfigFromContext(
208198
context: BuilderContext,
209199
webpackPartialGenerator: (wco: BrowserWebpackConfigOptions) => webpack.Configuration[],
210200
host: virtualFs.Host<fs.Stats> = new NodeJsSyncHost(),
201+
differentialLoadingMode = false,
211202
): Promise<{ config: webpack.Configuration; projectRoot: string; projectSourceRoot?: string }> {
212203
const projectName = context.target && context.target.project;
213204
if (!projectName) {
@@ -231,13 +222,13 @@ export async function generateBrowserWebpackConfigFromContext(
231222
);
232223

233224
const config = await generateWebpackConfig(
234-
context,
235225
getSystemPath(workspaceRoot),
236226
getSystemPath(projectRoot),
237227
sourceRoot && getSystemPath(sourceRoot),
238228
normalizedOptions,
239229
webpackPartialGenerator,
240230
context.logger,
231+
differentialLoadingMode,
241232
);
242233

243234
return {

0 commit comments

Comments
 (0)