Skip to content

Commit 7347d88

Browse files
Alan AgiusKeen Yee Liau
Alan Agius
authored and
Keen Yee Liau
committed
feat(@ngtools/webpack): add support for Ivy compatible solution
Ivy compatible solution still uses the 'standard' bootstrapping code, however the difference is that there are no factories. Using a similar approach for `ngc` but without factories and instead of `bootstrapModuleFactory` it uses `bootstrapModule`.
1 parent f94576b commit 7347d88

File tree

3 files changed

+65
-11
lines changed

3 files changed

+65
-11
lines changed

Diff for: packages/ngtools/webpack/src/angular_compiler_plugin.ts

+8-3
Original file line numberDiff line numberDiff line change
@@ -406,12 +406,12 @@ export class AngularCompilerPlugin {
406406
}
407407

408408
// If there's still no entryModule try to resolve from mainPath.
409-
if (!this._entryModule && this._mainPath && !this._compilerOptions.enableIvy) {
409+
if (!this._entryModule && this._mainPath) {
410410
time('AngularCompilerPlugin._make.resolveEntryModuleFromMain');
411411
this._entryModule = resolveEntryModuleFromMain(
412412
this._mainPath, this._compilerHost, this._getTsProgram() as ts.Program);
413413

414-
if (!this.entryModule) {
414+
if (!this.entryModule && !this._compilerOptions.enableIvy) {
415415
this._warnings.push('Lazy routes discovery is not enabled. '
416416
+ 'Because there is neither an entryModule nor a '
417417
+ 'statically analyzable bootstrap code in the main file.',
@@ -879,7 +879,12 @@ export class AngularCompilerPlugin {
879879

880880
if (!this._JitMode) {
881881
// Replace bootstrap in browser AOT.
882-
this._transformers.push(replaceBootstrap(isAppPath, getEntryModule, getTypeChecker));
882+
this._transformers.push(replaceBootstrap(
883+
isAppPath,
884+
getEntryModule,
885+
getTypeChecker,
886+
!!this._compilerOptions.enableIvy,
887+
));
883888
}
884889
} else if (this._platform === PLATFORM.Server) {
885890
this._transformers.push(exportLazyModuleMap(isMainPath, getLazyRoutes));

Diff for: packages/ngtools/webpack/src/transformers/replace_bootstrap.ts

+15-8
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export function replaceBootstrap(
1717
shouldTransform: (fileName: string) => boolean,
1818
getEntryModule: () => { path: string, className: string } | null,
1919
getTypeChecker: () => ts.TypeChecker,
20+
enableIvy?: boolean,
2021
): ts.TransformerFactory<ts.SourceFile> {
2122

2223
const standardTransform: StandardTransform = function (sourceFile: ts.SourceFile) {
@@ -37,9 +38,6 @@ export function replaceBootstrap(
3738
return [];
3839
}
3940

40-
const relativeEntryModulePath = relative(dirname(sourceFile.fileName), entryModule.path);
41-
const normalizedEntryModulePath = `./${relativeEntryModulePath}`.replace(/\\/g, '/');
42-
4341
// Find the bootstrap calls.
4442
entryModuleIdentifiers.forEach(entryModuleIdentifier => {
4543
// Figure out if it's a `platformBrowserDynamic().bootstrapModule(AppModule)` call.
@@ -79,19 +77,28 @@ export function replaceBootstrap(
7977
const idNgFactory = ts.createUniqueName('__NgCli_bootstrap_');
8078

8179
// Add the transform operations.
82-
const factoryClassName = entryModule.className + 'NgFactory';
83-
const factoryModulePath = normalizedEntryModulePath + '.ngfactory';
80+
const relativeEntryModulePath = relative(dirname(sourceFile.fileName), entryModule.path);
81+
let className = entryModule.className;
82+
let modulePath = `./${relativeEntryModulePath}`.replace(/\\/g, '/');
83+
let bootstrapIdentifier = 'bootstrapModule';
84+
85+
if (!enableIvy) {
86+
className += 'NgFactory';
87+
modulePath += '.ngfactory';
88+
bootstrapIdentifier = 'bootstrapModuleFactory';
89+
}
90+
8491
ops.push(
8592
// Replace the entry module import.
86-
...insertStarImport(sourceFile, idNgFactory, factoryModulePath),
93+
...insertStarImport(sourceFile, idNgFactory, modulePath),
8794
new ReplaceNodeOperation(sourceFile, entryModuleIdentifier,
88-
ts.createPropertyAccess(idNgFactory, ts.createIdentifier(factoryClassName))),
95+
ts.createPropertyAccess(idNgFactory, ts.createIdentifier(className))),
8996
// Replace the platformBrowserDynamic import.
9097
...insertStarImport(sourceFile, idPlatformBrowser, '@angular/platform-browser'),
9198
new ReplaceNodeOperation(sourceFile, platformBrowserDynamicIdentifier,
9299
ts.createPropertyAccess(idPlatformBrowser, 'platformBrowser')),
93100
new ReplaceNodeOperation(sourceFile, bootstrapModuleIdentifier,
94-
ts.createIdentifier('bootstrapModuleFactory')),
101+
ts.createIdentifier(bootstrapIdentifier)),
95102
);
96103
});
97104

Diff for: packages/ngtools/webpack/src/transformers/replace_bootstrap_spec.ts

+42
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,48 @@ describe('@ngtools/webpack transformers', () => {
5252
expect(tags.oneLine`${result}`).toEqual(tags.oneLine`${output}`);
5353
});
5454

55+
it('should replace bootstrap for Ivy without referencing ngFactory', () => {
56+
const input = tags.stripIndent`
57+
import { enableProdMode } from '@angular/core';
58+
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
59+
60+
import { AppModule } from './app/app.module';
61+
import { environment } from './environments/environment';
62+
63+
if (environment.production) {
64+
enableProdMode();
65+
}
66+
67+
platformBrowserDynamic().bootstrapModule(AppModule);
68+
`;
69+
70+
// tslint:disable:max-line-length
71+
const output = tags.stripIndent`
72+
import { enableProdMode } from '@angular/core';
73+
import { environment } from './environments/environment';
74+
75+
import * as __NgCli_bootstrap_1 from "./app/app.module";
76+
import * as __NgCli_bootstrap_2 from "@angular/platform-browser";
77+
78+
if (environment.production) {
79+
enableProdMode();
80+
}
81+
__NgCli_bootstrap_2.platformBrowser().bootstrapModule(__NgCli_bootstrap_1.AppModule);
82+
`;
83+
// tslint:enable:max-line-length
84+
85+
const { program, compilerHost } = createTypescriptContext(input);
86+
const transformer = replaceBootstrap(
87+
() => true,
88+
() => ({ path: '/project/src/app/app.module', className: 'AppModule' }),
89+
() => program.getTypeChecker(),
90+
true,
91+
);
92+
const result = transformTypescript(undefined, [transformer], program, compilerHost);
93+
94+
expect(tags.oneLine`${result}`).toEqual(tags.oneLine`${output}`);
95+
});
96+
5597
it('should replace bootstrap when barrel files are used', () => {
5698
const input = tags.stripIndent`
5799
import { enableProdMode } from '@angular/core';

0 commit comments

Comments
 (0)