Skip to content

Commit 64f6962

Browse files
committed
deduplicate module imports
Summary: In the module post-processor, if the same module is required multiple times, rewrite it to reuse the same import. Fixes #118. Reviewers: mprobst Reviewed By: mprobst Subscribers: typescript-eng Differential Revision: https://reviews.angular.io/D46
1 parent 5ba04df commit 64f6962

File tree

2 files changed

+31
-6
lines changed

2 files changed

+31
-6
lines changed

src/sickle.ts

+21-6
Original file line numberDiff line numberDiff line change
@@ -908,15 +908,24 @@ export function annotate(program: ts.Program, file: ts.SourceFile, options: Opti
908908
*/
909909
class PostProcessor extends Rewriter {
910910
/**
911-
* defaultImportSymbols collects the names of imported goog.modules. That is, if the code has
912-
* var foo = goog.require('bar');
913-
* which comes from the TS input:
911+
* defaultImportSymbols collects the names of imported goog.modules.
912+
* If the original TS input is:
914913
* import foo from 'goog:bar';
915-
* Then defaultImportSymbols['foo'] is true.
916-
* This is used to rewrite "foo.default" into just "foo".
914+
* then TS produces:
915+
* var foo = require('goog:bar');
916+
* and this class rewrites it to:
917+
* var foo = require('goog.bar');
918+
* After this step, defaultImportSymbols['foo'] is true.
919+
* (This is used to rewrite 'foo.default' into just 'foo'.)
917920
*/
918921
defaultImportSymbols: {[varName: string]: boolean} = {};
919922

923+
/**
924+
* moduleVariables maps from module names to the variables they're assigned to.
925+
* Continuing the above example, moduleVariables['goog.bar'] = 'foo'.
926+
*/
927+
moduleVariables: {[moduleName: string]: string} = {};
928+
920929
/** strippedStrict is true once we've stripped a "use strict"; from the input. */
921930
strippedStrict: boolean = false;
922931

@@ -1053,7 +1062,12 @@ class PostProcessor extends Rewriter {
10531062

10541063
let modName = this.pathToModuleName(this.file.fileName, require);
10551064
this.writeRange(node.getFullStart(), node.getStart());
1056-
this.emit(`var ${varName} = goog.require('${modName}');`);
1065+
if (this.moduleVariables.hasOwnProperty(modName)) {
1066+
this.emit(`var ${varName} = ${this.moduleVariables[modName]};`);
1067+
} else {
1068+
this.emit(`var ${varName} = goog.require('${modName}');`);
1069+
this.moduleVariables[modName] = varName;
1070+
}
10571071
return true;
10581072
}
10591073

@@ -1074,6 +1088,7 @@ class PostProcessor extends Rewriter {
10741088
if (!this.defaultImportSymbols.hasOwnProperty(lhsIdent.text)) break;
10751089
// Emit the same expression, with spaces to replace the ".default" part
10761090
// so that source maps still line up.
1091+
this.writeRange(node.getFullStart(), node.getStart());
10771092
this.emit(`${lhsIdent.text} `);
10781093
return true;
10791094
default:

test/sickle_test.ts

+10
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,16 @@ var foo = bar;
235235
*/
236236
237237
var foo = bar;
238+
`);
239+
});
240+
241+
it('deduplicates module imports', () => {
242+
expectCommonJs('a/b.js', `var foo_1 = require('goog:foo');
243+
var foo_2 = require('goog:foo');
244+
foo_1.A, foo_2.B, foo_2.default, foo_3.default;
245+
`).to.equal(`goog.module('a$b');var foo_1 = goog.require('foo');
246+
var foo_2 = foo_1;
247+
foo_1.A, foo_2.B, foo_2 , foo_3.default;
238248
`);
239249
});
240250
});

0 commit comments

Comments
 (0)