Skip to content

Commit 2616ef0

Browse files
committed
feat(@angular-devkit/build-angular): integrate JIT mode linker
With this change we intergate JIT mode linker into the Angular CLI. Closes #20281
1 parent 8862a9f commit 2616ef0

File tree

4 files changed

+40
-30
lines changed

4 files changed

+40
-30
lines changed

packages/angular_devkit/build_angular/src/babel/presets/application.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ export interface ApplicationPresetOptions {
1616
translation?: unknown;
1717
};
1818

19-
angularLinker?: boolean;
19+
angularLinker?: {
20+
shouldLink: boolean;
21+
jitMode: boolean;
22+
};
2023

2124
forceES5?: boolean;
2225
forceAsyncTransformation?: boolean;
@@ -124,21 +127,24 @@ export default function (api: unknown, options: ApplicationPresetOptions) {
124127
const plugins = [];
125128
let needRuntimeTransform = false;
126129

127-
if (options.angularLinker) {
130+
if (options.angularLinker?.shouldLink) {
128131
// Babel currently is synchronous so import cannot be used
129132
const {
130133
createEs2015LinkerPlugin,
131-
} = require('@angular/compiler-cli/linker/babel');
134+
} = require('@angular/compiler-cli/linker/babel') as typeof import('@angular/compiler-cli/linker/babel');
132135

133136
plugins.push(createEs2015LinkerPlugin({
137+
linkerJitMode: options.angularLinker.jitMode,
134138
logger: createNgtscLogger(options.diagnosticReporter),
135139
fileSystem: {
136140
resolve: path.resolve,
137141
exists: fs.existsSync,
138142
dirname: path.dirname,
139143
relative: path.relative,
140144
readFile: fs.readFileSync,
141-
},
145+
// Node.JS types don't overlap the Compiler types.
146+
// tslint:disable-next-line: no-any
147+
} as any,
142148
}));
143149
}
144150

packages/angular_devkit/build_angular/src/babel/webpack-loader.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,9 @@ import { custom } from 'babel-loader';
1010
import { ScriptTarget } from 'typescript';
1111
import { ApplicationPresetOptions } from './presets/application';
1212

13-
interface AngularCustomOptions {
13+
interface AngularCustomOptions extends Pick<ApplicationPresetOptions, 'angularLinker' | 'i18n'> {
1414
forceAsyncTransformation: boolean;
1515
forceES5: boolean;
16-
shouldLink: boolean;
17-
i18n: ApplicationPresetOptions['i18n'];
1816
}
1917

2018
function requiresLinking(
@@ -41,20 +39,25 @@ export default custom<AngularCustomOptions>(() => {
4139
});
4240

4341
return {
44-
async customOptions({ i18n, scriptTarget, ...rawOptions }, { source }) {
42+
async customOptions({ i18n, scriptTarget, aot, ...rawOptions }, { source }) {
4543
// Must process file if plugins are added
4644
let shouldProcess = Array.isArray(rawOptions.plugins) && rawOptions.plugins.length > 0;
4745

4846
const customOptions: AngularCustomOptions = {
4947
forceAsyncTransformation: false,
5048
forceES5: false,
51-
shouldLink: false,
49+
angularLinker: undefined,
5250
i18n: undefined,
5351
};
5452

5553
// Analyze file for linking
56-
customOptions.shouldLink = await requiresLinking(this.resourcePath, source);
57-
shouldProcess ||= customOptions.shouldLink;
54+
if (await requiresLinking(this.resourcePath, source)) {
55+
customOptions.angularLinker = {
56+
shouldLink: true,
57+
jitMode: aot !== true,
58+
};
59+
shouldProcess = true;
60+
}
5861

5962
// Analyze for ES target processing
6063
const esTarget = scriptTarget as ScriptTarget | undefined;
@@ -109,10 +112,7 @@ export default custom<AngularCustomOptions>(() => {
109112
[
110113
require('./presets/application').default,
111114
{
112-
angularLinker: customOptions.shouldLink,
113-
forceES5: customOptions.forceES5,
114-
forceAsyncTransformation: customOptions.forceAsyncTransformation,
115-
i18n: customOptions.i18n,
115+
...customOptions,
116116
diagnosticReporter: (type, message) => {
117117
switch (type) {
118118
case 'error':

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,7 @@ export function getCommonConfig(wco: WebpackConfigOptions): Configuration {
493493
options: {
494494
cacheDirectory: findCachePath('babel-webpack'),
495495
scriptTarget: wco.scriptTarget,
496+
aot: buildOptions.aot,
496497
},
497498
},
498499
...buildOptimizerUseRule,

tests/legacy-cli/e2e/tests/generate/library/library-consumption-linker.ts

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1+
import { getGlobalVariable } from '../../../utils/env';
12
import { writeFile } from '../../../utils/fs';
2-
import { getActivePackageManager } from '../../../utils/packages';
3-
import { ng, silentYarn } from '../../../utils/process';
3+
import { ng } from '../../../utils/process';
44
import { updateJsonFile } from '../../../utils/project';
5-
import { getGlobalVariable } from '../../../utils/env';
65

76
export default async function () {
87
if ((getGlobalVariable('argv')['ve'])) {
@@ -13,8 +12,7 @@ export default async function () {
1312
await ng('generate', 'library', 'my-lib');
1413

1514
// Enable partial compilation mode (linker) for the library
16-
// Enable ivy for production as well (current schematic disables ivy in production)
17-
await updateJsonFile('projects/my-lib/tsconfig.lib.prod.json', config => {
15+
await updateJsonFile('projects/my-lib/tsconfig.lib.json', config => {
1816
const { angularCompilerOptions = {} } = config;
1917
angularCompilerOptions.enableIvy = true;
2018
angularCompilerOptions.compilationMode = 'partial';
@@ -51,7 +49,7 @@ export default async function () {
5149
template: '<lib-my-lib></lib-my-lib>'
5250
})
5351
export class AppComponent {
54-
title = 'app';
52+
title = 'test-project';
5553
5654
constructor(myLibService: MyLibService) {
5755
console.log(myLibService);
@@ -85,18 +83,23 @@ export default async function () {
8583
});
8684
`);
8785

88-
await runLibraryTests();
89-
await runLibraryTests(true);
90-
}
86+
// Build library in partial mode (development)
87+
await ng('build', 'my-lib', '--configuration=development');
9188

92-
async function runLibraryTests(prodMode = false): Promise<void> {
93-
const args = ['build', 'my-lib'];
94-
if (!prodMode) {
95-
args.push('--configuration=development');
96-
}
89+
// AOT linking
90+
await runTests();
9791

98-
await ng(...args);
92+
// JIT linking
93+
await updateJsonFile('angular.json', config => {
94+
const build = config.projects['test-project'].architect.build;
95+
build.options.aot = false;
96+
build.configurations.production.buildOptimizer = false;
97+
});
98+
99+
await runTests();
100+
}
99101

102+
async function runTests(): Promise<void> {
100103
// Check that the tests succeeds both with named project, unnamed (should test app), and prod.
101104
await ng('e2e');
102105
await ng('e2e', 'test-project', '--devServerTarget=test-project:serve:production');

0 commit comments

Comments
 (0)