|
|
<!doctype html>
|
|
|
<html>
|
|
|
<head>
|
|
|
<meta charset=utf-8>
|
|
|
<meta name=generator content="Pelican 4.9.1">
|
|
|
<meta name=author content="LEdoian">
|
|
|
<meta name=description content="My personal webpage">
|
|
|
<meta name=referrer content=no-referrer>
|
|
|
|
|
|
|
|
|
<link rel=stylesheet href="./theme/css/theme.css">
|
|
|
|
|
|
<title>Using Gleam in HTML with as little JavaScript knowledge as possible – LEdoian's Blog</title>
|
|
|
</head>
|
|
|
<body>
|
|
|
|
|
|
<header>
|
|
|
<h1>LEdoian's Blog</h1>
|
|
|
</header>
|
|
|
|
|
|
<div id=main>
|
|
|
<nav>
|
|
|
<div>
|
|
|
<!-- Main navigation -->
|
|
|
<!-- TODO! -->
|
|
|
</div>
|
|
|
<div>
|
|
|
<h2>Categories</h2>
|
|
|
<ul>
|
|
|
<li><a href="./category/networking.html">networking</a></li>
|
|
|
<li><a href="./category/programming.html">programming</a></li>
|
|
|
<li><a href="./category/queer.html">queer</a></li>
|
|
|
<li><a href="./category/talks.html">talks</a></li>
|
|
|
<li><a href="./category/technology.html">technology</a></li>
|
|
|
<li><a href="./category/til.html">til</a></li>
|
|
|
</ul>
|
|
|
|
|
|
<h2>Tags</h2>
|
|
|
<ul>
|
|
|
<li><a href="./tag/gleam.html">gleam</a></li>
|
|
|
<li><a href="./tag/software.html">software</a></li>
|
|
|
<li><a href="./tag/web.html">web</a></li>
|
|
|
<li><a href="./tag/gender.html">gender</a></li>
|
|
|
<li><a href="./tag/identity.html">identity</a></li>
|
|
|
<li><a href="./tag/linux.html">linux</a></li>
|
|
|
<li><a href="./tag/lifehack.html">lifehack</a></li>
|
|
|
<li><a href="./tag/relationships.html">relationships</a></li>
|
|
|
<li><a href="./tag/print.html">print</a></li>
|
|
|
<li><a href="./tag/comics.html">comics</a></li>
|
|
|
<li><a href="./tag/ipv6-only.html">ipv6-only</a></li>
|
|
|
<li><a href="./tag/dns.html">dns</a></li>
|
|
|
<li><a href="./tag/meta.html">meta</a></li>
|
|
|
<li><a href="./tag/infrastructure.html">infrastructure</a></li>
|
|
|
<li><a href="./tag/smrst.html">smršť</a></li>
|
|
|
<li><a href="./tag/trains.html">trains</a></li>
|
|
|
<li><a href="./tag/software-engineering.html">software-engineering</a></li>
|
|
|
</ul>
|
|
|
</div>
|
|
|
<div>
|
|
|
<h2>Stalk me also at</h2>
|
|
|
TODO!
|
|
|
|
|
|
<h2>I stalk</h2>
|
|
|
TODO!
|
|
|
</nav>
|
|
|
|
|
|
<main>
|
|
|
<div>
|
|
|
<div class="details"><time datetime="2024-09-09T16:28:00+02:00">2024-09-09 16:28</time></div>
|
|
|
<h1>Using Gleam in HTML with as little JavaScript knowledge as possible</h1>
|
|
|
<p>I've been looking at the <a class="reference external" href="https://gleam.run">Gleam language</a> recently. Among other features, it can be compiled to JavaScript, and thus presumably used on web frontend. I wanted to try that. This is a short tutorial on how to do that with little idea how JavaScript is supposed to work.</p>
|
|
|
<p>My initial JS knowledge: <tt class="docutils literal">alert(3)</tt>, <tt class="docutils literal">onclick</tt> and some basic selectors, i.e. the little stuff that is useful to add minor interactivity to HTML pages and implement trivial ViolentMonkey scripts. Namely: I have no knowledge about modules and whatnot, and this post is just a result of my trial-and-error attempt at embedding my Gleam. I succeeded, but still have no idea what I am doing :-)</p>
|
|
|
<div class="section" id="my-code">
|
|
|
<h2>My code</h2>
|
|
|
<p>Let's start with some trivial code, in <tt class="docutils literal">src/lol.gleam</tt> (in a project initialised with <tt class="docutils literal">gleam new lol</tt> and the <tt class="docutils literal">repeatedly</tt> package added with <tt class="docutils literal">gleam add repeatedly</tt>):</p>
|
|
|
<pre class="literal-block">
|
|
|
import gleam/io
|
|
|
import repeatedly
|
|
|
|
|
|
pub fn say_hello() {
|
|
|
repeatedly.call(2000, Nil, fn(_state, _call) {io.println(get_greeting())})
|
|
|
}
|
|
|
|
|
|
pub fn get_greeting() {
|
|
|
"Hello World!"
|
|
|
}
|
|
|
|
|
|
pub fn main() {
|
|
|
io.println("3, 2, 1, go!")
|
|
|
}
|
|
|
</pre>
|
|
|
<p>This snippet has many of the basic stuff I might need in future: it does some io, it uses another package <a class="footnote-reference" href="#stdlib-package" id="footnote-reference-1">[1]</a>, it returns data I will want to show. At first I am mostly interested in multiplatform stuff (i.e. running also on the BEAM backend), so I don't want to use any DOM frameworks at first, though I will mention some of the ways later in the post.</p>
|
|
|
<p>So, build this for JavaScript: <tt class="docutils literal">gleam build <span class="pre">--target</span> javascript</tt>, and <em>stuff happens</em>. It is not very clear what to do now, but <tt class="docutils literal"><span class="pre">grep``ping</span> through the ``build/</tt> directory shows that the built code lives in <tt class="docutils literal">build/dev/javascript/lol/lol.mjs</tt>.</p>
|
|
|
</div>
|
|
|
<div class="section" id="embedding-the-code">
|
|
|
<h2>Embedding the code</h2>
|
|
|
<p>Here comes the fun part: the code is in JavaScript <em>module</em>, not plain code. That comes with several surprises:
|
|
|
- It can only be imported from other modules, not by “plain” code in global scope
|
|
|
- Due to CORS, imports only work with network schemes, not with the <tt class="docutils literal"><span class="pre">file://</span></tt> one
|
|
|
- Due to scoping, I have not found a way of using the functions from devtools console</p>
|
|
|
<p>Big wins for the platform /s, but we have to live with that, so let's try to write the respective HTML for this. I put that in <tt class="docutils literal">main.html</tt> in the project root, but it does not probably matter. The code:</p>
|
|
|
<pre class="literal-block">
|
|
|
<!doctype html>
|
|
|
<html>
|
|
|
<head>
|
|
|
<meta charset=utf-8> <!-- firefox complains otherwise -->
|
|
|
<title>Buh</title>
|
|
|
</head>
|
|
|
<body>
|
|
|
<!-- some random elements to work with -->
|
|
|
<button id=butt>Klik mee</button>
|
|
|
<p id=uwu>
|
|
|
|
|
|
<!-- the “binding” to our Gleam code. This probably needs to be at the end of the page, since it needs to be able to use the selectors. -->
|
|
|
<script type=module> //It has to be a module to allow imports
|
|
|
import * as lol from "./build/dev/javascript/lol/lol.mjs";
|
|
|
|
|
|
// Set the text of one element to the computed stuff:
|
|
|
let par = document.getElementById('uwu');
|
|
|
par.innerText = lol.get_greeting();
|
|
|
|
|
|
// Let's have an interactive button (I love the come-from pattern, but using `onclick` would be even trickier…)
|
|
|
let butt = document.getElementById('butt');
|
|
|
butt.addEventListener('click', lol.say_hello);
|
|
|
|
|
|
// Apparently, the `main` function does not get run automatically, so call that explicitly.
|
|
|
lol.main();
|
|
|
</script>
|
|
|
</body>
|
|
|
</html>
|
|
|
</pre>
|
|
|
<p>Shoutout to <a class="reference external" href="https://stackoverflow.com/questions/53630310/use-functions-defined-in-es6-module-directly-in-html">the person who asked the same question on StackOverflow</a>. From this point on, we only need a HTTP server; luckily, Python has one in stdlib, so just calling <tt class="docutils literal">python3 <span class="pre">-m</span> http.server 12312</tt> in the project root lets us load <tt class="docutils literal"><span class="pre">http://localhost:12312/main.html</span></tt> and see our page.</p>
|
|
|
</div>
|
|
|
<div class="section" id="next-steps-alternatives-et-cetera">
|
|
|
<h2>Next steps, alternatives et cetera</h2>
|
|
|
<p>When developing web frontend in Gleam, the more common way is using a framework like <a class="reference external" href="https://hexdocs.pm/lustre/index.html">Lustre</a> or at least a DOM library (there are <a class="reference external" href="https://packages.gleam.run/?search=dom">several</a>, I have no idea how mature those are). I did not go this route yet, because I am more interested in using backend-agnostic Gleam code from JavaScript and don't mind writing the trivial bindings in JavaScript. <a class="footnote-reference" href="#netzpevnik-gleam" id="footnote-reference-2">[2]</a></p>
|
|
|
<p>Also, a common thing to do is using a minifier+bundler like <a class="reference external" href="https://hexdocs.pm/esgleam/index.html">esgleam</a> (it uses <a class="reference external" href="https://esbuild.github.io/">esbuild</a> under the hood), so that the whole project is in one file. I don't think I need that now (having the JS be readable is more important to me atm and I don't want to complicate things further), but there is at least <a class="reference external" href="https://erikarow.land/notes/esgleam-embed">one tutorial</a> on how to do that.</p>
|
|
|
<p>Also, during writing of this article I realised Gleam can run all the JS code from itself, so I could have a <tt class="docutils literal">js_main</tt> function that would bind the HTML from Gleam itself. But this is probably more readable and separated anyway.</p>
|
|
|
<hr class="docutils" />
|
|
|
<table class="docutils footnote" frame="void" id="stdlib-package" rules="none">
|
|
|
<colgroup><col class="label" /><col /></colgroup>
|
|
|
<tbody valign="top">
|
|
|
<tr><td class="label"><a class="fn-backref" href="#footnote-reference-1">[1]</a></td><td>Well, as far as I understand it, Gleam's stdlib is actually just another package anyway.</td></tr>
|
|
|
</tbody>
|
|
|
</table>
|
|
|
<table class="docutils footnote" frame="void" id="netzpevnik-gleam" rules="none">
|
|
|
<colgroup><col class="label" /><col /></colgroup>
|
|
|
<tbody valign="top">
|
|
|
<tr><td class="label"><a class="fn-backref" href="#footnote-reference-2">[2]</a></td><td>I will probably use some kind of framework eventually as a part of <a class="reference external" href="https://gitea.ledoian.cz/LEdoian/netzpevnik">netzpevnik</a>, but I am exploring the technologies that will be involved, so I want to keep stuff simple.</td></tr>
|
|
|
</tbody>
|
|
|
</table>
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
</main>
|
|
|
</div> <!-- #main -->
|
|
|
|
|
|
<footer>
|
|
|
<hr>
|
|
|
Written using Pelican 4.9.1 by LEdoian.
|
|
|
</footer>
|
|
|
|
|
|
</body>
|
|
|
</html>
|