ChangeLog: swc v1.2.27

Bugfixes#

Import / export orders are preserved (#1069)#

Previously swc can break codes if you use es6 circular imports. As circular imports are not used widely, it was undetected.

The affected code looks like

import "reflect-metadata";
export * from "./http";
export { id } from "./interfaces";

Changelog: swc v1.2.25

Bugfixes#

codegen of block comment (#1062)#

Previously, swc injected a newline after block comments.

This is wrong behavior, as it can break some codes. Especially, the code below is broken.

return /*****/ function () {};

It was compiled as

return /*****/
function () {};

which is equal to

return /*****/;
function () {};

due to automatic semicolon insertion and it's broken as the return value is changed and function () {} is a function declaration, not a function expression.

meta properties (#1053)#

swc now compiles meta properties correctly.

class ArgumentValidationError extends Error {
constructor(public validationErrors: ValidationError[]) {
super("Argument Validation Error");
Object.setPrototypeOf(this, new.target.prototype);
}
}

common js: order of exports (#1057)#

Previously, swc does not follow the order declared in the soruce file while emitting imports and exports. As a result, cyclic imports were broken. This is now fixed, and

export * from "./http";
export { Scope } from "./interfaces";

is compiled as

"use strict";
Object.defineProperty(exports, "__esModule", {
value: true,
});
var _interfaces = require("./interfaces");
var _http = require("./http");
Object.defineProperty(exports, "Scope", {
enumerable: true,
get: function () {
return _interfaces.Scope;
},
});
Object.keys(_http).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
Object.defineProperty(exports, key, {
enumerable: true,
get: function () {
return _http[key];
},
});
});

instead of

"use strict";
Object.defineProperty(exports, "__esModule", {
value: true,
});
Object.defineProperty(exports, "Scope", {
enumerable: true,
get: function () {
return _interfaces.Abstract;
},
});
var _interfaces = require("./interfaces");
var _http = require("./http");
Object.keys(_http).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
Object.defineProperty(exports, key, {
enumerable: true,
get: function () {
return _http[key];
},
});
});

calling conditional expressions (#1051)#

This affects code like

(a) => (set) => (elemE(a, set) ? removeE : insertE)(a)(set);

Hotfix: swc v1.2.26

Hotfix#

Due to a bug of the build script, unpacked size was too big. New version is published to reduce package size.

Changelog: swc v1.2.23

New features#

jsx pragma (#1015)#

swc finally suports jsx pragma, which is required to use some libraries like emotion.sh.

// this comment tells babel to convert jsx to calls to a function called jsx instead of React.createElement
/** @jsx jsx */
import { css, jsx } from "@emotion/core";
const color = "white";
render(
<div
css={css`
padding: 32px;
background-color: hotpink;
font-size: 24px;
border-radius: 4px;
&:hover {
color: ${color};
}
`}
>
Hover to change color.
</div>
);

BingInt literal type (#1020)#

I didn't know that it is valid syntax, but the code below is validl, and swc now supports it.

const a: 1000n = 1000n;

Dynamic imports in non-es6 modules (#1028)#

Dynamic imports are not widely supported, so it should be transcompiled.

describe("foo", () => {
it("should import", async () => {
expect.assertions(1);
const { FOO } = await import("./foo");
expect(FOO).toBe(true);
});
});

is now compiled as

describe("foo", () => {
it("should import", async () => {
expect.assertions(1);
const { FOO } = await Promise.resolve().then(function () {
return require("./foo");
});
expect(FOO).toBe(true);
});
});

if the module config is common js.

Block scoping (#1029)#

this is now correctly handled in the loops.

class C {
m() {
for (let x = 0; x < 10; x++) console.log(this, (y) => y != x);
}
}

Also, you can now mutate the index variable while iterating.

e.g.

for (let i = 0; i < 5; i++) {
console.log(
i++,
[2].every((x) => x != i)
);
}

fixer: binary expression in callee of new (#1030)#

Previously swc miscompiled

return new (P || (P = Promise))(function (resolve, reject) {
// ....
});

into

return (
new P() ||
(P = Promise)(function (resolve, reject) {
// ....
})
);

which is wrong. Now it's fixed and swc emits correct output.

Support for large binary expressions (#1032)#

I fixed the code generator, parser, typescript stripper, fixer pass, resolver pass and hygiene pass to handle very large binary expressions.

As a result, swc can now compile very large binary expressions like those in seedlings

Correct this in optional chaining (#1035)#

Previously, swc miscompiled

a.focus?.();

into

"use strict";
var ref;
(ref = a.focus) === null || ref === void 0 ? void 0 : ref.call(ref);

which is wrong. It should be

"use strict";
var ref;
(ref = a.focus) === null || ref === void 0 ? void 0 : ref.call(a);

and swc now emits correct code.

spack (#1016, #1031, #1034)#

I did very hard work on it, and many edge cases are fixed. I don't think it's production ready yet, but it will be in a near future.

As a side note, #1016 is about ecmascript imports and #1031 and #0134 are about complex reexports and common js support, respectively.

Performance improvement#

swc becomes faster and it will be much faster with the next version. Its performance is similar to it of esbuild, even though there are so many low-hanging fruits.


Full change log

Changelog: swc v1.2.22

General improvements#

No install script (#1009)#

With napi-rs, swc becomes faster and install script is removed. npm i @swc/core is enough!

emitDecoratorMetadata checks for Reflect (#1011)#

Thanks to @Brooooooklyn, swc now works just like official tsc while transpiling decorators.

Performance improvements#

Parser (#1004)#

Previously, parser of the swc did many crazy things. For example, while parsing keywords, it allocated an interned string for them, and convert them to cheap enums. And now, the cheap enums are created directly.

Fixing various crazy things like this, parser becomes 10% faster.

TypeScript transpilation (#993)#

TypeScript pass got 5 times faster. Previously it was slow due to a design flaw, but is's now fixed.


Changelog: swc v1.2.21

General improvements#

Support optional named tuple elements (#982)#

TypeScript 4 allows

type Foo = [first: number, second?: string, ...rest: any[]];

and swc now supports it.

Better error messages (#980)#

Error messages were crpytic, mainly because I'm too lazy. Anyway, it's finally got improved.

error: Unexpected token Some(Semi)
--> $DIR/tests/typescript-errors/type-arguments/input.ts:1:9
|
1 | new A<T>;

becomes

error: Unexpected token `;`. Expected this, import, async, function, [ for array literal, { for object literal, @ for decorator, function, class, null, true, false, number, bigint, string, regexp, ` for template literal, (, or an identifier
--> $DIR/tests/typescript-errors/type-arguments/input.ts:1:9
|
1 | new A<T>;

Performance improvement#

Performance of swc is improved (#992)#

Previously, swc spend all time moving the memory with memmove. I've managed to remove some memmoves. Also, panic cases are handled properly.

For example, I changed code from

let prev = match self.cur.take() {
Some(t) => t,
None => unreachable!(
"Current token is `None`. Parser should not call bump()without knowing current \
token"
),
};

to

#[cold]
#[inline(never)]
fn invalid_state() -> ! {
unreachable!(
"Current token is `None`. Parser should not call bump() without knowing current \
token"
)
}
let prev = match self.cur.take() {
Some(t) => t,
None => invalid_state(),
};

This technique aids cpu cache issue.

sse2 is enabled#

It drastically reduces times used to memmove.

Performance of spack is improved (#992, #972)#

Some design flaws are fixed, it's fully parallelzed, and it does not transform files from node_modules.

Binary size is reduced (#973)#

Some useless allocations are removed, some memmoves are removed. Also, merging of reexports in spack now works in parallel manner.


Changelog: swc v1.2.20

Bugfixes#

spack respects swcrc (#964)#

Spack supports .swcrc properly. Just like webpack + babel environment, the configuration is determined per-file. You can even mix tsx, ts, js if you want.

spack handles common js modules properly (#969)#

Previously common js modules were improperly handled. After some very hard work, I managed to fix it and common js imports are transcompiled to compact code.

Spack generates clean code, just like the code below.

function __spack_require__(mod) {
var cache;
return function () {
if (cache) {
return cache;
}
var module = {
exports: {},
};
mod(module, module.exports);
cache = module.exports;
return cache;
};
}
// a-a-a.js
var load = __spack_require__.bind(void 0, function (module, exports) {
module.exports = {
default: "a-a-a",
};
});
// a-b.js
var load1 = __spack_require__.bind(void 0, function (module, exports) {
console.log("a-b");
exports.default = "ab";
});
// a-a.js
var load2 = __spack_require__.bind(void 0, function (module, exports) {
module.exports = load();
});
// b.js
var load3 = __spack_require__.bind(void 0, function (module, exports) {
console.log("b");
});
// c.js
var load4 = __spack_require__.bind(void 0, function (module, exports) {
console.log("c");
});
// a.js
var load5 = __spack_require__.bind(void 0, function (module, exports) {
var aa = load2();
var bb = load1();
load3();
module.exports = {
aa: aa,
bb: bb,
};
});
// entry.js
load5();
var b = load3();
load4();
console.log(b);

Spack is designed to emit bundle as smallest as possible when minified.

You can now use spack to bundle react projects. See an integration test for react in the swc main repository.

lodash-es is supported (#963)#

lodash-es accesses exports even if it's an es module. In order to handle name conflict, swc prevously rename exports to something different.

import root from "./_root.js";
import stubFalse from "./stubFalse.js";
var freeExports =
typeof exports == "object" && exports && !exports.nodeType && exports;
var freeModule =
freeExports && typeof module == "object" && module && !module.nodeType && \;
module;
var moduleExports = freeModule && freeModule.exports === freeExports;
var Buffer = moduleExports ? root.Buffer : undefined;
var nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined;
var isBuffer = nativeIsBuffer || stubFalse;
export default isBuffer;

It's now handled more sensitively to avoid breaking codes.

Parameter decorators (#961)#

Note: this applies to typescript decorators

Previously, decorators on a parameter which does not have initializer were broken.

class Base {
constructor() {
this.action = new Subject();
}
}
class Child extends Base {
@DefineAction() action: Observable<void>;
callApi() {
console.log(this.action);
}
}

It was undefined, which is wrong, and it's now an instance of Subject.

Changelog: swc v1.2.19

Bugfixes#

optional constructor property parameters (#959)#

Previously test? in the code below was miscompiled. It's now fixed and swc generates correct output.

export class Test {
constructor(readonly test?: string) {}
}

Some dce bugs (#959)#

While abstraction of the spack, I added much more test cases and fixed some tree-shaking bugs.

Improvements#

cyclic dependencies (#959)#

spack now supprots cyclic dependencies between es modules.

Changelog: swc v1.2.18

Bugfixes#

typescript class properties (#956)#

This is a bugfix for a new feature introduced in [swc][]@v1.2.16.

An example of affected code is

class A {
declare1;
declare2!: string;
}

Changelog: swc v1.2.16

Bugfixes#

typescript class properties (#951)#

This is a bugfix for a new feature introduced in [swc][]@v1.2.15.

An example of affected code is

class B {}
class A extends B {
foo = new Subject();
b = this.a;
constructor(readonly a) {
super();
this.foo.subscribe();
}
}