This post is part of a series of four, Gleam calling Erlang and v.v., A Rebar3 project using Gleam, this post, and Gleam in the browser.
In this post, we look at running Gleam with node, and deno. We also call JavaScript code from Gleam and vice versa.Compile Gleam to JavaScript
To let the gleam compiler output JavaScript, you need to call it with the argument--target=javascript
, e.g. when you build the project, or run the tests.
If you want to do this all the time, add a line target = "javascript"
to
the gleam.toml
configuration file.
You may notice that compiling to Erlang takes longer, that is because the Erlang compiler is called in addition to the Gleam compiler.
Using Deno
When the target is JavaScript, Gleam can choose between node and deno when running, either on the command line:gleam run --runtime=deno
or via the configuration file:
[javascript]
runtime = "deno"
Deno claims better security, and you'll notice that when you run your tests this way.
Let Gleam call JavaScript code
In order to call JavaScript code from Gleam, we need to use the
@external(javascript, "module-path", "method"
annotation, just as we did for Erlang. The path is to a JavaScript module, i.e. it works with
import
and export
, and it is best
to use the
.mjs
extension.
Let us create a file src/ffi.mjs
that contains:
export const random = Math.random
Then we can use it from Gleam as follows:
import gleam/io
pub fn main() {
random()
|> io.debug
}
@external(javascript, "./ffi.mjs", "random")
pub fn random() -> Float
JavaScript knows no List
The JavaScript target has been added to Gleam later; Gleam is designed for the Erlang/BEAM target. There is no nice one-on-one mapping from Gleam types to JavaScript types. Specifically, a Gleam list is not mapped to a JavaScript array. Because it is a singly linked list, not an array. The JavaScript implementation of Gleam thus comes with its own list that will be used.If you want to use JavaScript constructs such as an array, promises, and 'typeof', there is a library for that:
gleam add gleam_javascript
JavaScript calling Gleam
Like in our Erlang post, let's have a look at the generated code, now JavaScript, namelybuild/dev/javascript/happy/happy.mjs
:
import * as $io from "../gleam_stdlib/gleam/io.mjs";
import { random } from "./ffi.mjs";
export { random };
export function main() {
let _pipe = random();
return $io.debug(_pipe);
}
Pretty straightforward, files map to modules, with the path providing a nested scope.
Note that this is different from Erlang, which has no nested scope.
Calling an exported Gleam function from JavaScript is, hence, trivial:
import * as $happy from "./happy.mjs"
$happy.random()