Skip to content

Commit 1c1bff8

Browse files
committed
refactor(@angular-devkit/build-angular): integrate Ivy Webpack compiler plugin
This change integrates the Ivy Webpack compiler plugin into the browser builder. When Ivy is enabled, which is the default behavior for applications, this plugin will now be used. If needed, the previous plugin can still be used by enabling the `NG_BUILD_IVY_LEGACY` environment variable.
1 parent 7e07698 commit 1c1bff8

File tree

2 files changed

+109
-13
lines changed

2 files changed

+109
-13
lines changed

packages/angular_devkit/build_angular/src/webpack/configs/common.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,14 @@ export function getCommonConfig(wco: WebpackConfigOptions): Configuration {
327327

328328
if (buildOptions.namedChunks && !isWebpackFiveOrHigher()) {
329329
extraPlugins.push(new NamedLazyChunksPlugin());
330+
331+
// Provide full names for lazy routes that use the deprecated string format
332+
extraPlugins.push(
333+
new ContextReplacementPlugin(
334+
/\@angular[\\\/]core[\\\/]/,
335+
(data: { chunkName?: string }) => (data.chunkName = '[request]'),
336+
),
337+
);
330338
}
331339

332340
if (!differentialLoadingMode) {

packages/angular_devkit/build_angular/src/webpack/configs/typescript.ts

Lines changed: 101 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,73 @@ import {
1313
AngularCompilerPlugin,
1414
AngularCompilerPluginOptions,
1515
NgToolsLoader,
16-
PLATFORM
16+
PLATFORM,
17+
ivy,
1718
} from '@ngtools/webpack';
1819
import { WebpackConfigOptions, BuildOptions } from '../../utils/build-options';
20+
import { CompilerOptions } from '@angular/compiler-cli';
21+
import { RuleSetLoader } from 'webpack';
22+
23+
function canUseIvyPlugin(wco: WebpackConfigOptions): boolean {
24+
// Can only be used with Ivy
25+
if (!wco.tsConfig.options.enableIvy) {
26+
return false;
27+
}
28+
29+
// Allow fallback to legacy build system via environment variable ('NG_BUILD_IVY_LEGACY=1')
30+
const flag = process.env['NG_BUILD_IVY_LEGACY'];
31+
if (flag !== undefined && flag !== '0' && flag.toLowerCase() !== 'false') {
32+
wco.logger.warn(
33+
'"NG_BUILD_IVY_LEGACY" environment variable detected. Using legacy Ivy build system.',
34+
);
35+
36+
return false;
37+
}
38+
39+
// Lazy modules option uses the deprecated string format for lazy routes
40+
if (wco.buildOptions.lazyModules && wco.buildOptions.lazyModules.length > 0) {
41+
return false;
42+
}
43+
44+
// This pass relies on internals of the original plugin
45+
if (wco.buildOptions.experimentalRollupPass) {
46+
return false;
47+
}
48+
49+
return true;
50+
}
51+
52+
function createIvyPlugin(
53+
wco: WebpackConfigOptions,
54+
aot: boolean,
55+
tsconfig: string,
56+
): ivy.AngularWebpackPlugin {
57+
const { buildOptions } = wco;
58+
const optimize = buildOptions.optimization.scripts;
59+
60+
const compilerOptions: CompilerOptions = {
61+
skipTemplateCodegen: !aot,
62+
sourceMap: buildOptions.sourceMap.scripts,
63+
};
64+
65+
if (buildOptions.preserveSymlinks !== undefined) {
66+
compilerOptions.preserveSymlinks = buildOptions.preserveSymlinks;
67+
}
68+
69+
const fileReplacements: Record<string, string> = {};
70+
if (buildOptions.fileReplacements) {
71+
for (const replacement of buildOptions.fileReplacements) {
72+
fileReplacements[replacement.replace] = replacement.with;
73+
}
74+
}
75+
76+
return new ivy.AngularWebpackPlugin({
77+
tsconfig,
78+
compilerOptions,
79+
fileReplacements,
80+
emitNgModuleScope: !optimize,
81+
});
82+
}
1983

2084
function _pluginOptionsOverrides(
2185
buildOptions: BuildOptions,
@@ -112,31 +176,55 @@ export function getNonAotConfig(wco: WebpackConfigOptions) {
112176

113177
export function getAotConfig(wco: WebpackConfigOptions, i18nExtract = false) {
114178
const { tsConfigPath, buildOptions } = wco;
179+
const optimize = buildOptions.optimization.scripts;
180+
const useIvyOnlyPlugin = canUseIvyPlugin(wco) && !i18nExtract;
115181

116-
const loaders: any[] = [NgToolsLoader];
182+
let buildOptimizerRules: RuleSetLoader[] = [];
117183
if (buildOptions.buildOptimizer) {
118-
loaders.unshift({
184+
buildOptimizerRules = [{
119185
loader: buildOptimizerLoaderPath,
120186
options: { sourceMap: buildOptions.sourceMap.scripts }
121-
});
187+
}];
122188
}
123189

124-
const test = /(?:\.ngfactory\.js|\.ngstyle\.js|\.tsx?)$/;
125-
const optimize = wco.buildOptions.optimization.scripts;
126-
127190
return {
128-
module: { rules: [{ test, use: loaders }] },
191+
module: {
192+
rules: [
193+
{
194+
test: useIvyOnlyPlugin ? /\.tsx?$/ : /(?:\.ngfactory\.js|\.ngstyle\.js|\.tsx?)$/,
195+
use: [
196+
...buildOptimizerRules,
197+
useIvyOnlyPlugin ? ivy.AngularWebpackLoaderPath : NgToolsLoader,
198+
],
199+
},
200+
// "allowJs" support with ivy plugin - ensures build optimizer is not run twice
201+
...(useIvyOnlyPlugin
202+
? [
203+
{
204+
test: /\.jsx?$/,
205+
use: [ivy.AngularWebpackLoaderPath],
206+
},
207+
]
208+
: []),
209+
],
210+
},
129211
plugins: [
130-
_createAotPlugin(
131-
wco,
132-
{ tsConfigPath, emitClassMetadata: !optimize, emitNgModuleScope: !optimize },
133-
i18nExtract,
134-
),
212+
useIvyOnlyPlugin
213+
? createIvyPlugin(wco, true, tsConfigPath)
214+
: _createAotPlugin(
215+
wco,
216+
{ tsConfigPath, emitClassMetadata: !optimize, emitNgModuleScope: !optimize },
217+
i18nExtract,
218+
),
135219
],
136220
};
137221
}
138222

139223
export function getTypescriptWorkerPlugin(wco: WebpackConfigOptions, workerTsConfigPath: string) {
224+
if (wco.buildOptions.aot && canUseIvyPlugin(wco)) {
225+
return createIvyPlugin(wco, false, workerTsConfigPath);
226+
}
227+
140228
const { buildOptions } = wco;
141229

142230
let pluginOptions: AngularCompilerPluginOptions = {

0 commit comments

Comments
 (0)