Skip to content
This repository was archived by the owner on May 1, 2020. It is now read-only.

Commit 0594803

Browse files
committed
fix(AoT): dynamically enable prod mode for AoT builds
dynamically enable prod mode for AoT builds
1 parent 5d82829 commit 0594803

File tree

4 files changed

+52
-6
lines changed

4 files changed

+52
-6
lines changed

src/aot/aot-compiler.ts

+1
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ export class AotCompiler {
111111
try {
112112
modifiedFileContent = replaceBootstrap(mainFile.path, mainFile.content, AppNgModuleTokens[0], AppNgModuleTokens[1]);
113113
} catch (ex) {
114+
Logger.debug(`Failed to parse bootstrap: `, ex.message);
114115
Logger.warn(`Failed to parse and update ${this.options.entryPoint} content for AoT compilation.
115116
For now, the default fallback content will be used instead.
116117
Please consider updating ${this.options.entryPoint} with the content from the following link:

src/aot/optimization.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import { removeDecorators } from '../util/typescript-utils';
33
export function optimizeJavascript(filePath: string, fileContent: string) {
44
fileContent = removeDecorators(filePath, fileContent);
55
fileContent = purgeDecoratorStatements(filePath, fileContent, ['@angular']);
6-
fileContent = purgeCtorStatements(filePath, fileContent, ['@angular']);
6+
// TODO - needs more testing to fully understand
7+
// fileContent = purgeCtorStatements(filePath, fileContent, ['@angular']);
78
fileContent = purgeKnownContent(filePath, fileContent, ['@angular']);
89

910
return fileContent;

src/aot/utils.ts

+32-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
ScriptTarget
88
} from 'typescript';
99

10-
import { getTypescriptSourceFile, findNodes, replaceImportModuleSpecifier, replaceNamedImport, replaceNode } from '../util/typescript-utils';
10+
import { appendBefore, checkIfFunctionIsCalled, getTypescriptSourceFile, findNodes, insertNamedImportIfNeeded, replaceImportModuleSpecifier, replaceNamedImport, replaceNode } from '../util/typescript-utils';
1111

1212
export function getFallbackMainContent() {
1313
return `
@@ -86,6 +86,34 @@ function replaceBootstrapModuleFactory(filePath: string, fileContent: string) {
8686
return modifiedContent;
8787
}
8888

89+
function getPlatformBrowserFunctionNode(filePath: string, fileContent: string) {
90+
let modifiedFileContent = fileContent;
91+
const sourceFile = getTypescriptSourceFile(filePath, modifiedFileContent, ScriptTarget.Latest, false);
92+
const allCalls = findNodes(sourceFile, sourceFile, SyntaxKind.CallExpression, true) as CallExpression[];
93+
const callsToPlatformBrowser = allCalls.filter(call => call.expression && call.expression.kind === SyntaxKind.Identifier && (call.expression as Identifier).text === 'platformBrowser');
94+
const toAppend = `enableProdMode();\n`;
95+
if (callsToPlatformBrowser.length) {
96+
modifiedFileContent = appendBefore(filePath, modifiedFileContent, callsToPlatformBrowser[0].expression, toAppend);
97+
} else {
98+
// just throw it at the bottom
99+
modifiedFileContent + toAppend;
100+
}
101+
return modifiedFileContent;
102+
}
103+
104+
function importAndEnableProdMode(filePath: string, fileContent: string) {
105+
let modifiedFileContent = fileContent;
106+
modifiedFileContent = insertNamedImportIfNeeded(filePath, modifiedFileContent, 'enableProdMode', '@angular/core');
107+
108+
const isCalled = checkIfFunctionIsCalled(filePath, modifiedFileContent, 'enableProdMode');
109+
if (!isCalled) {
110+
// go ahead and insert this
111+
modifiedFileContent = getPlatformBrowserFunctionNode(filePath, modifiedFileContent);
112+
}
113+
114+
return modifiedFileContent;
115+
}
116+
89117
export function replaceBootstrap(filePath: string, fileContent: string, appNgModulePath: string, appNgModuleClassName: string) {
90118
if (!fileContent.match(/\bbootstrapModule\b/)) {
91119
throw new Error(`Could not find bootstrapModule in ${filePath}`);
@@ -103,7 +131,6 @@ export function replaceBootstrap(filePath: string, fileContent: string, appNgMod
103131

104132
let modifiedFileContent = fileContent;
105133
modifiedFileContent = replaceNgModuleClassName(filePath, modifiedFileContent, appNgModuleClassName);
106-
107134
modifiedFileContent = replacePlatformBrowser(filePath, modifiedFileContent);
108135
modifiedFileContent = replaceBootstrapModuleFactory(filePath, modifiedFileContent);
109136

@@ -112,5 +139,8 @@ export function replaceBootstrap(filePath: string, fileContent: string, appNgMod
112139
modifiedFileContent = replaceImportModuleSpecifier(filePath, modifiedFileContent, '@angular/platform-browser-dynamic', '@angular/platform-browser');
113140
modifiedFileContent = replaceImportModuleSpecifier(filePath, modifiedFileContent, originalImport, ngFactryImport);
114141

142+
// check if prod mode is imported and enabled
143+
modifiedFileContent = importAndEnableProdMode(filePath, modifiedFileContent);
144+
115145
return modifiedFileContent;
116146
}

src/util/typescript-utils.ts

+17-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import {
2+
CallExpression,
23
createSourceFile,
4+
Identifier,
35
ImportClause,
46
ImportDeclaration,
57
ImportSpecifier,
@@ -58,12 +60,17 @@ export function appendAfter(source: string, node: Node, toAppend: string): strin
5860
return stringSplice(source, node.getEnd(), 0, toAppend);
5961
}
6062

61-
export function insertNamedImport(filePath: string, fileContent: string, namedImport: string, fromPath: string) {
63+
export function appendBefore(filePath: string, fileContent: string, node: Node, toAppend: string): string {
64+
const sourceFile = getTypescriptSourceFile(filePath, fileContent, ScriptTarget.Latest, false);
65+
return stringSplice(fileContent, node.getStart(sourceFile), 0, toAppend);
66+
}
67+
68+
export function insertNamedImportIfNeeded(filePath: string, fileContent: string, namedImport: string, fromModule: string) {
6269
const sourceFile = getTypescriptSourceFile(filePath, fileContent, ScriptTarget.Latest, false);
6370
const allImports = findNodes(sourceFile, sourceFile, SyntaxKind.ImportDeclaration);
6471
const maybeImports = allImports.filter((node: ImportDeclaration) => {
6572
return node.moduleSpecifier.kind === SyntaxKind.StringLiteral
66-
&& (node.moduleSpecifier as StringLiteral).text === fromPath;
73+
&& (node.moduleSpecifier as StringLiteral).text === fromModule;
6774
}).filter((node: ImportDeclaration) => {
6875
// Remove import statements that are either `import 'XYZ'` or `import * as X from 'XYZ'`.
6976
const clause = node.importClause as ImportClause;
@@ -93,7 +100,7 @@ export function insertNamedImport(filePath: string, fileContent: string, namedIm
93100
} else {
94101
// Find the last import and insert after.
95102
fileContent = appendAfter(fileContent, allImports[allImports.length - 1],
96-
`import {${namedImport}} from '${fromPath}';`);
103+
`\nimport { ${namedImport} } from '${fromModule}';`);
97104
}
98105

99106
return fileContent;
@@ -131,3 +138,10 @@ export function replaceImportModuleSpecifier(filePath: string, fileContent: stri
131138
});
132139
return modifiedContent;
133140
}
141+
142+
export function checkIfFunctionIsCalled(filePath: string, fileContent: string, functionName: string) {
143+
const sourceFile = getTypescriptSourceFile(filePath, fileContent, ScriptTarget.Latest, false);
144+
const allCalls = findNodes(sourceFile, sourceFile, SyntaxKind.CallExpression, true) as CallExpression[];
145+
const functionCallList = allCalls.filter(call => call.expression && call.expression.kind === SyntaxKind.Identifier && (call.expression as Identifier).text === functionName);
146+
return functionCallList.length > 0;
147+
}

0 commit comments

Comments
 (0)