diff --git a/output/category/programming.html b/output/category/programming.html new file mode 100644 index 0000000..a7116cb --- /dev/null +++ b/output/category/programming.html @@ -0,0 +1,82 @@ + + + + + + + + + + + + + Category: programming – LEdoian's Blog + + + +
+

LEdoian's Blog

+
+ +
+ + +
+
+

Category: programming

+ +
+
+
+ + + + + diff --git a/output/feeds/programming.atom.xml b/output/feeds/programming.atom.xml new file mode 100644 index 0000000..39524e0 --- /dev/null +++ b/output/feeds/programming.atom.xml @@ -0,0 +1,85 @@ + +LEdoian's Blog - programminghttps://blog.ledoian.cz/2024-09-09T16:28:00+02:00Using Gleam in HTML with as little JavaScript knowledge as possible2024-09-09T16:28:00+02:002024-09-09T16:28:00+02:00LEdoiantag:blog.ledoian.cz,2024-09-09:/using-gleam-in-html-low-js.html<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 …</p><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() { + &quot;Hello World!&quot; +} + +pub fn main() { + io.println(&quot;3, 2, 1, go!&quot;) +} +</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"> +&lt;!doctype html&gt; +&lt;html&gt; +&lt;head&gt; + &lt;meta charset=utf-8&gt; &lt;!-- firefox complains otherwise --&gt; + &lt;title&gt;Buh&lt;/title&gt; +&lt;/head&gt; +&lt;body&gt; + &lt;!-- some random elements to work with --&gt; + &lt;button id=butt&gt;Klik mee&lt;/button&gt; + &lt;p id=uwu&gt; + + &lt;!-- 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. --&gt; + &lt;script type=module&gt; //It has to be a module to allow imports + import * as lol from &quot;./build/dev/javascript/lol/lol.mjs&quot;; + + // 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(); + &lt;/script&gt; +&lt;/body&gt; +&lt;/html&gt; +</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> + \ No newline at end of file diff --git a/output/tag/gleam.html b/output/tag/gleam.html new file mode 100644 index 0000000..465fdb4 --- /dev/null +++ b/output/tag/gleam.html @@ -0,0 +1,82 @@ + + + + + + + + + + + + + Tag: gleam – LEdoian's Blog + + + +
+

LEdoian's Blog

+
+ +
+ + +
+
+

Articles tagged with gleam

+ +
+
+
+ + + + + diff --git a/output/tag/web.html b/output/tag/web.html new file mode 100644 index 0000000..67f64ad --- /dev/null +++ b/output/tag/web.html @@ -0,0 +1,82 @@ + + + + + + + + + + + + + Tag: web – LEdoian's Blog + + + +
+

LEdoian's Blog

+
+ +
+ + +
+
+

Articles tagged with web

+ +
+
+
+ + + + + diff --git a/output/using-gleam-in-html-low-js.html b/output/using-gleam-in-html-low-js.html new file mode 100644 index 0000000..9bdd89b --- /dev/null +++ b/output/using-gleam-in-html-low-js.html @@ -0,0 +1,164 @@ + + + + + + + + + + + + + Using Gleam in HTML with as little JavaScript knowledge as possible – LEdoian's Blog + + + +
+

LEdoian's Blog

+
+ +
+ + +
+
+
+

Using Gleam in HTML with as little JavaScript knowledge as possible

+

I've been looking at the Gleam language 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.

+

My initial JS knowledge: alert(3), onclick 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 :-)

+
+

My code

+

Let's start with some trivial code, in src/lol.gleam (in a project initialised with gleam new lol and the repeatedly package added with gleam add repeatedly):

+
+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!")
+}
+
+

This snippet has many of the basic stuff I might need in future: it does some io, it uses another package [1], 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.

+

So, build this for JavaScript: gleam build --target javascript, and stuff happens. It is not very clear what to do now, but grep``ping through the ``build/ directory shows that the built code lives in build/dev/javascript/lol/lol.mjs.

+
+
+

Embedding the code

+

Here comes the fun part: the code is in JavaScript module, 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 file:// one +- Due to scoping, I have not found a way of using the functions from devtools console

+

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 main.html in the project root, but it does not probably matter. The code:

+
+<!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>
+
+

Shoutout to the person who asked the same question on StackOverflow. From this point on, we only need a HTTP server; luckily, Python has one in stdlib, so just calling python3 -m http.server 12312 in the project root lets us load http://localhost:12312/main.html and see our page.

+
+
+

Next steps, alternatives et cetera

+

When developing web frontend in Gleam, the more common way is using a framework like Lustre or at least a DOM library (there are several, 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. [2]

+

Also, a common thing to do is using a minifier+bundler like esgleam (it uses esbuild 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 one tutorial on how to do that.

+

Also, during writing of this article I realised Gleam can run all the JS code from itself, so I could have a js_main function that would bind the HTML from Gleam itself. But this is probably more readable and separated anyway.

+
+ + + + + +
[1]Well, as far as I understand it, Gleam's stdlib is actually just another package anyway.
+ + + + + +
[2]I will probably use some kind of framework eventually as a part of netzpevnik, but I am exploring the technologies that will be involved, so I want to keep stuff simple.
+
+ +
+
+
+ + + + +