Published 17 Jun, 2021 by Louis Pilfold
Gleam is a type safe and scalable language for the Erlang virtual machine, and as of today’s v0.16.0 release Gleam compiles to JavaScript as well!
Show me!
What’s the introduction of a new way to write front end web code without some cliché examples?
Here’s a collection of interactive widgets you’ve probably seen countless times before, along with their Gleam source code and the JavaScript it compiles into.
In the interest of brevity we skip error handling in these examples and use rather quick-and-dirty type definitions of the JavaScript functions they import. In real Gleam programs we would expect these JavaScript bindings to live within shared libraries, but these examples should be enough to give you a taste of what Gleam can do with JavaScript.
Display Gleam source
Display compiled JavaScript
Display Gleam source
Display compiled JavaScript
Display Gleam source
Display compiled JavaScript
Thank you to dog.ceo for their Dog API
Why JavaScript?
The Erlang virtual machine is second-to-none for long-running services that run on servers, but outside of this space it may not always be the best tool for the job. It is not supported on all platforms, and factors such as compiled application size, boot time, and ease of installation may be an issue.
JavaScript is one of the most widely used and widely supported languages in the world. It can be used for website front ends, desktop applications, command line applications, mobile phones app, on IoT devices, on cloud serverless platforms, and more.
While JavaScript lacks the multi-core and distribute computing capabilities of the Erlang virtual machine it does have robust concurrency features and respectable single threaded performance thanks to highly optimised runtimes such Google’s V8 engine, which is used in NodeJS and the Chrome web browser.
By compiling to JavaScript as well as Erlang Gleam can be used for a much wider range of problem spaces and domains, and be accessible to a wider range of people. A team writing a backend web API in Gleam can now choose to also write their website frontend in Gleam, sharing code between both platforms and enjoying the friendly and productive type-based programming style of Gleam throughout their application stack.
Personally I’m excited to run Gleam code using serverless function platforms, and to make fun little Processing style sketches that run in the browser.
How does it work?
Much like the Erlang compiler backend this new JavaScript backend outputs human readable and pretty printed source code. It is now included with the compiler and does not require any extra components to be installed to use it.
Rather than attempting to replicate a subset of Erlang’s actor model Gleam uses the standard promise based concurrency model when targeting JavaScript. While this may be disappointing for some, it means that there is no additional runtime code added. This keeps bundle size small and makes it so code written in Gleam can be called like normal from languages such as JavaScript and TypeScript.
What’s next?
Full language support
The JavaScript backend supports almost all of the Gleam language, but there’s a few features still to be implemented, most notably the bit string syntax. Support for the remaining features will be added in following releases.
Tooling
When compiling to Erlang we typically use Erlang’s rebar3 build tool or Elixir’s
mix build tool. With JavaScript we do not yet any build tool integration and
instead have to use the lower level gleam compile-package --target=javascript
command line API. This API could be called by an npm preprocess script, a
makefile, or by more sophisticated integrations with tools such as Parcel or
Webpack.
Currently a Gleam build tool is being worked on, one that will be suitable for use with Erlang and JavaScript, and handle the resolution and compilation of dependancies from the Hex package manager.
Concurrency exploration
In JavaScript code yield points have to be manually inserted using
Promise.prototype.then
, or with the await
keyword, while in languages like
Erlang and Go this is handled automatically by the compiler.
The pervasive Promise
type and the split between synchronous and asynchronous
functions in JavaScript can be more difficult to learn and use than languages
such as Erlang and Go that make no such distinction. While there are no firm
plans at present I would like to explore using the Gleam compiler’s static
analysis to automatically insert await
statements into the generated
JavaScript code.
If this proves to be successful and useful we could swap promise based Gleam code that looks like this:
pub fn main() -> Promise(Int) {
async_function()
|> promise.then(fn(x) {
let y = sync_function()
async_function()
|> promise.then(fn(z) {
promise.resolve(x + y + z)
})
})
}
For automatically yielding Gleam code that looks like this:
pub fn main() -> Int {
let x = async_function()
let y = sync_function()
let z = async_function()
x + y + z
}
Both of these examples would have the same runtime behaviour and performance characteristics.
This would also solve the problem of JavaScript’s promise type automatically
flattening Promise(Promise(value))
into Promise(value)
, which makes it not
possible to soundly type without adding a special case to Gleam’s type system.
How can I try it?
Instructions on how to install the latest version of Gleam can be found on the getting started page of the website.
Once installed this Gleam JavaScript template can be used for writing and running Gleam code on JavaScript.
For all the details of this release check out the changelog files:
Supporting Gleam
Gleam sponsorship is my primary source of income. If you would like to support me in making Gleam please consider sponsoring Gleam or asking your employer to sponsor Gleam. Every donation makes a difference, no matter how small, so thank you for your help.
Thank you
The JavaScript backend for the Gleam compiler was initially created by Peter Saxton, so a big thank you to him. I also want to thank Hayleigh Thompson, her knowledge of other functional languages that compile to JavaScript has been invaluable in getting to this first release.
Gleam is made possible by the support of all the people who have sponsored and contributed to the project. Thank you all!
- Adam Bowen
- Adam Brodzinski
- Adam Mokan
- Adi Iyengar
- alexander
- Ali Farhadi
- Andy Thompson
- Arian Daneshvar
- Arno Dirlam
- Arto Bendiken
- Ben Marx
- Ben Myles
- Bruno Michel
- Chew Choon Keat
- Chris Lloyd
- Chris Young
- Christian Meunier
- ChristianEspinoza
- clangley
- Cole Lawrence
- Colin
- Connor Lay (Clay)
- Cristine Guadelupe
- Dan Mueller
- Dave Lucia
- David Bernheisel
- David Lewis
- David McKay
- David Pedersen
- Dennis Dang
- Edgar Gomes
- Eric Meadows-Jönsson
- Erik Terpstra
- Florian Kraft
- Gitpod
- Guilherme de Maio
- Guilherme Pasqualino
- Herdy Handoko
- human154
- Ian González
- Ingmar Gagen
- inoas
- Ivar Vong
- James MacAulay
- jcc333
- Jechol Lee
- Jeff Kreeftmeijer
- Jeroen Engels
- jiangplus
- Joe Corkerton
- John Palgut
- JohnDoneth
- josh rotenberg
- José Valim
- João Veiga
- Jussi Norlund
- Kapp Technology
- Lars Lillo Ulvestad
- Lars Wikman
- Leandro Cesquini Pereira
- Marcel Lanz
- Marcin Puc
- Mario Vellandi
- Marius Kalvø
- Mark Markaryan
- Markus
- Matheus Consoli
- Matt A
- Matthew Cheely
- Memo
- Michael Chris Lopez
- Michael Jones
- Michał Kowieski
- Michele Riva
- Mike Lapping
- Mike Roach
- Milad
- Nick Reynolds
- Nicklas Sindlev Andersen
- nico piderman
- NineFX
- OldhamMade
- Ole Michaelis
- Oliver Evans
- Parker Selbert
- Patrick Ryan
- Pete Jodo
- Peter
- Praveen Perera
- qingliangcn
- Raphael Megzari
- Raúl Chouza
- Redmar Kerkhoff
- Reio
- René Klačan
- Robert Attard
- Robin Mattheussen
- sabiwara
- Sam Aaron
- Sascha Wolf [he/him]
- Saša Jurić
- Scott Wey
- Sean Jensen-Grey
- Sebastian Porto
- Shane Sveller
- Shunji Lin
- Simone Vittori
- SkunkWerks GmbH
- Terje Bakken
- Tim Buchwaldt
- Tomasz Kowal
- Tomochika Hara
- Topher Hunt
- Tristan Sloughter
- Tyler Wilcock
- Vladimir Kuznetsov
- Wilson Silva
- Wojtek Mach
- YourMother-really
- Yu Matsuzawa
Thanks for reading! Have fun! 💜