I’ve poked around with a couple of compile to JS languages in the past. Years ago it was Clojurescript. More recently I did a lot of interfacing professionally with Purescript at the generated JS level.

The biggest issue plaguing these languages is that the codegen is generally not optimized for size — something critical for UX related work.

bucklescript’s Generated JS

On that note, I’ve recently been tooling around with ReasonML and bucklescript at work. And the codegen is really really great. As a toy example, consider this depth first traversal of a binary tree.

This editable example lets you see the codegen in real time. By the way, jaredly has done some great work with this REPL ❤. For completeness though, it’s included below.

There’s not much here. Thanks to webpack and treeshaking, the biggest “penalty” incurred is that currying as a default has brought in one extra module, curry.js. The other exports in these files don’t use prototype assignment or this and are just shaken out. Almost a zero cost abstraction.

Object properties are not generally minified with Uglify (unless you want to dive into the mangle-props morass). bucklescript treats variants as just integer tags for decent sized space savings.

The Typescript version

I was surprised to find out that Typescript doesn’t support recursive type definitions.

type Tree<a> = null | a | [a, Tree, Tree];

This code won’t compile with a Type alias 'Tree' circularly references itself.

You could, of course, do this same toy example with classes, but Typescript classes use this when transpiled to ES5. At least as of writing, IE 11 support is still alive and kicking in that regard…

Purescript

As a counter-example to the bucklescript codegen, there’s Purescript. An important caveat, Purescript, like most(?) compile to JS languages, doesn’t support ES Module style treeshaking and leans on its own internal toolchain for bundling.

That said, it does support, as part of a post-processing step, purs-bundle dumping dead code. But only if it’s psc generated.

Long story short, If you’re trying to work purescript into an existing JS project, get ready for a lot larger bundles.

In the example below, notice the module system is CommonJS, which Clojurescript also only supports. There are a handful of Javascript Modules/es(6)? Modules/ESM issues in the Purescript tracker.

In my example, I imported <> (the lovely cons operator) which even with a qualified import, results in the entire Prelude being pulled in. Because of the module system, you’re basically incurring a penalty of a medium sized library in JS.

instanceof is used for pattern matching as opposed to bucklescript’s primitive checks. And currying, also taken care of by purs-bundle , means that currying is part of the JS output. this and IIFEs that make dead code removal with Uglify not possible.

Elm(?) presumably suffers from these same problems, but don’t quote me on that.

Wrapping Up

I think bucklescript’s fast and light codegen is an example other compile to JS languages should try to emulate. While the usage of Bucklescript has been more amenable to usage within existing JS applications, allowing your language to use and benefit from JS bundling upgrades.