Skip to content

Commit

Permalink
Wrap classes with decorators or static properties in an IIFE, even fo…
Browse files Browse the repository at this point in the history
…r ES2015+ (microsoft#32011)

* Always wrap classes with decorators or static properties in an IIFE

Currently only script targets less than or equal to ES5 will wrap classes.  However, the wrapping is also crucial to file size optimizations for ES2015+ as well.  Without the IIFE wrapper, minification tools do not elide the class.  This is due to references to the class being present within the downlevelled decorator and static property code.
This change represents the full completion of issue microsoft#15857

* Accept new baselines
  • Loading branch information
clydin committed Feb 15, 2020
1 parent 1d6bb8b commit 7cc4a8d
Show file tree
Hide file tree
Showing 73 changed files with 1,286 additions and 967 deletions.
12 changes: 8 additions & 4 deletions src/compiler/transformers/ts.ts
Expand Up @@ -23,11 +23,10 @@ namespace ts {
IsNamedExternalExport = 1 << 4,
IsDefaultExternalExport = 1 << 5,
IsDerivedClass = 1 << 6,
UseImmediatelyInvokedFunctionExpression = 1 << 7,

HasAnyDecorators = HasConstructorDecorators | HasMemberDecorators,
NeedsName = HasStaticInitializedProperties | HasMemberDecorators,
MayNeedImmediatelyInvokedFunctionExpression = HasAnyDecorators | HasStaticInitializedProperties,
UseImmediatelyInvokedFunctionExpression = HasAnyDecorators | HasStaticInitializedProperties,
IsExported = IsExportOfNamespace | IsDefaultExternalExport | IsNamedExternalExport,
}

Expand Down Expand Up @@ -590,7 +589,6 @@ namespace ts {
if (isExportOfNamespace(node)) facts |= ClassFacts.IsExportOfNamespace;
else if (isDefaultExternalModuleExport(node)) facts |= ClassFacts.IsDefaultExternalExport;
else if (isNamedExternalModuleExport(node)) facts |= ClassFacts.IsNamedExternalExport;
if (languageVersion <= ScriptTarget.ES5 && (facts & ClassFacts.MayNeedImmediatelyInvokedFunctionExpression)) facts |= ClassFacts.UseImmediatelyInvokedFunctionExpression;
return facts;
}

Expand Down Expand Up @@ -661,6 +659,12 @@ namespace ts {
const iife = createImmediatelyInvokedArrowFunction(statements);
setEmitFlags(iife, EmitFlags.TypeScriptClassWrapper);

// Class comment is already added by the ES2015 transform when targeting ES5 or below.
// Only add if targetting ES2015+ to prevent duplicates
if (languageVersion > ScriptTarget.ES5) {
addSyntheticLeadingComment(iife, SyntaxKind.MultiLineCommentTrivia, "* @class ");
}

const varStatement = createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList([
Expand All @@ -669,7 +673,7 @@ namespace ts {
/*type*/ undefined,
iife
)
])
], languageVersion > ScriptTarget.ES5 ? NodeFlags.Let : undefined)
);

setOriginalNode(varStatement, node);
Expand Down
40 changes: 22 additions & 18 deletions tests/baselines/reference/awaitAndYieldInProperty.js
Expand Up @@ -19,27 +19,31 @@ async function* test(x: Promise<string>) {

//// [awaitAndYieldInProperty.js]
async function* test(x) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
class C {
constructor() {
this[_a] = await x;
this[_c] = yield 2;
}
}
_a = await x, _b = await x, _c = yield 1, _d = yield 3;
C[_b] = await x;
C[_d] = yield 4;
return _j = class {
var _a, _b, _c, _d, _e;
let C = /** @class */ (() => {
var _e, _f, _g, _h;
class C {
constructor() {
this[_e] = await x;
this[_g] = yield 2;
}
}
_e = await x, _f = await x, _g = yield 1, _h = yield 3;
C[_f] = await x;
C[_h] = yield 4;
return C;
})();
return _e = class {
constructor() {
this[_a] = await x;
this[_c] = yield 2;
}
},
_e = await x,
_f = await x,
_g = yield 1,
_h = yield 3,
_j[_f] = await x,
_j[_h] = yield 4,
_j;
_a = await x,
_b = await x,
_c = yield 1,
_d = yield 3,
_e[_b] = await x,
_e[_d] = yield 4,
_e;
}
Expand Up @@ -4,6 +4,9 @@ class C3 {
}

//// [classDeclarationCheckUsedBeforeDefinitionInItself.js]
class C3 {
}
C3.intance = new C3(); // ok
let C3 = /** @class */ (() => {
class C3 {
}
C3.intance = new C3(); // ok
return C3;
})();
21 changes: 12 additions & 9 deletions tests/baselines/reference/computedPropertyNames12_ES6.js
Expand Up @@ -17,16 +17,19 @@ class C {
}

//// [computedPropertyNames12_ES6.js]
var _a, _b, _c;
var s;
var n;
var a;
class C {
constructor() {
this[_a] = n;
this[_b] = 2;
this[`hello bye`] = 0;
let C = /** @class */ (() => {
var _a, _b, _c;
class C {
constructor() {
this[_a] = n;
this[_b] = 2;
this[`hello bye`] = 0;
}
}
}
_a = n, s + s, _b = s + n, +s, _c = `hello ${a} bye`;
C[_c] = 0;
_a = n, s + s, _b = s + n, +s, _c = `hello ${a} bye`;
C[_c] = 0;
return C;
})();
Expand Up @@ -11,13 +11,16 @@ class C {
}

//// [computedPropertyNamesWithStaticProperty.js]
class C {
get [C.staticProp]() {
return "hello";
let C = /** @class */ (() => {
class C {
get [C.staticProp]() {
return "hello";
}
set [C.staticProp](x) {
var y = x;
}
[C.staticProp]() { }
}
set [C.staticProp](x) {
var y = x;
}
[C.staticProp]() { }
}
C.staticProp = 10;
C.staticProp = 10;
return C;
})();
17 changes: 10 additions & 7 deletions tests/baselines/reference/decoratedClassExportsCommonJS1.js
Expand Up @@ -14,12 +14,15 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var Testing123_1;
Object.defineProperty(exports, "__esModule", { value: true });
let Testing123 = Testing123_1 = class Testing123 {
};
Testing123.prop1 = Testing123_1.prop0;
Testing123 = Testing123_1 = __decorate([
Something({ v: () => Testing123_1 })
], Testing123);
let Testing123 = /** @class */ (() => {
var Testing123_1;
let Testing123 = Testing123_1 = class Testing123 {
};
Testing123.prop1 = Testing123_1.prop0;
Testing123 = Testing123_1 = __decorate([
Something({ v: () => Testing123_1 })
], Testing123);
return Testing123;
})();
exports.Testing123 = Testing123;
15 changes: 9 additions & 6 deletions tests/baselines/reference/decoratedClassExportsCommonJS2.js
Expand Up @@ -12,11 +12,14 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var Testing123_1;
Object.defineProperty(exports, "__esModule", { value: true });
let Testing123 = Testing123_1 = class Testing123 {
};
Testing123 = Testing123_1 = __decorate([
Something({ v: () => Testing123_1 })
], Testing123);
let Testing123 = /** @class */ (() => {
var Testing123_1;
let Testing123 = Testing123_1 = class Testing123 {
};
Testing123 = Testing123_1 = __decorate([
Something({ v: () => Testing123_1 })
], Testing123);
return Testing123;
})();
exports.Testing123 = Testing123;
18 changes: 11 additions & 7 deletions tests/baselines/reference/decoratedClassExportsSystem1.js
Expand Up @@ -16,17 +16,21 @@ System.register([], function (exports_1, context_1) {
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var Testing123_1, Testing123;
var Testing123;
var __moduleName = context_1 && context_1.id;
return {
setters: [],
execute: function () {
Testing123 = Testing123_1 = class Testing123 {
};
Testing123.prop1 = Testing123_1.prop0;
Testing123 = Testing123_1 = __decorate([
Something({ v: () => Testing123_1 })
], Testing123);
Testing123 = /** @class */ (() => {
var Testing123_1;
let Testing123 = Testing123_1 = class Testing123 {
};
Testing123.prop1 = Testing123_1.prop0;
Testing123 = Testing123_1 = __decorate([
Something({ v: () => Testing123_1 })
], Testing123);
return Testing123;
})();
exports_1("Testing123", Testing123);
}
};
Expand Down
16 changes: 10 additions & 6 deletions tests/baselines/reference/decoratedClassExportsSystem2.js
Expand Up @@ -13,16 +13,20 @@ System.register([], function (exports_1, context_1) {
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var Testing123_1, Testing123;
var Testing123;
var __moduleName = context_1 && context_1.id;
return {
setters: [],
execute: function () {
Testing123 = Testing123_1 = class Testing123 {
};
Testing123 = Testing123_1 = __decorate([
Something({ v: () => Testing123_1 })
], Testing123);
Testing123 = /** @class */ (() => {
var Testing123_1;
let Testing123 = Testing123_1 = class Testing123 {
};
Testing123 = Testing123_1 = __decorate([
Something({ v: () => Testing123_1 })
], Testing123);
return Testing123;
})();
exports_1("Testing123", Testing123);
}
};
Expand Down
13 changes: 8 additions & 5 deletions tests/baselines/reference/decoratedClassFromExternalModule.js
Expand Up @@ -17,10 +17,13 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
function decorate(target) { }
let Decorated = class Decorated {
};
Decorated = __decorate([
decorate
], Decorated);
let Decorated = /** @class */ (() => {
let Decorated = class Decorated {
};
Decorated = __decorate([
decorate
], Decorated);
return Decorated;
})();
export default Decorated;
//// [undecorated.js]
26 changes: 16 additions & 10 deletions tests/baselines/reference/decoratedDefaultExportsGetExportedAmd.js
Expand Up @@ -24,11 +24,14 @@ define(["require", "exports"], function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var decorator;
let Foo = class Foo {
};
Foo = __decorate([
decorator
], Foo);
let Foo = /** @class */ (() => {
let Foo = class Foo {
};
Foo = __decorate([
decorator
], Foo);
return Foo;
})();
exports.default = Foo;
});
//// [b.js]
Expand All @@ -42,10 +45,13 @@ define(["require", "exports"], function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var decorator;
let default_1 = class {
};
default_1 = __decorate([
decorator
], default_1);
let default_1 = /** @class */ (() => {
let default_1 = class {
};
default_1 = __decorate([
decorator
], default_1);
return default_1;
})();
exports.default = default_1;
});
Expand Up @@ -23,11 +23,14 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
};
Object.defineProperty(exports, "__esModule", { value: true });
var decorator;
let Foo = class Foo {
};
Foo = __decorate([
decorator
], Foo);
let Foo = /** @class */ (() => {
let Foo = class Foo {
};
Foo = __decorate([
decorator
], Foo);
return Foo;
})();
exports.default = Foo;
//// [b.js]
"use strict";
Expand All @@ -39,9 +42,12 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
};
Object.defineProperty(exports, "__esModule", { value: true });
var decorator;
let default_1 = class {
};
default_1 = __decorate([
decorator
], default_1);
let default_1 = /** @class */ (() => {
let default_1 = class {
};
default_1 = __decorate([
decorator
], default_1);
return default_1;
})();
exports.default = default_1;
Expand Up @@ -26,11 +26,14 @@ System.register([], function (exports_1, context_1) {
return {
setters: [],
execute: function () {
Foo = class Foo {
};
Foo = __decorate([
decorator
], Foo);
Foo = /** @class */ (() => {
let Foo = class Foo {
};
Foo = __decorate([
decorator
], Foo);
return Foo;
})();
exports_1("default", Foo);
}
};
Expand All @@ -49,11 +52,14 @@ System.register([], function (exports_1, context_1) {
return {
setters: [],
execute: function () {
default_1 = class {
};
default_1 = __decorate([
decorator
], default_1);
default_1 = /** @class */ (() => {
let default_1 = class {
};
default_1 = __decorate([
decorator
], default_1);
return default_1;
})();
exports_1("default", default_1);
}
};
Expand Down

0 comments on commit 7cc4a8d

Please sign in to comment.