Changelog: swc v1.2.36

Bugfixes#

export * as ns (#1142)#

swc now handle export * as ns from 'foo'; by default, if you are targeting < es2020.

Also, spack and swc_bundler now supports it directly.

conditional expression in await (#1133)#

swc errornously removed parenthesis of conditional expression in await expressions.

scope of optional chaining (#1136)#

Previously, swc miscompiled the code below.

const PATCHES = new Map();
const ident = "foo";
const patch = PATCHES.get(ident)?.();

This was compiled as

var _obj = PATCHES.get(ident),
ref;
const PATCHES = new Map();
const ident = "foo";
const patch = (ref = _obj) === null || ref === void 0 ? void 0 : ref.call(_obj);

Which results in a runtime error. This is caused by sharing variable buffer. It's fixed by using two variable buffers.

computed keys in object literal (#1140)#

The hygiene pass of swc had a bug. The bug was that it does not visit key in { [key]: value }.

This is fixed, and code like below works properly.

const categories = [{ key: "apple" }, { key: "banana" }, { key: "strawberry" }];
const item = "some item";
const catNames = categories.reduce((a, item) => {
return { ...a, [item.key.toString()]: item };
}, {});

bundler: deglob imports correctly (#1139)#

import * as circular2 from "./circular2.ts";
export function f1(): void {
console.log("f1");
}
circular2.f2();

Previously, the code above was bundled as

export function f1() {
console.log("f1");
}
circular2.f2();
circular1.f1();

which is clearly wrong. It's now fixed.

bundler: aliased imports (#1138)#

This bug occurs if nested export is mixed with aliased import.

a.ts:

export const a = "a";

l.ts:

export { a } from "./a.ts";

entry.ts:

import { a as defaultA } from "./l.ts";
const o: { a?: string } = {};
const { a = defaultA } = o;
console.log(a);

This resulted in

const o = {};
const { a = defaultA } = o;
console.log(a);

which is wrong. It's now fixed and swc_bundler now supports quite complex imports.


Changelog: swc v1.2.35

Bugfixes#

This version includes lots of bugfixes.

optional chaining (#1130)#

Nested property access in optional chaining is now properly compiled.

The affected code looks like below. Notice that there's no ? before map.

let data;
const result = data
?.filter((item) => Math.random() > 0.5)
.map((item) => JSON.stringify(item));

computed typescript properties (#1122)#

This is a regression caused by v1.2.18. The issue is about computed class properties in typescript.

const identifier = "bar";
class Foo {
[identifier] = 5;
}
console.log(new Foo().bar);

The code above now works properly.

temp var in nullish coalescing (#1123)#

Previously,

interface SuperSubmission {
[key: string]: any;
}
const normalizedQuestionSet: any = {};
const submissions: SuperSubmission[] = (
normalizedQuestionSet.submissionIds ?? []
).map(
(id, index): SuperSubmission => {
const submission = normalizedQuestionSet.submissions?.[id];
const submissionAnswers = (submission.answers ?? []).map(
(answerId) => normalizedQuestionSet.answers?.[answerId]
);
console.log(id, index);
return {
type: "super-submission",
};
}
);
console.log(submissions);

was miscompiled as

"use strict";
const normalizedQuestionSet = {};
const submissions = ((_submissionIds = normalizedQuestionSet.submissionIds) !==
null && _submissionIds !== void 0
? _submissionIds
: []
).map((id, index) => {
var ref, ref1;
var _submissionIds;
const submission =
(ref = normalizedQuestionSet.submissions) === null || ref === void 0
? void 0
: ref[id];
var _answers;
const submissionAnswers = ((_answers = submission.answers) !== null &&
_answers !== void 0
? _answers
: []
).map((answerId) =>
(ref1 = normalizedQuestionSet.answers) === null || ref1 === void 0
? void 0
: ref1[answerId]
);
console.log(id, index);
return {
type: "super-submission",
};
});
console.log(submissions);

which is wrong because var _submissionIds; should be declared at tbe top level. This is fixed by visiting children nodes (like block statement) with a new empty variable buffer.

renaming of private class properties (#1117)#

At the time of implementing hygiene and resolver, which is the core of the swc, there was no support for private class properties. It resulted in this bug, where hygiene pass renaming private properties. This is fixed by not visiting private identifiers.

Affected code looks like below.

Two private identifiers with same name declared in different class, but in same file. This bug is found by @kitsonk while integrating swc_bundler into deno.

export class G {
#g!: number[];
constructor(shared: boolean) {
if (shared) {
this.#g = g;
} else {
this.#g = [];
}
}
}
export class H {
#g!: number[];
constructor(shared: boolean) {
if (shared) {
this.#g = g;
} else {
this.#g = [];
}
}
}

bundler: too many exports (#1119)#

export function a(...d: string[]): string {
return d.join(" ");
}

resulted in

const _i = (function () {
function a(...d) {
return d.join(" ");
}
return {
a,
d,
};
})();

which is clearly wrong. This is fixed by collecting exported identifiers carefully.

bundler: export * (#1116)#

Code like

export * from "./a.ts";

was handled inproperly by spack.

stack overflow of inliner (#1127)#

This is fixed by migrating by working with pointers instead of passing structs around.

bundler: import.meta support (#1115)#

As deno bundle, which works with tsc and in a progress of integrating the bundler of swc into it, supports import.meta, I added support for them.

Currently two meta properties are supported.

import.meta.main; // false for imported modules, and as-is for entries
import.meta.url; // The path of file. (Customizable for rust users)

bundler: namespaced imports (#1109)#

entry.ts:

import * as a from "./a.ts";
console.log(a);

a.ts:

export const a = "a";

is now bundled as

const a = (function () {
const a = "a";
return {
a,
};
})();
console.log(a);

bundler: namedspaced reexports (#1110)#

Namespaced export statements like

export * as c from "./c.ts";

is now properly handled.

bundler: shorthand properties (#1111)#

Bundler had a bug related to shorthand properties. But it's now fixed, and

entry.ts:

import { d } from "./d.ts";
console.log(d);

d.ts:

import { a } from "./a.ts";
export const d = { a }; // This was problematic

a.ts:

export const a = "a";

is compiled as

const a = "a";
const d = {
a: "a",
};
console.log(d);

bundler: top level await (#1112)#

As deno supports top level await, I added support for it to the bundler.

ChangeLog: swc v1.2.31

Domain change#

The swc project now uses swc.rs, instead of swc-project.github.io. Thank you contributors!

Bugfixes#

(spack) export * in entry (1083)#

Previously, export * from './a' only worked in non-entry files. It's a common pattern to export everything from main module, so I think it's an important improvement.

let with for in/of (#1086)#

Previously, swc miscompiled the code shown below.

const b = [];
{
let a;
for (a in b) {
console.log(a);
}
}

The bug is realted to left hand side in the for-in loop.

File names in the source map is preserved (#1091)#

This is about feeding source code into swc after processing using other tools with source map support.

@lujjjh kindly found the cause and proposed solution.

(spack) Fixed imports (#1076)#

The spack had a bug related to packages without main field in package.json.

optional chaining (#1092)#

Starting with the version, swc can compile

a?.b.c();

into the correct output, namely

a === null || a === void 0 ? void 0 : a.b.c();

logical operators and function calls (#1093)#

Previously, swc erroneously removed the parenthesis which wraps fnA || fnB. This is now fixed.

const fnA = () => {
console.log("Output from function A");
};
const fnB = () => {
console.log("Output from function B");
};
const x = (fnA || fnB)();

regenerator scoping issue (#1036)#

I had a hard time debugging this, because all pass work correctly. It was pass ordering issue, and I fixed pass ordering. The bug affects user who used an array pattern ([a,,c]) or an object pattern ({ a: foo }) within async function.

Example of the affected code is show below.

const x = async function () {
console.log(
await Promise.all(
[[1], [2], [3]].map(async ([a]) => Promise.resolve().then(() => a * 2))
)
);
};

ChangeLog: swc v1.2.30

Documentations#

.d.ts files and the documentation of swc is now consistent.

See: configuring swc

Bugfixes#

spack (#1075, #1078)#

  • Panic while calculating the least common ancestor.

Previously, in some cases, lca calculation resulted in a panic because root entries do not have any ancestor.

  • Cyclic imports mixed with normal imports

This was tricky to fix because spack works in the parallel manner. You can't know which module is loaded first, and even the order of processing is not determined.

  • Cyclic imports in the root entry

Previously, swc could not handle cyclic imports in the root entry. But it's now fixed.

musl support#

swc finally supports musl. It was my long-cherished project, and finally fixed by @Brooooooklyn.

@swc/jest#

It's a much faster alternative for ts-jest without type checking.

Homepage: https://github.com/swc-project/jest

Usage:

jest.config.js:

module.exports = {
transform: {
"^.+\\.(t|j)sx?$": ["@swc/jest"],
},
};

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.