Skip to content

Commit e1c1ac1

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 763130f commit e1c1ac1

File tree

2 files changed

+125
-15
lines changed

2 files changed

+125
-15
lines changed

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

+8
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

+117-15
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,
@@ -103,40 +167,78 @@ function _createAotPlugin(
103167

104168
export function getNonAotConfig(wco: WebpackConfigOptions) {
105169
const { tsConfigPath } = wco;
170+
const useIvyOnlyPlugin = canUseIvyPlugin(wco);
106171

107172
return {
108-
module: { rules: [{ test: /\.tsx?$/, loader: NgToolsLoader }] },
109-
plugins: [_createAotPlugin(wco, { tsConfigPath, skipCodeGeneration: true })]
173+
module: {
174+
rules: [
175+
{
176+
test: useIvyOnlyPlugin ? /\.[jt]sx?$/ : /\.tsx?$/,
177+
loader: useIvyOnlyPlugin
178+
? ivy.AngularWebpackLoaderPath
179+
: NgToolsLoader,
180+
},
181+
],
182+
},
183+
plugins: [
184+
useIvyOnlyPlugin
185+
? createIvyPlugin(wco, false, tsConfigPath)
186+
: _createAotPlugin(wco, { tsConfigPath, skipCodeGeneration: true }),
187+
],
110188
};
111189
}
112190

113191
export function getAotConfig(wco: WebpackConfigOptions, i18nExtract = false) {
114192
const { tsConfigPath, buildOptions } = wco;
193+
const optimize = buildOptions.optimization.scripts;
194+
const useIvyOnlyPlugin = canUseIvyPlugin(wco) && !i18nExtract;
115195

116-
const loaders: any[] = [NgToolsLoader];
196+
let buildOptimizerRules: RuleSetLoader[] = [];
117197
if (buildOptions.buildOptimizer) {
118-
loaders.unshift({
198+
buildOptimizerRules = [{
119199
loader: buildOptimizerLoaderPath,
120200
options: { sourceMap: buildOptions.sourceMap.scripts }
121-
});
201+
}];
122202
}
123203

124-
const test = /(?:\.ngfactory\.js|\.ngstyle\.js|\.tsx?)$/;
125-
const optimize = wco.buildOptions.optimization.scripts;
126-
127204
return {
128-
module: { rules: [{ test, use: loaders }] },
205+
module: {
206+
rules: [
207+
{
208+
test: useIvyOnlyPlugin ? /\.tsx?$/ : /(?:\.ngfactory\.js|\.ngstyle\.js|\.tsx?)$/,
209+
use: [
210+
...buildOptimizerRules,
211+
useIvyOnlyPlugin ? ivy.AngularWebpackLoaderPath : NgToolsLoader,
212+
],
213+
},
214+
// "allowJs" support with ivy plugin - ensures build optimizer is not run twice
215+
...(useIvyOnlyPlugin
216+
? [
217+
{
218+
test: /\.jsx?$/,
219+
use: [ivy.AngularWebpackLoaderPath],
220+
},
221+
]
222+
: []),
223+
],
224+
},
129225
plugins: [
130-
_createAotPlugin(
131-
wco,
132-
{ tsConfigPath, emitClassMetadata: !optimize, emitNgModuleScope: !optimize },
133-
i18nExtract,
134-
),
226+
useIvyOnlyPlugin
227+
? createIvyPlugin(wco, true, tsConfigPath)
228+
: _createAotPlugin(
229+
wco,
230+
{ tsConfigPath, emitClassMetadata: !optimize, emitNgModuleScope: !optimize },
231+
i18nExtract,
232+
),
135233
],
136234
};
137235
}
138236

139237
export function getTypescriptWorkerPlugin(wco: WebpackConfigOptions, workerTsConfigPath: string) {
238+
if (canUseIvyPlugin(wco)) {
239+
return createIvyPlugin(wco, false, workerTsConfigPath);
240+
}
241+
140242
const { buildOptions } = wco;
141243

142244
let pluginOptions: AngularCompilerPluginOptions = {

0 commit comments

Comments
 (0)