From 8192262a14b832442e317d0207559436b7be6ce6 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Thu, 5 Mar 2020 18:25:19 +0100 Subject: [PATCH] Add more support for exported imports in tree shaking --- build/lib/treeshaking.js | 37 +++++++++++++++++++++++++++++++++++++ build/lib/treeshaking.ts | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/build/lib/treeshaking.js b/build/lib/treeshaking.js index e9ae2b3fbc1..bc739120444 100644 --- a/build/lib/treeshaking.js +++ b/build/lib/treeshaking.js @@ -254,6 +254,7 @@ function markNodes(languageService, options) { } const black_queue = []; const gray_queue = []; + const export_import_queue = []; const sourceFilesLoaded = {}; function enqueueTopLevelModuleStatements(sourceFile) { sourceFile.forEachChild((node) => { @@ -270,6 +271,11 @@ function markNodes(languageService, options) { setColor(node, 2 /* Black */); enqueueImport(node, node.moduleSpecifier.text); } + if (node.exportClause && ts.isNamedExports(node.exportClause)) { + for (const exportSpecifier of node.exportClause.elements) { + export_import_queue.push(exportSpecifier); + } + } return; } if (ts.isExpressionStatement(node) @@ -448,6 +454,22 @@ function markNodes(languageService, options) { }; node.forEachChild(loop); } + while (export_import_queue.length > 0) { + const node = export_import_queue.shift(); + if (nodeOrParentIsBlack(node)) { + continue; + } + const symbol = node.symbol; + if (!symbol) { + continue; + } + const aliased = checker.getAliasedSymbol(symbol); + if (aliased.declarations && aliased.declarations.length > 0) { + if (nodeOrParentIsBlack(aliased.declarations[0]) || nodeOrChildIsBlack(aliased.declarations[0])) { + setColor(node, 2 /* Black */); + } + } + } } function nodeIsInItsOwnDeclaration(nodeSourceFile, node, symbol) { for (let i = 0, len = symbol.declarations.length; i < len; i++) { @@ -539,6 +561,21 @@ function generateResult(languageService, shakeLevel) { } } } + if (ts.isExportDeclaration(node)) { + if (node.exportClause && node.moduleSpecifier && ts.isNamedExports(node.exportClause)) { + let survivingExports = []; + for (const exportSpecifier of node.exportClause.elements) { + if (getColor(exportSpecifier) === 2 /* Black */) { + survivingExports.push(exportSpecifier.getFullText(sourceFile)); + } + } + const leadingTriviaWidth = node.getLeadingTriviaWidth(); + const leadingTrivia = sourceFile.text.substr(node.pos, leadingTriviaWidth); + if (survivingExports.length > 0) { + return write(`${leadingTrivia}export {${survivingExports.join(',')} } from${node.moduleSpecifier.getFullText(sourceFile)};`); + } + } + } if (shakeLevel === 2 /* ClassMembers */ && (ts.isClassDeclaration(node) || ts.isInterfaceDeclaration(node)) && nodeOrChildIsBlack(node)) { let toWrite = node.getFullText(); for (let i = node.members.length - 1; i >= 0; i--) { diff --git a/build/lib/treeshaking.ts b/build/lib/treeshaking.ts index a5c19906414..c1551e8143d 100644 --- a/build/lib/treeshaking.ts +++ b/build/lib/treeshaking.ts @@ -336,6 +336,7 @@ function markNodes(languageService: ts.LanguageService, options: ITreeShakingOpt const black_queue: ts.Node[] = []; const gray_queue: ts.Node[] = []; + const export_import_queue: ts.Node[] = []; const sourceFilesLoaded: { [fileName: string]: boolean } = {}; function enqueueTopLevelModuleStatements(sourceFile: ts.SourceFile): void { @@ -356,6 +357,11 @@ function markNodes(languageService: ts.LanguageService, options: ITreeShakingOpt setColor(node, NodeColor.Black); enqueueImport(node, node.moduleSpecifier.text); } + if (node.exportClause && ts.isNamedExports(node.exportClause)) { + for (const exportSpecifier of node.exportClause.elements) { + export_import_queue.push(exportSpecifier); + } + } return; } @@ -566,6 +572,23 @@ function markNodes(languageService: ts.LanguageService, options: ITreeShakingOpt }; node.forEachChild(loop); } + + while (export_import_queue.length > 0) { + const node = export_import_queue.shift()!; + if (nodeOrParentIsBlack(node)) { + continue; + } + const symbol: ts.Symbol | undefined = (node).symbol; + if (!symbol) { + continue; + } + const aliased = checker.getAliasedSymbol(symbol); + if (aliased.declarations && aliased.declarations.length > 0) { + if (nodeOrParentIsBlack(aliased.declarations[0]) || nodeOrChildIsBlack(aliased.declarations[0])) { + setColor(node, NodeColor.Black); + } + } + } } function nodeIsInItsOwnDeclaration(nodeSourceFile: ts.SourceFile, node: ts.Node, symbol: ts.Symbol): boolean { @@ -667,6 +690,22 @@ function generateResult(languageService: ts.LanguageService, shakeLevel: ShakeLe } } + if (ts.isExportDeclaration(node)) { + if (node.exportClause && node.moduleSpecifier && ts.isNamedExports(node.exportClause)) { + let survivingExports: string[] = []; + for (const exportSpecifier of node.exportClause.elements) { + if (getColor(exportSpecifier) === NodeColor.Black) { + survivingExports.push(exportSpecifier.getFullText(sourceFile)); + } + } + const leadingTriviaWidth = node.getLeadingTriviaWidth(); + const leadingTrivia = sourceFile.text.substr(node.pos, leadingTriviaWidth); + if (survivingExports.length > 0) { + return write(`${leadingTrivia}export {${survivingExports.join(',')} } from${node.moduleSpecifier.getFullText(sourceFile)};`); + } + } + } + if (shakeLevel === ShakeLevel.ClassMembers && (ts.isClassDeclaration(node) || ts.isInterfaceDeclaration(node)) && nodeOrChildIsBlack(node)) { let toWrite = node.getFullText(); for (let i = node.members.length - 1; i >= 0; i--) { -- GitLab