Skip to content

Commit 71fb830

Browse files
Terser syntax for exporting identifiers (#263)
* Terser syntax for exporting identifiers * Minify Import Statements (#265) * Import minification * Remove unneccessary casting storage * Increase test coverage for new import minification
1 parent 09254e4 commit 71fb830

17 files changed

+90
-23
lines changed

src/transformers/exports.ts

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -230,15 +230,18 @@ export default class ExportTransform extends Transform implements TransformInter
230230
}
231231
break;
232232
case ExportClosureMapping.NAMED_CONSTANT:
233-
const exportFromCurrentSource = exportDetails.source === null;
234-
const inlineExport =
233+
const exportFromCurrentSource: boolean = exportDetails.source === null;
234+
const inlineExport: boolean =
235235
exportFromCurrentSource && currentSourceExportCount === 1;
236+
let exportCollected: boolean = false;
236237
if (exportFromCurrentSource) {
237238
const { object: leftObject } = ancestor.expression.left;
238239
if (leftObject.range) {
239-
const { right } = ancestor.expression;
240+
const { left, right } = ancestor.expression;
240241
switch (right.type) {
241242
case 'FunctionExpression':
243+
// Function Expressions can be inlined instead of preserved as variable references.
244+
// window['foo'] = function(){}; => export function foo(){} / function foo(){}
242245
if (right.params.length > 0) {
243246
// FunctionExpression has parameters.
244247
source.overwrite(
@@ -258,6 +261,28 @@ export default class ExportTransform extends Transform implements TransformInter
258261
);
259262
}
260263
break;
264+
case 'Identifier':
265+
if (left.property.type === 'Identifier') {
266+
// Identifiers are present when a complex object (class) has been saved as an export.
267+
// In this case we currently opt out of inline exporting, since the identifier
268+
// is a mangled name for the export.
269+
exportDetails.local = right.name;
270+
exportDetails.closureName = left.property.name;
271+
272+
source.remove(
273+
(ancestor.expression.left.range as Range)[0],
274+
(ancestor.expression.right.range as Range)[1] + 1,
275+
);
276+
277+
// Since we're manually mapping the name back from the changes done by Closure
278+
// Ensure the export isn't stored for insertion here and later on.
279+
collectedExportsToAppend = ExportTransform.storeExportToAppend(
280+
collectedExportsToAppend,
281+
exportDetails,
282+
);
283+
exportCollected = true;
284+
}
285+
break;
261286
default:
262287
const statement = inlineExport ? 'export var ' : 'var ';
263288
source.overwrite(
@@ -282,7 +307,7 @@ export default class ExportTransform extends Transform implements TransformInter
282307
);
283308
}
284309

285-
if (!inlineExport) {
310+
if (!inlineExport && !exportCollected) {
286311
collectedExportsToAppend = ExportTransform.storeExportToAppend(
287312
collectedExportsToAppend,
288313
exportDetails,

src/transformers/imports.ts

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,17 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { Transform, Range } from '../types';
17+
import {
18+
Transform,
19+
Range,
20+
IMPORT_SPECIFIER,
21+
IMPORT_NAMESPACE_SPECIFIER,
22+
IMPORT_DEFAULT_SPECIFIER,
23+
} from '../types';
1824
import { literalName, importLocalNames } from './parsing-utilities';
1925
import { TransformSourceDescription } from 'rollup';
2026
import MagicString from 'magic-string';
21-
import { ImportDeclaration, Identifier } from 'estree';
27+
import { ImportDeclaration, Identifier, ImportSpecifier } from 'estree';
2228
import { parse, walk } from '../acorn';
2329

2430
const DYNAMIC_IMPORT_KEYWORD = 'import';
@@ -85,7 +91,29 @@ window['${DYNAMIC_IMPORT_REPLACEMENT}'] = ${DYNAMIC_IMPORT_REPLACEMENT};`;
8591
async ImportDeclaration(node: ImportDeclaration) {
8692
const name = literalName(self.context, node.source);
8793
const range: Range = node.range as Range;
88-
self.importedExternalsSyntax[name] = code.slice(...range);
94+
95+
let defaultSpecifier: string | null = null;
96+
const specificSpecifiers: Array<string> = [];
97+
for (const specifier of node.specifiers) {
98+
switch (specifier.type) {
99+
case IMPORT_SPECIFIER:
100+
case IMPORT_NAMESPACE_SPECIFIER:
101+
const { name: local } = (specifier as ImportSpecifier).local;
102+
const { name: imported } = (specifier as ImportSpecifier).imported;
103+
specificSpecifiers.push(local === imported ? local : `${imported} as ${local}`);
104+
break;
105+
case IMPORT_DEFAULT_SPECIFIER:
106+
defaultSpecifier = specifier.local.name;
107+
break;
108+
}
109+
}
110+
self.importedExternalsSyntax[name] = `import ${
111+
defaultSpecifier !== null
112+
? `${defaultSpecifier}${specificSpecifiers.length > 0 ? ',' : ''}`
113+
: ''
114+
}${
115+
specificSpecifiers.length > 0 ? `{${specificSpecifiers.join(',')}}` : ''
116+
} from '${name}';`;
89117
source.remove(...range);
90118

91119
self.importedExternalsLocalNames = self.importedExternalsLocalNames.concat(
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
function bar(){console.log(1)};function baz(a){console.log(a)};var foo=1;export{bar,baz,foo};
1+
class b{constructor(a){this.a=a}console(){console.log(this.a)}}function bar(){console.log(1)};function baz(a){console.log(a)};var foo=1;export{b as ExportedClass,bar,baz,foo};
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
function bar(){console.log(1)};function baz(a){console.log(a)};var foo=1;export{bar,baz,foo};
1+
class b{constructor(a){this.name_=a}console(){console.log(this.name_)}}function bar(){console.log(1)};function baz(a){console.log(a)};var foo=1;export{b as ExportedClass,bar,baz,foo};
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
function bar(){console.log(1)};function baz(a){console.log(a)};var foo=1;export{bar,baz,foo};
1+
function b(a){this.name_=a}b.prototype.console=function(){console.log(this.name_)};function bar(){console.log(1)};function baz(a){console.log(a)};var foo=1;export{b as ExportedClass,bar,baz,foo};

test/export-named/fixtures/multiple.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,16 @@ const bar = function() {
55
const baz = function(name) {
66
console.log(name);
77
}
8-
export{foo, bar, baz};
8+
class ExportedClass {
9+
constructor(name) {
10+
/**
11+
* @private {string}
12+
*/
13+
this.name_ = name;
14+
}
15+
16+
console() {
17+
console.log(this.name_);
18+
}
19+
}
20+
export{foo, bar, baz, ExportedClass};
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
class a{constructor(b){this.a=b}console(){console.log(this.a)}}export var Exported=a;
1+
class a{constructor(b){this.a=b}console(){console.log(this.a)}}export{a as Exported};
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
class a{constructor(b){this.name_=b}console(){console.log(this.name_)}}export var Exported=a;
1+
class a{constructor(b){this.name_=b}console(){console.log(this.name_)}}export{a as Exported};
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
function a(b){this.name_=b}a.prototype.console=function(){console.log(this.name_)};export var Exported=a;
1+
function a(b){this.name_=b}a.prototype.console=function(){console.log(this.name_)};export{a as Exported};

test/generator.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ async function compile(category, name, codeSplit, closureFlags, optionKey, forma
5454
const bundle = await rollup.rollup({
5555
input: fixtureLocation(category, name, format, optionKey, false),
5656
plugins: [compiler(closureFlags[optionKey])],
57-
external: ['lodash', './external.js', './external-default.js'],
57+
external: ['lodash', 'lodash2', 'lodash3', './external.js', './external-default.js'],
5858
experimentalCodeSplitting: codeSplit,
5959
onwarn: _ => null,
6060
});

0 commit comments

Comments
 (0)