From 1dedc5320e0ccf9d1b461c1b851f438891745e1c Mon Sep 17 00:00:00 2001 From: Dan Bucholtz Date: Wed, 22 Feb 2017 23:11:17 -0600 Subject: [PATCH] fix(optimizations): comment out code instead of purge it so source-maps don't error out in some edge comment out code instead of purge it so source-maps don't error out in some edge cases --- src/optimization/decorators.spec.ts | 7 +- src/optimization/decorators.ts | 10 ++- src/optimization/treeshake.spec.ts | 113 +++++++++++++++++++--------- src/optimization/treeshake.ts | 34 +++++---- 4 files changed, 110 insertions(+), 54 deletions(-) diff --git a/src/optimization/decorators.spec.ts b/src/optimization/decorators.spec.ts index b2597978..8fe030c8 100644 --- a/src/optimization/decorators.spec.ts +++ b/src/optimization/decorators.spec.ts @@ -16,7 +16,7 @@ describe('optimization', () => { process.env = originalEnv; }); - it('should purge the decorators', () => { + it('should comment out the decorator statement', () => { // arrange const decoratorStatement = ` IonicModule.decorators = [ @@ -247,7 +247,10 @@ some more content // assert expect(result).not.toEqual(knownContent); - expect(result.indexOf(decoratorStatement)).toEqual(-1); + const regex = decorators.getDecoratorRegex(); + const matches = regex.exec(result); + expect(matches).toBeTruthy(); + expect(result.indexOf(`/*${matches[0]}*/`)).toBeGreaterThan(0); expect(result.indexOf(additionalGeneratedContent)).toBeGreaterThan(-1); }); }); diff --git a/src/optimization/decorators.ts b/src/optimization/decorators.ts index 1473056d..0b640d2b 100644 --- a/src/optimization/decorators.ts +++ b/src/optimization/decorators.ts @@ -8,9 +8,15 @@ export function purgeDecorators(filePath: string, fileContent: string) { export function purgeIndexDecorator(filePath: string, fileContent: string) { if (process.env[Constants.ENV_VAR_IONIC_ANGULAR_ENTRY_POINT] === filePath) { Logger.debug(`Purging index file decorator for ${filePath}`); - return fileContent.replace(DECORATORS_REGEX, ''); + const DECORATORS_REGEX = getDecoratorRegex(); + const matches = DECORATORS_REGEX.exec(fileContent); + if (matches && matches.length) { + return fileContent.replace(matches[0], `/*${matches[0]}*/`); + } } return fileContent; } -const DECORATORS_REGEX = /IonicModule.decorators.=[\s\S\n]*?([\s\S\n]*?)];/igm; +export function getDecoratorRegex() { + return /IonicModule.decorators.=[\s\S\n]*?([\s\S\n]*?)];/igm; +} \ No newline at end of file diff --git a/src/optimization/treeshake.spec.ts b/src/optimization/treeshake.spec.ts index 5f658606..fe3953cc 100644 --- a/src/optimization/treeshake.spec.ts +++ b/src/optimization/treeshake.spec.ts @@ -1,6 +1,7 @@ -import { join } from 'path'; +import { join, relative } from 'path'; import * as treeshake from './treeshake'; import * as Constants from '../util/constants'; +import * as helpers from '../util/helpers'; let originalEnv: any = null; @@ -1207,15 +1208,26 @@ export const AppModuleNgFactory = new import0.NgModuleFactory(AppModuleInjector, const componentFactoryPath2 = `/Users/dan/Dev/myApp3/node_modules/ionic-angular/components/alert/alert-component.ngfactory.js`; // act - let updatedContent = treeshake.purgeComponentNgFactoryImportAndUsage(appModuleNgFactoryPath, knownContent, componentFactoryPath); - updatedContent = treeshake.purgeComponentNgFactoryImportAndUsage(appModuleNgFactoryPath, updatedContent, componentFactoryPath2); + const updatedContent = treeshake.purgeComponentNgFactoryImportAndUsage(appModuleNgFactoryPath, knownContent, componentFactoryPath); + const updatedContentAgain = treeshake.purgeComponentNgFactoryImportAndUsage(appModuleNgFactoryPath, updatedContent, componentFactoryPath2); // assert - expect(updatedContent).not.toEqual(knownContent); - expect(updatedContent.indexOf(knownImport)).toEqual(-1); - expect(updatedContent.indexOf(knownImport2)).toEqual(-1); - expect(updatedContent.indexOf(knownImportUsage)).toEqual(-1); - expect(updatedContent.indexOf(knownImportUsage2)).toEqual(-1); + expect(updatedContentAgain).not.toEqual(knownContent); + const knownImportOneRegex = treeshake.generateWildCardImportRegex('../../node_modules/ionic-angular/components/action-sheet/action-sheet-component.ngfactory'); + const knownImportTwoRegex = treeshake.generateWildCardImportRegex('../../node_modules/ionic-angular/components/alert/alert-component.ngfactory'); + const knownImportOneResults = knownImportOneRegex.exec(updatedContentAgain); + const knownImportTwoResults = knownImportTwoRegex.exec(updatedContentAgain); + const knownNamedImportOne = knownImportOneResults[1].trim(); + const knownNamedImportTwo = knownImportTwoResults[1].trim(); + expect(updatedContentAgain.indexOf(`/*${knownImportOneResults[0]}*/`)).toBeGreaterThanOrEqual(0); + expect(updatedContentAgain.indexOf(`/*${knownImportTwoResults[0]}*/`)).toBeGreaterThanOrEqual(0); + + const removeFromConstructorRegexOne = treeshake.generateRemoveComponentFromConstructorRegex(knownNamedImportOne); + const removeFromConstructorRegexTwo = treeshake.generateRemoveComponentFromConstructorRegex(knownNamedImportTwo); + const removeFromConstructorOneResults = removeFromConstructorRegexOne.exec(updatedContentAgain); + const removeFromConstructorTwoResults = removeFromConstructorRegexTwo.exec(updatedContentAgain); + expect(updatedContentAgain.indexOf(`/*${removeFromConstructorOneResults[0]}*/`)).toBeGreaterThanOrEqual(0); + expect(updatedContentAgain.indexOf(`/*${removeFromConstructorTwoResults[0]}*/`)).toBeGreaterThanOrEqual(0); }); }); @@ -1235,32 +1247,32 @@ export const AppModuleNgFactory = new import0.NgModuleFactory(AppModuleInjector, // arrange const ifStatementOne = ` - if ((token === import32.ActionSheetController)) { - return this._ActionSheetController_54; - } +if ((token === import32.ActionSheetController)) { + return this._ActionSheetController_54; +} `; const ifStatementTwo = ` - if ((token === import33.AlertController)) { - return this._AlertController_55; - } +if ((token === import33.AlertController)) { + return this._AlertController_55; +} `; const getterOne = ` - get _ActionSheetController_54() { - if ((this.__ActionSheetController_54 == null)) { - (this.__ActionSheetController_54 = new import32.ActionSheetController(this._App_19, this._Config_16)); - } - return this.__ActionSheetController_54; - } +get _ActionSheetController_54() { + if ((this.__ActionSheetController_54 == null)) { + (this.__ActionSheetController_54 = new import32.ActionSheetController(this._App_19, this._Config_16)); + } + return this.__ActionSheetController_54; +} `; const getterTwo = ` - get _AlertController_55() { - if ((this.__AlertController_55 == null)) { - (this.__AlertController_55 = new import33.AlertController(this._App_19, this._Config_16)); - } - return this.__AlertController_55; - } +get _AlertController_55() { + if ((this.__AlertController_55 == null)) { + (this.__AlertController_55 = new import33.AlertController(this._App_19, this._Config_16)); + } + return this.__AlertController_55; +} `; const knownContent = ` @@ -1916,22 +1928,47 @@ export const AppModuleNgFactory = new import0.NgModuleFactory(AppModuleInjector, //# sourceMappingURL=app.module.ngfactory.js.map `; + const nodeModulesPath = '/Users/dan/Dev/myApp3/node_modules'; + const appModuleNgFactoryPath = `/Users/dan/Dev/myApp3/src/app/app.module.ngfactory.js`; - const controllerPath = `/Users/dan/Dev/myApp3/node_modules/ionic-angular/components/action-sheet/action-sheet-controller.js`; - const controllerPath2 = `/Users/dan/Dev/myApp3/node_modules/ionic-angular/components/alert/alert-controller.js`; + const controllerPath = join(nodeModulesPath, 'ionic-angular', 'components', 'action-sheet', 'action-sheet-controller.js'); + const controllerPath2 = join(nodeModulesPath, 'ionic-angular', 'components', 'alert', 'alert-controller.js'); // act let updatedContent = treeshake.purgeProviderControllerImportAndUsage(appModuleNgFactoryPath, knownContent, controllerPath); - updatedContent = treeshake.purgeProviderControllerImportAndUsage(appModuleNgFactoryPath, knownContent, controllerPath2); + updatedContent = treeshake.purgeProviderControllerImportAndUsage(appModuleNgFactoryPath, updatedContent, controllerPath2); // assert expect(updatedContent).not.toEqual(knownContent); - /*expect(updatedContent.indexOf(ifStatementOne)).toEqual(-1); - expect(updatedContent.indexOf(ifStatementTwo)).toEqual(-1); - expect(updatedContent.indexOf(getterOne)).toEqual(-1); - expect(updatedContent.indexOf(getterTwo)).toEqual(-1); - */ + const relativeImportPathOne = helpers.changeExtension(relative(nodeModulesPath, controllerPath), ''); + const relativeImportPathTwo = helpers.changeExtension(relative(nodeModulesPath, controllerPath2), ''); + + const importRegexOne = treeshake.generateWildCardImportRegex(relativeImportPathOne); + const importRegexTwo = treeshake.generateWildCardImportRegex(relativeImportPathTwo); + const importResultOne = importRegexOne.exec(updatedContent); + const importResultTwo = importRegexTwo.exec(updatedContent); + expect(updatedContent.indexOf(`/*${importResultOne[0]}*/`)).toBeGreaterThanOrEqual(0); + expect(updatedContent.indexOf(`/*${importResultTwo[0]}*/`)).toBeGreaterThanOrEqual(0); + + const namedImportOne = importResultOne[1].trim(); + const namedImportTwo = importResultTwo[1].trim(); + + const purgeGetterRegExOne = treeshake.generateRemoveGetterFromImportRegex(namedImportOne); + const purgeGetterResultsOne = purgeGetterRegExOne.exec(updatedContent); + const purgeIfRegExOne = treeshake.generateRemoveIfStatementRegex(namedImportOne); + const purgeIfResultsOne = purgeIfRegExOne.exec(updatedContent); + + const purgeGetterRegExTwo = treeshake.generateRemoveGetterFromImportRegex(namedImportTwo); + + const purgeGetterResultsTwo = purgeGetterRegExTwo.exec(updatedContent); + const purgeIfRegExTwo = treeshake.generateRemoveIfStatementRegex(namedImportTwo); + const purgeIfResultsTwo = purgeIfRegExTwo.exec(updatedContent); + + expect(updatedContent.indexOf(`/*${purgeGetterResultsOne[0]}*/`)).toBeGreaterThanOrEqual(0); + expect(updatedContent.indexOf(`/*${purgeIfResultsOne[0]}*/`)).toBeGreaterThanOrEqual(0); + expect(updatedContent.indexOf(`/*${purgeGetterResultsTwo[0]}*/`)).toBeGreaterThanOrEqual(0); + expect(updatedContent.indexOf(`/*${purgeIfResultsTwo[0]}*/`)).toBeGreaterThanOrEqual(0); }); }); @@ -1999,8 +2036,12 @@ export const AppModuleNgFactory = new import0.NgModuleFactory(AppModuleInjector, // assert expect(updatedContent).not.toEqual(knownContent); - expect(updatedContent.indexOf(classOne)).toEqual(-1); - expect(updatedContent.indexOf(classTwo)).toEqual(-1); + const regexOne = treeshake.generateIonicModulePurgeProviderRegex(classOne); + const regexTwo = treeshake.generateIonicModulePurgeProviderRegex(classTwo); + const resultsOne = regexOne.exec(updatedContent); + const resultsTwo = regexTwo.exec(updatedContent); + expect(updatedContent.indexOf(`/*${resultsOne[0]}*/`)).toBeGreaterThanOrEqual(0); + expect(updatedContent.indexOf(`/*${resultsTwo[0]}*/`)).toBeGreaterThanOrEqual(0); }); }); }); diff --git a/src/optimization/treeshake.ts b/src/optimization/treeshake.ts index 43a33c6b..fded7363 100644 --- a/src/optimization/treeshake.ts +++ b/src/optimization/treeshake.ts @@ -171,14 +171,14 @@ export function purgeUnusedImportsAndExportsFromIndex(indexFilePath: string, ind // replace the import if it's found let results: RegExpExecArray = null; while ((results = importRegex.exec(indexFileContent)) && results.length) { - indexFileContent = indexFileContent.replace(importRegex, ''); + indexFileContent = indexFileContent.replace(importRegex, `/*${results[0]}*/`); } results = null; const exportRegex = generateExportRegex(importPath); Logger.debug(`[treeshake] purgeUnusedImportsFromIndex: Removing exports with path ${importPath}`); while ((results = exportRegex.exec(indexFileContent)) && results.length) { - indexFileContent = indexFileContent.replace(exportRegex, ''); + indexFileContent = indexFileContent.replace(exportRegex, `/*${results[0]}*/`); } } @@ -188,12 +188,12 @@ export function purgeUnusedImportsAndExportsFromIndex(indexFilePath: string, ind function generateImportRegex(relativeImportPath: string) { const cleansedString = escapeStringForRegex(relativeImportPath); - return new RegExp(`import.*?{(.+)}.*?from.*?'${cleansedString}';`); + return new RegExp(`^import.*?{(.+)}.*?from.*?['"\`]${cleansedString}['"\`];`, 'gm'); } function generateExportRegex(relativeExportPath: string) { const cleansedString = escapeStringForRegex(relativeExportPath); - return new RegExp(`export.*?{(.+)}.*?from.*?'${cleansedString}';`); + return new RegExp(`^export.*?{(.+)}.*?from.*?'${cleansedString}';`, 'gm'); } export function purgeComponentNgFactoryImportAndUsage(appModuleNgFactoryPath: string, appModuleNgFactoryContent: string, componentFactoryPath: string) { @@ -205,11 +205,14 @@ export function purgeComponentNgFactoryImportAndUsage(appModuleNgFactoryPath: st const importRegex = generateWildCardImportRegex(importPath); const results = importRegex.exec(appModuleNgFactoryContent); if (results && results.length >= 2) { - appModuleNgFactoryContent = appModuleNgFactoryContent.replace(importRegex, ''); + appModuleNgFactoryContent = appModuleNgFactoryContent.replace(importRegex, `/*${results[0]}*/`); const namedImport = results[1].trim(); Logger.debug(`[treeshake] purgeComponentNgFactoryImportAndUsage: Purging code using named import ${namedImport}`); const purgeFromConstructor = generateRemoveComponentFromConstructorRegex(namedImport); - appModuleNgFactoryContent = appModuleNgFactoryContent.replace(purgeFromConstructor, ''); + const purgeFromConstructorResults = purgeFromConstructor.exec(appModuleNgFactoryContent); + if (purgeFromConstructorResults && purgeFromConstructorResults.length) { + appModuleNgFactoryContent = appModuleNgFactoryContent.replace(purgeFromConstructor, `/*${purgeFromConstructorResults[0]}*/`); + } } Logger.debug(`[treeshake] purgeComponentNgFactoryImportAndUsage: Starting to purge component ngFactory import/export ... DONE`); return appModuleNgFactoryContent; @@ -236,7 +239,7 @@ export function purgeProviderControllerImportAndUsage(appModuleNgFactoryPath: st if (purgeGetterResults && purgeIfResults) { Logger.debug(`[treeshake] purgeProviderControllerImportAndUsage: Purging imports ${namedImport}`); - appModuleNgFactoryContent = appModuleNgFactoryContent.replace(importRegex, ''); + appModuleNgFactoryContent = appModuleNgFactoryContent.replace(importRegex, `/*${results[0]}*/`); Logger.debug(`[treeshake] purgeProviderControllerImportAndUsage: Purging getter logic using ${namedImport}`); const getterContentToReplace = purgeGetterResults[0]; @@ -257,29 +260,32 @@ export function purgeProviderControllerImportAndUsage(appModuleNgFactoryPath: st export function purgeProviderClassNameFromIonicModuleForRoot(indexFileContent: string, providerClassName: string) { Logger.debug(`[treeshake] purgeProviderClassNameFromIonicModuleForRoot: Purging reference in the ionicModule forRoot method ...`); const regex = generateIonicModulePurgeProviderRegex(providerClassName); - indexFileContent = indexFileContent.replace(regex, ''); + const results = regex.exec(indexFileContent); + if (results && results.length) { + indexFileContent = indexFileContent.replace(regex, `/*${results[0]}*/`); + } Logger.debug(`[treeshake] purgeProviderClassNameFromIonicModuleForRoot: Purging reference in the ionicModule forRoot method ... DONE`); return indexFileContent; } -function generateWildCardImportRegex(relativeImportPath: string) { +export function generateWildCardImportRegex(relativeImportPath: string) { const cleansedString = escapeStringForRegex(relativeImportPath); return new RegExp(`import.*?as(.*?)from '${cleansedString}';`); } -function generateRemoveComponentFromConstructorRegex(namedImport: string) { +export function generateRemoveComponentFromConstructorRegex(namedImport: string) { return new RegExp(`${namedImport}\..*?,`); } export function generateRemoveGetterFromImportRegex(namedImport: string) { - const regexString = `(get _(.*?)_(\\d*)\\(\\) {([\\s\\S][^}]*?)${namedImport}([\\s\\S]*?)}([\\s\\S]*?)})`; + const regexString = `(get _.*?_\\d*\\(\\) {[\\s\\S][^}]*?${namedImport}[\\s\\S]*?}[\\s\\S]*?})`; return new RegExp(regexString); } -function generateRemoveIfStatementRegex(namedImport: string) { +export function generateRemoveIfStatementRegex(namedImport: string) { return new RegExp(`if \\(\\(token === ${namedImport}.([\\S]*?)\\)\\) {([\\S\\s]*?)}`, `gm`); } -function generateIonicModulePurgeProviderRegex(className: string) { - return new RegExp(`(^([\\s]*)${className},\\n)`, `m`); +export function generateIonicModulePurgeProviderRegex(className: string) { + return new RegExp(`${className},`, `gm`); }