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

Commit

Permalink
fix(AoT): dynamically enable prod mode for AoT builds
Browse files Browse the repository at this point in the history
dynamically enable prod mode for AoT builds
  • Loading branch information
danbucholtz committed Dec 12, 2016
1 parent 5d82829 commit 0594803
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 6 deletions.
1 change: 1 addition & 0 deletions src/aot/aot-compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ export class AotCompiler {
try {
modifiedFileContent = replaceBootstrap(mainFile.path, mainFile.content, AppNgModuleTokens[0], AppNgModuleTokens[1]);
} catch (ex) {
Logger.debug(`Failed to parse bootstrap: `, ex.message);
Logger.warn(`Failed to parse and update ${this.options.entryPoint} content for AoT compilation.
For now, the default fallback content will be used instead.
Please consider updating ${this.options.entryPoint} with the content from the following link:
Expand Down
3 changes: 2 additions & 1 deletion src/aot/optimization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { removeDecorators } from '../util/typescript-utils';
export function optimizeJavascript(filePath: string, fileContent: string) {
fileContent = removeDecorators(filePath, fileContent);
fileContent = purgeDecoratorStatements(filePath, fileContent, ['@angular']);
fileContent = purgeCtorStatements(filePath, fileContent, ['@angular']);
// TODO - needs more testing to fully understand
// fileContent = purgeCtorStatements(filePath, fileContent, ['@angular']);
fileContent = purgeKnownContent(filePath, fileContent, ['@angular']);

return fileContent;
Expand Down
34 changes: 32 additions & 2 deletions src/aot/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
ScriptTarget
} from 'typescript';

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

export function getFallbackMainContent() {
return `
Expand Down Expand Up @@ -86,6 +86,34 @@ function replaceBootstrapModuleFactory(filePath: string, fileContent: string) {
return modifiedContent;
}

function getPlatformBrowserFunctionNode(filePath: string, fileContent: string) {
let modifiedFileContent = fileContent;
const sourceFile = getTypescriptSourceFile(filePath, modifiedFileContent, ScriptTarget.Latest, false);
const allCalls = findNodes(sourceFile, sourceFile, SyntaxKind.CallExpression, true) as CallExpression[];
const callsToPlatformBrowser = allCalls.filter(call => call.expression && call.expression.kind === SyntaxKind.Identifier && (call.expression as Identifier).text === 'platformBrowser');
const toAppend = `enableProdMode();\n`;
if (callsToPlatformBrowser.length) {
modifiedFileContent = appendBefore(filePath, modifiedFileContent, callsToPlatformBrowser[0].expression, toAppend);
} else {
// just throw it at the bottom
modifiedFileContent + toAppend;

This comment has been minimized.

Copy link
@biesbjerg

biesbjerg Dec 12, 2016

Did you mean modifiedFileContent += toAppend?

This comment has been minimized.

Copy link
@danbucholtz

danbucholtz Dec 12, 2016

Author Contributor

@biesbjerg, yes. Wanna do a PR?

Thanks,
Dan

}
return modifiedFileContent;
}

function importAndEnableProdMode(filePath: string, fileContent: string) {
let modifiedFileContent = fileContent;
modifiedFileContent = insertNamedImportIfNeeded(filePath, modifiedFileContent, 'enableProdMode', '@angular/core');

const isCalled = checkIfFunctionIsCalled(filePath, modifiedFileContent, 'enableProdMode');
if (!isCalled) {
// go ahead and insert this
modifiedFileContent = getPlatformBrowserFunctionNode(filePath, modifiedFileContent);
}

return modifiedFileContent;
}

export function replaceBootstrap(filePath: string, fileContent: string, appNgModulePath: string, appNgModuleClassName: string) {
if (!fileContent.match(/\bbootstrapModule\b/)) {
throw new Error(`Could not find bootstrapModule in ${filePath}`);
Expand All @@ -103,7 +131,6 @@ export function replaceBootstrap(filePath: string, fileContent: string, appNgMod

let modifiedFileContent = fileContent;
modifiedFileContent = replaceNgModuleClassName(filePath, modifiedFileContent, appNgModuleClassName);

modifiedFileContent = replacePlatformBrowser(filePath, modifiedFileContent);
modifiedFileContent = replaceBootstrapModuleFactory(filePath, modifiedFileContent);

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

// check if prod mode is imported and enabled
modifiedFileContent = importAndEnableProdMode(filePath, modifiedFileContent);

return modifiedFileContent;
}
20 changes: 17 additions & 3 deletions src/util/typescript-utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import {
CallExpression,
createSourceFile,
Identifier,
ImportClause,
ImportDeclaration,
ImportSpecifier,
Expand Down Expand Up @@ -58,12 +60,17 @@ export function appendAfter(source: string, node: Node, toAppend: string): strin
return stringSplice(source, node.getEnd(), 0, toAppend);
}

export function insertNamedImport(filePath: string, fileContent: string, namedImport: string, fromPath: string) {
export function appendBefore(filePath: string, fileContent: string, node: Node, toAppend: string): string {
const sourceFile = getTypescriptSourceFile(filePath, fileContent, ScriptTarget.Latest, false);
return stringSplice(fileContent, node.getStart(sourceFile), 0, toAppend);
}

export function insertNamedImportIfNeeded(filePath: string, fileContent: string, namedImport: string, fromModule: string) {
const sourceFile = getTypescriptSourceFile(filePath, fileContent, ScriptTarget.Latest, false);
const allImports = findNodes(sourceFile, sourceFile, SyntaxKind.ImportDeclaration);
const maybeImports = allImports.filter((node: ImportDeclaration) => {
return node.moduleSpecifier.kind === SyntaxKind.StringLiteral
&& (node.moduleSpecifier as StringLiteral).text === fromPath;
&& (node.moduleSpecifier as StringLiteral).text === fromModule;
}).filter((node: ImportDeclaration) => {
// Remove import statements that are either `import 'XYZ'` or `import * as X from 'XYZ'`.
const clause = node.importClause as ImportClause;
Expand Down Expand Up @@ -93,7 +100,7 @@ export function insertNamedImport(filePath: string, fileContent: string, namedIm
} else {
// Find the last import and insert after.
fileContent = appendAfter(fileContent, allImports[allImports.length - 1],
`import {${namedImport}} from '${fromPath}';`);
`\nimport { ${namedImport} } from '${fromModule}';`);
}

return fileContent;
Expand Down Expand Up @@ -131,3 +138,10 @@ export function replaceImportModuleSpecifier(filePath: string, fileContent: stri
});
return modifiedContent;
}

export function checkIfFunctionIsCalled(filePath: string, fileContent: string, functionName: string) {
const sourceFile = getTypescriptSourceFile(filePath, fileContent, ScriptTarget.Latest, false);
const allCalls = findNodes(sourceFile, sourceFile, SyntaxKind.CallExpression, true) as CallExpression[];
const functionCallList = allCalls.filter(call => call.expression && call.expression.kind === SyntaxKind.Identifier && (call.expression as Identifier).text === functionName);
return functionCallList.length > 0;
}

0 comments on commit 0594803

Please sign in to comment.