Skip to content

Commit

Permalink
Terser syntax for exporting identifiers (#263)
Browse files Browse the repository at this point in the history
* Terser syntax for exporting identifiers

* Minify Import Statements (#265)

* Import minification

* Remove unneccessary casting storage

* Increase test coverage for new import minification
  • Loading branch information
kristoferbaxter authored Dec 29, 2019
1 parent 09254e4 commit 71fb830
Show file tree
Hide file tree
Showing 17 changed files with 90 additions and 23 deletions.
33 changes: 29 additions & 4 deletions src/transformers/exports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,15 +230,18 @@ export default class ExportTransform extends Transform implements TransformInter
}
break;
case ExportClosureMapping.NAMED_CONSTANT:
const exportFromCurrentSource = exportDetails.source === null;
const inlineExport =
const exportFromCurrentSource: boolean = exportDetails.source === null;
const inlineExport: boolean =
exportFromCurrentSource && currentSourceExportCount === 1;
let exportCollected: boolean = false;
if (exportFromCurrentSource) {
const { object: leftObject } = ancestor.expression.left;
if (leftObject.range) {
const { right } = ancestor.expression;
const { left, right } = ancestor.expression;
switch (right.type) {
case 'FunctionExpression':
// Function Expressions can be inlined instead of preserved as variable references.
// window['foo'] = function(){}; => export function foo(){} / function foo(){}
if (right.params.length > 0) {
// FunctionExpression has parameters.
source.overwrite(
Expand All @@ -258,6 +261,28 @@ export default class ExportTransform extends Transform implements TransformInter
);
}
break;
case 'Identifier':
if (left.property.type === 'Identifier') {
// Identifiers are present when a complex object (class) has been saved as an export.
// In this case we currently opt out of inline exporting, since the identifier
// is a mangled name for the export.
exportDetails.local = right.name;
exportDetails.closureName = left.property.name;

source.remove(
(ancestor.expression.left.range as Range)[0],
(ancestor.expression.right.range as Range)[1] + 1,
);

// Since we're manually mapping the name back from the changes done by Closure
// Ensure the export isn't stored for insertion here and later on.
collectedExportsToAppend = ExportTransform.storeExportToAppend(
collectedExportsToAppend,
exportDetails,
);
exportCollected = true;
}
break;
default:
const statement = inlineExport ? 'export var ' : 'var ';
source.overwrite(
Expand All @@ -282,7 +307,7 @@ export default class ExportTransform extends Transform implements TransformInter
);
}

if (!inlineExport) {
if (!inlineExport && !exportCollected) {
collectedExportsToAppend = ExportTransform.storeExportToAppend(
collectedExportsToAppend,
exportDetails,
Expand Down
34 changes: 31 additions & 3 deletions src/transformers/imports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,17 @@
* limitations under the License.
*/

import { Transform, Range } from '../types';
import {
Transform,
Range,
IMPORT_SPECIFIER,
IMPORT_NAMESPACE_SPECIFIER,
IMPORT_DEFAULT_SPECIFIER,
} from '../types';
import { literalName, importLocalNames } from './parsing-utilities';
import { TransformSourceDescription } from 'rollup';
import MagicString from 'magic-string';
import { ImportDeclaration, Identifier } from 'estree';
import { ImportDeclaration, Identifier, ImportSpecifier } from 'estree';
import { parse, walk } from '../acorn';

const DYNAMIC_IMPORT_KEYWORD = 'import';
Expand Down Expand Up @@ -85,7 +91,29 @@ window['${DYNAMIC_IMPORT_REPLACEMENT}'] = ${DYNAMIC_IMPORT_REPLACEMENT};`;
async ImportDeclaration(node: ImportDeclaration) {
const name = literalName(self.context, node.source);
const range: Range = node.range as Range;
self.importedExternalsSyntax[name] = code.slice(...range);

let defaultSpecifier: string | null = null;
const specificSpecifiers: Array<string> = [];
for (const specifier of node.specifiers) {
switch (specifier.type) {
case IMPORT_SPECIFIER:
case IMPORT_NAMESPACE_SPECIFIER:
const { name: local } = (specifier as ImportSpecifier).local;
const { name: imported } = (specifier as ImportSpecifier).imported;
specificSpecifiers.push(local === imported ? local : `${imported} as ${local}`);
break;
case IMPORT_DEFAULT_SPECIFIER:
defaultSpecifier = specifier.local.name;
break;
}
}
self.importedExternalsSyntax[name] = `import ${
defaultSpecifier !== null
? `${defaultSpecifier}${specificSpecifiers.length > 0 ? ',' : ''}`
: ''
}${
specificSpecifiers.length > 0 ? `{${specificSpecifiers.join(',')}}` : ''
} from '${name}';`;
source.remove(...range);

self.importedExternalsLocalNames = self.importedExternalsLocalNames.concat(
Expand Down
2 changes: 1 addition & 1 deletion test/export-named/fixtures/multiple.esm.advanced.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
function bar(){console.log(1)};function baz(a){console.log(a)};var foo=1;export{bar,baz,foo};
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};
2 changes: 1 addition & 1 deletion test/export-named/fixtures/multiple.esm.default.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
function bar(){console.log(1)};function baz(a){console.log(a)};var foo=1;export{bar,baz,foo};
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};
2 changes: 1 addition & 1 deletion test/export-named/fixtures/multiple.esm.es5.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
function bar(){console.log(1)};function baz(a){console.log(a)};var foo=1;export{bar,baz,foo};
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};
14 changes: 13 additions & 1 deletion test/export-named/fixtures/multiple.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,16 @@ const bar = function() {
const baz = function(name) {
console.log(name);
}
export{foo, bar, baz};
class ExportedClass {
constructor(name) {
/**
* @private {string}
*/
this.name_ = name;
}

console() {
console.log(this.name_);
}
}
export{foo, bar, baz, ExportedClass};
2 changes: 1 addition & 1 deletion test/export-variables/fixtures/class.esm.advanced.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
class a{constructor(b){this.a=b}console(){console.log(this.a)}}export var Exported=a;
class a{constructor(b){this.a=b}console(){console.log(this.a)}}export{a as Exported};
2 changes: 1 addition & 1 deletion test/export-variables/fixtures/class.esm.default.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
class a{constructor(b){this.name_=b}console(){console.log(this.name_)}}export var Exported=a;
class a{constructor(b){this.name_=b}console(){console.log(this.name_)}}export{a as Exported};
2 changes: 1 addition & 1 deletion test/export-variables/fixtures/class.esm.es5.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
function a(b){this.name_=b}a.prototype.console=function(){console.log(this.name_)};export var Exported=a;
function a(b){this.name_=b}a.prototype.console=function(){console.log(this.name_)};export{a as Exported};
2 changes: 1 addition & 1 deletion test/generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ async function compile(category, name, codeSplit, closureFlags, optionKey, forma
const bundle = await rollup.rollup({
input: fixtureLocation(category, name, format, optionKey, false),
plugins: [compiler(closureFlags[optionKey])],
external: ['lodash', './external.js', './external-default.js'],
external: ['lodash', 'lodash2', 'lodash3', './external.js', './external-default.js'],
experimentalCodeSplitting: codeSplit,
onwarn: _ => null,
});
Expand Down
2 changes: 1 addition & 1 deletion test/import/fixtures/external.esm.advanced.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
import _ from 'lodash';console.log("lodash",_);
import j from 'lodash3';import {thing,thing2} from 'lodash2';import _,{foo,bar} from 'lodash';console.log("lodash",_,foo,bar,thing,thing2,j);
2 changes: 1 addition & 1 deletion test/import/fixtures/external.esm.default.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
import _ from 'lodash';console.log("lodash",_);
import j from 'lodash3';import {thing,thing2} from 'lodash2';import _,{foo,bar} from 'lodash';console.log("lodash",_,foo,bar,thing,thing2,j);
2 changes: 1 addition & 1 deletion test/import/fixtures/external.esm.es5.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
import _ from 'lodash';console.log("lodash",_);
import j from 'lodash3';import {thing,thing2} from 'lodash2';import _,{foo,bar} from 'lodash';console.log("lodash",_,foo,bar,thing,thing2,j);
6 changes: 4 additions & 2 deletions test/import/fixtures/external.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import _ from 'lodash';
import _, { foo, bar as baz } from 'lodash';
import {thing, thing2 as thing3} from 'lodash2';
import j from 'lodash3';

console.log('lodash', _);
console.log('lodash', _, foo, baz, thing, thing3, j);
2 changes: 1 addition & 1 deletion test/provided-externs/fixtures/class.esm.advanced.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
class a{constructor(b){this.a=b}console(){console.log(this.a)}}export var ExportThis=a;
class a{constructor(b){this.a=b}console(){console.log(this.a)}}export{a as ExportThis};
2 changes: 1 addition & 1 deletion test/provided-externs/fixtures/class.esm.default.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
class a{constructor(b){this.name_=b}console(){console.log(this.name_)}}export var ExportThis=a;
class a{constructor(b){this.name_=b}console(){console.log(this.name_)}}export{a as ExportThis};
2 changes: 1 addition & 1 deletion test/provided-externs/fixtures/class.esm.es5.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
function a(b){this.name_=b}a.prototype.console=function(){console.log(this.name_)};export var ExportThis=a;
function a(b){this.name_=b}a.prototype.console=function(){console.log(this.name_)};export{a as ExportThis};

0 comments on commit 71fb830

Please sign in to comment.