<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[SLVA.fr]]></title><description><![CDATA[Samuel's home for blogs and technological hot takes]]></description><link>https://blog.slva.fr</link><generator>RSS for Node</generator><lastBuildDate>Wed, 22 Apr 2026 08:40:29 GMT</lastBuildDate><atom:link href="https://blog.slva.fr/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Rust Askama Axum Unpoly Template]]></title><description><![CDATA[This is a carbon copy of the readme of my new rust web template samuelhnrq/transversal
Transversal
Template rust application. Rust speed, SPA interactivity.
Backend & Web
Axum
Lets start by the most simpler part, Axum is part of the tokio project, a ...]]></description><link>https://blog.slva.fr/rust-template</link><guid isPermaLink="true">https://blog.slva.fr/rust-template</guid><category><![CDATA[Rust]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[webdev]]></category><category><![CDATA[Developer]]></category><category><![CDATA[Cloud]]></category><dc:creator><![CDATA[Samuel Henrique]]></dc:creator><pubDate>Tue, 29 Jul 2025 18:16:50 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/iczg9tvalKA/upload/582ace80068ade88a74de210c46e4b5a.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This is a carbon copy of the readme of my new rust web template <a target="_blank" href="https://github.com/samuelhnrq/transversal">samuelhnrq/transversal</a></p>
<h1 id="heading-transversal">Transversal</h1>
<p>Template rust application. Rust speed, SPA interactivity.</p>
<h2 id="heading-backend-amp-web">Backend &amp; Web</h2>
<h3 id="heading-axum">Axum</h3>
<p>Lets start by the most simpler part, Axum is part of the tokio project, a thin layer of it &amp; hyper, supports tower. Its blazing fast its simple its predictable its great, provides great base and gets out of your way. There are lower level and faster but also more annoying to work with and not as rich ecosystem.</p>
<h3 id="heading-openid-oauth-2">OpenID OAuth 2</h3>
<p>The authentication is made though an OpenID implicit PKCE flow, it receives a openid URL a client ID and secret and uses open ID discovery <code>.well-known</code> to discover the server configuration. After receiving a successful redirect, saves user data to the database and starts a session.</p>
<h3 id="heading-monitoring-amp-tracing">Monitoring &amp; Tracing</h3>
<p>Axum is part of the tokio ecosystem so has built-in support to the great tracing crate, rich logging, spans, tracing you name it, built in.</p>
<h3 id="heading-sea-session">Sea Session</h3>
<p>A more simpler MVC web application allows to the yester-year of sessions, its like cookies but not as annoying or limited. In your controllers you can simply <code>session.get::&lt;Struct&gt;().await</code> with the glue code (Session Backend) in place to persist arbitrary JSON to DB. Its use to mainly to store auth session, but any other Serializable struct can be persisted.</p>
<h2 id="heading-frontend-amp-templating">Frontend &amp; Templating</h2>
<p>The main building blocks are UniPoly and beer.css</p>
<h3 id="heading-no-build-step"><strong>NO BUILD STEP</strong></h3>
<p>This is a quite constraining decision that might be revisited later because there might be a ceiling of functionality that can be achieved without a nodejs build step, but I really wanted to avoid the complexity of managing 2 the projects of different ecosystems and languages. The local DX is already non-ideal (rust compile times) I really rather avoid the extra complexity of having 2 watch process that need to be synchronized.</p>
<h3 id="heading-beercss">Beer.Css</h3>
<p>There is nothing revolutionary about it per-se whats important is ticks all the boxes I needed:</p>
<ul>
<li>Small size</li>
<li>"batteries included" components</li>
<li>accessibility</li>
<li>no build step</li>
</ul>
<p>It is missing some quality of life utility classes (e.g. margins) and is quite aggressive overriding meaning of normal HTML tags like <code>&lt;i&gt;</code> being now for icons but that characteristic actually helps since when used in raw HTML.</p>
<h3 id="heading-unipoly">Unipoly</h3>
<p>MVC has a bunch of historic limitations which I think have been overcompensated for with a javascript frontend SPA framework dictatorship killing a lot of the richness exists in computer programming.</p>
<p>Unipoly is part of the SSR renaissance and from a family of increasingly popular libraries of HTML enhancement libraries (the most infamous being HTMX) which the goal of bringing richer SPA characteristics to MVC web apps, JS stateful navigation, in place update of certain parts of the page without full refresh, richer form validation, etc.</p>
<p>It works great it really is a great progressive enhancement library has a great foundation and anything I need seems to be a <code>up-*</code> html attribute away no matter how complex the behavior.</p>
<h3 id="heading-askama">Askama</h3>
<p>In brief its Jinja, but for rust, parsed and converted at compile time to embedded (in the final binary) rust code. When I was shopping for possible templating solutions I immediately excluded ones that did runtime interpolation/interpretation or anything of the sorts, they just as clunky as templating and still offer a much bigger runtime hit.</p>
<p>Out of the pre-compiled options some were too obscure and/or crazy (see <a target="_blank" href="https://maud.lambda.xyz/">maud</a>) Askama hit the perfect sweet spot of the battle tested Jinja syntax and blazing speed. But not without its issues</p>
<h2 id="heading-known-issues">Known issues</h2>
<ol>
<li><p>Slow compilation times and no auto refresh</p>
<ul>
<li>This is the main tradeoff of Askama, if your templates become rust code when you compile it it means it will go through the infamously slow rust compiler</li>
<li>There is currently no mechanism to auto refresh, it is doable but would be a very complicated bunch of code that needed to be selectively disabled by target</li>
</ul>
</li>
<li><p>The sea-orm Active model &lt;-&gt; serde integration is a little awkward</p>
<ul>
<li>The templates receiving active models to render is a very convenient way to allow per field optional rendering but I got the wrong impression that deserializing into an active model would allow to deserialized missing fields (e.g. ID of relations which make no sense serializing)</li>
<li>The JSON value needs to be a valid model which might mean inserting a fake ID during inserts <code>json_value["id"] = json!(UUID::nil().to_string())</code></li>
<li>As per FormValues HTML limitation, everything is a string, even numbers, because JSON has numbers serde refuses to auto convert string into numbers, which is sensible default and can be configured, sadly sea-orm is migration-first you generate entities from DB state, which has limited customization. I settled for something like this in the repository layer:</li>
</ul>
<pre><code class="lang-rust">json_value[<span class="hljs-string">"number_prop"</span>] = json!(json_value[<span class="hljs-string">"number_prop"</span>].as_str().parse::&lt;<span class="hljs-built_in">i32</span>&gt;().unwrap_or_default())
</code></pre>
</li>
</ol>
<h2 id="heading-faq">FAQ</h2>
<ul>
<li>How to generate the files from the database?<pre><code class="lang-bash">sea generate entity -o models/src/generated --with-serde both --serde-skip-deserializing-primary-key --serde-skip-hidden-column
</code></pre>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Hot potato bug: from Mocha to Node JS]]></title><description><![CDATA[Contributing to open source can be fun, but its not perfect: bureaucracy, egos, async communication across time-zones, a big challenge to any project manager, expect they tend to be nonexistent in open source.
I was working in fixing a bug in Mocha, ...]]></description><link>https://blog.slva.fr/bug-mocha-to-node-js</link><guid isPermaLink="true">https://blog.slva.fr/bug-mocha-to-node-js</guid><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Bugs and Errors]]></category><category><![CDATA[Testing]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[Open Source]]></category><dc:creator><![CDATA[Samuel Henrique]]></dc:creator><pubDate>Mon, 21 Jul 2025 15:27:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/Cm6GGegbcoU/upload/dc3478cdfb03365bc897051542764df0.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Contributing to open source can be fun, but its not perfect: bureaucracy, egos, async communication across time-zones, a big challenge to any project manager, expect they tend to be nonexistent in open source.</p>
<p>I was working in fixing a bug in <a target="_blank" href="https://github.com/mochajs/mocha">Mocha</a>, which although renowned testing framework, is starting to show its age (10+ years), so its going through major changes to keep up with the competition. And as with any major changes its normal to have some regressions along the way, I found one and reported it the mocha team was quite agile in confirming my issue, so I dug in the code myself to diagnose the root cause but turns out this bug was much bigger then initially thought.</p>
<p>Being a testing library it necessitates a quite a complex files loading and discovery code, turns out Mocha’s use case was complex enough to reveal <strong>a bug in Node JS</strong> itself, so this is a story how I managed the communication and reporting and escalation of the same bug to two different major JavaScript ecosystem projects.</p>
<h2 id="heading-esm-vs-cjs">ESM vs CJS</h2>
<p>For you to understand the bug, you need to understand the difference between an CJS and a ESM module, and especially and how node’s adoption of ESM was… well slow. I'd love to write about the mess which is the story of JavaScript modules, but it would be way too long of a tangent, if you’re curious you can read <a target="_blank" href="https://betterstack.com/community/guides/scaling-nodejs/commonjs-vs-esm/">this article</a> about it, but all you need to know that node.js has two main ways (module systems) to allow files to import each other: <code>import { foo } from “library”</code> (ESM) and <code>const { foo } = require('library')</code> (CJS) node JS is in the process of adding functionality to better support for the “new” ESM way.</p>
<p>One of the main pain points of the module system migration was the fact that although both the systems are conceptually equivalent: “import exposed symbols of some other file”, ESM has extra functionality which made it challenging to make then interoperable, the big one being ESM modules can have await expressions outside of async function body, a.k.a. “top level await”. The node team has dragged its feet with barebones ESM support for years. Only after fierce competition from new runtimes like Deno and Bun node finally added core missing ESM functionality. The important bit for us is: <code>require(ESM)</code></p>
<p><code>require(ESM)</code> is the missing piece that the ecosystem needed to start migrating en-masse to ESM, it basically allows you to <code>require()</code> an ESM module as if it were a CJS file helping bridging the gap and ease transition (<a target="_blank" href="https://nodejs.org/api/modules.html#loading-ecmascript-modules-using-require">with caveats</a>), historically if you needed to access a ESM module from CJS (which is the more common use case as libraries tend to migrate faster then applications) you were supposed to use dynamic async imports <code>await import(module)</code> which are very disruptive to any program flow: imagine of instead of having require calls at the top of your file you now had to <code>await import</code> in each of your functions? Because don’t you forget, in CJS you can only await inside an async function! In reality no one ever did that, given the popularity of Typescript, people already had transpilers setup in their projects, which all had functionality to hide node’s lack luster ESM support. <a target="_blank" href="https://www.typescriptlang.org/docs/handbook/modules/theory.html#the-module-output-format">Even typescript itself</a>.</p>
<h2 id="heading-whos-cache-is-it">Who’s cache is it?</h2>
<p>Enough of Node’s quirks, on to the bug: Although convenient, the <code>require(ESM)</code> begs an important question: Whose cache is it? CJS and ESM are historically known for having separate <a target="_blank" href="https://nodejs.org/api/modules.html#caching">module caches</a>, does that mean require can now write to ESM module cache? Will it check on its cache first? May seem like implementation details but now was a pressing question for me. Since mocha needs to support a lot of node it couldn’t rely anymore on good old <code>ERR_REQUIRE_ESM</code> to fallback to to <code>import()</code>. Mocha’s implementation basically ignored any error thrown by the first <code>require</code> call and trusted node JS to keep the same behaviour if you tried to import a module twice, no matter if <code>require(ESM)</code> or <code>import(ESM)</code>. Turns out it was not the case, and I had found a bug to affecting node versions all the way back to LTS which goes like this:</p>
<p>If you tried to <code>require(ESM)</code> a module with had a “top level error” (an error thrown during module evaluation outside the body of a function) the first require call would throw as expected but future calls of <code>import(ESM)</code> would just return an empty object. That broke the mocha implementation, that now couldn’t tell the module had a top level error: the <code>import(ESM)</code> promise was resolved normally hiding the error, when you called <code>mocha</code> it just skipped the said file without registering any tests.</p>
<p>The bug itself it’s not super complex to define and is quite situational. But was very important to more intricate consumers of the ESM API like Mocha. Confident of my code sandbox <a target="_blank" href="https://en.wikipedia.org/wiki/Minimal_reproducible_example#:~:text=In%20computing%2C%20a%20minimal%20reproducible,to%20be%20demonstrated%20and%20reproduced.">MRE</a> I opened my first <a target="_blank" href="https://github.com/nodejs/node/issues/58945">node bug request</a>. Just a quick shout out: tools like code sandbox shine for MREs, allows you to isolate environment differences and pin a specific node version running in a containerized environment. A blessing for creating meaningful bug requests.</p>
<h2 id="heading-the-race-for-the-fix">The race for the fix</h2>
<p>At this time I was confident of my bug and was hoping to be able to claim the laurels of my investigation by merging a bug fix on node’s main branch, but my C skills were not quick enough to be able to setup the project locally and understand node internals and how to fix the bug before the legendary <a target="_blank" href="https://github.com/joyeecheung">joyeecheung</a> (the original <code>require(esm)</code> implementer) came swooping in with a agile surgical fix. In the end the fix was merged within a week which is quite fast for a project size of node.</p>
<p>I did ended up updating the <a target="_blank" href="https://mochajs.org/#nodejs-native-esm-support">mocha’s official documentation</a> about the bug while we wait for node js release as a consolation prize from the gracious <a target="_blank" href="https://github.com/JoshuaKGoldberg">JoshuaKGoldberg</a>. I hope this inspired you to also post your bug reports to your favorite library and thanks for reading.</p>
]]></content:encoded></item><item><title><![CDATA[Open source: Testing the testers]]></title><description><![CDATA[Node.js latest releases have been quite fun as of late, and jest my go to testing framework wasn’t keeping up with the ecosystem so I thought it was time for me to go back to the good old days of hot drinks testing frameworks, but what was supposed t...]]></description><link>https://blog.slva.fr/mocha-bug</link><guid isPermaLink="true">https://blog.slva.fr/mocha-bug</guid><category><![CDATA[Bugs and Errors]]></category><category><![CDATA[Open Source]]></category><category><![CDATA[Testing]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Node.js]]></category><dc:creator><![CDATA[Samuel Henrique]]></dc:creator><pubDate>Mon, 07 Jul 2025 17:35:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/GP2DfG8WxU8/upload/5de63d101fde0e774a81e52e3fbbc75d.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Node.js latest releases have been quite fun as of late, and jest my go to testing framework wasn’t keeping up with the ecosystem so I thought it was time for me to go back to the good old days of hot drinks testing frameworks, but what was supposed to be a nostalgia trip back to mocha.js actually helped me feel open source in the flesh, open source tools you use everyday are not magical bug-free black boxes. Conceptually sounds obvious but it feels different when it happens to you and find a bug in a tool you used so long.</p>
<p>The first step of TDD is to write the failing test, but what if the test not even gets detected? That was the start of my journey. After spending a good afternoon after trying to track a bug down to a silly lack of environment variable I noticed that was something very fishy about mocha, it never reported top level import errors, an exception was being thrown during module import but mocha was not reporting on it, just saying “0 tests”, I initially didn’t want to blame it on mocha, I like living on the edge and was running the latest node (24) with native type-stripped ESM typescript files. But although I acknowledged the fact that the problem was somewhat self-inflicted I still believed it was relevant enough to raise an <a target="_blank" href="https://github.com/mochajs/mocha/issues/5396">issue</a> in mocha’s repository so they could prepare for when those features reach the <em>masses</em>.</p>
<p>I don’t know about you but personally my biggest struggle with open source has always been the social management aspect of working in public: piles of irrelevant issues, sometimes entitled people, finally you find something to contribute on, open a PR about it and have petty developers nitpick on your variable names. So for me I got quite the rush to have my reported bug not only confirmed but also affecting LTS, having that easy of a score I couldn’t resist, I dug in.</p>
<p>Then I realized that a decade old project might not be as accessible to contribute as one initially though, how do you even write tests on a testing framework? CONTRIBUTING.md files are something you can’t quite value until you need one, you can know conceptually that is supposed to help you understand how to contribute, but I hadn’t realized contributing might also mean working on a bug affecting you too, not a document for select few.</p>
<p>Turns out my bug could be tested using mocha’s “integration” test which is somewhat simpler then the unit tests (turns out is kinda complicated to test a test framework) which mostly means spawning a child process of mocha running a “fixture” test and asserting on std-out, exit code, etc.</p>
<p>I’m not particularly religious about TDD but it goes a long way conserving your sanity when trying to find your way in such a big project, secondly knowing my way around a debugger really turned out invaluable, much better to simply drop breakpoints, know all variable values at any given point and step over from there. Codebase which may I remind you, is mostly ES5 JavaScript so that means: no typescript, prototype based OOP, and node callback hell, the code is older than promises so lets just say the age is starting to show.</p>
<p>And I don't mean to complain, mocha is still wildly used and the contributors are right now working to reboot development and if anything all this tech debt just makes me feel I can make a difference, how many nerds are still around to refactor <code>function.proptotype.instanceMethod = function () {}</code> away? Endless contribution opportunities, and mocha still has 22k stars.</p>
<p>After stepping in, out and over, I finally came across a piece of code that although quite clever, assumes a little much about node, and exposed mocha to all kinds of funny bugs from downstream dependencies, but I’m getting ahead of myself, the code goes a little something like this: (overly simplified of course)</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">loadTestFile</span>(<span class="hljs-params">resolvedFilePath</span>) </span>{
    <span class="hljs-comment">// [...]</span>
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">require</span>(resolvedFilePath);
    } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-keyword">import</span>(resolvedFilePath);
    }
}
</code></pre>
<p>Its quite the ingenious way to support ESM and CJS modules transparently: tries the path of least resistant first by requiring it, if it fails, try falling back to importing, with the big assumption being that if the error thrown by the require wasn’t related to ESM / CJS integration, the second import will simply throw the same error again. Well turns out I had just struck gold because in fact the import call was not throwing the second time! The same module, with the same top level exception, simply disappeared swallowed by node, which was returning a meaningless empty object instead.</p>
<p>Stay tuned to learn how I reported and <em>almost</em> landed a the fix on node.JS main.</p>
]]></content:encoded></item></channel></rss>