{
    "version": "https://jsonfeed.org/version/1",
    "title": "diekmeier.de",
    "home_page_url": "https://diekmeier.de/",
    "feed_url": "https://diekmeier.de/json",
    "description": "A blog about software development.",
    "author": {
        "name": "Daniel Diekmeier"
    },
    "items": [
        {
            "id": "2025-03-04-get-a-grip",
            "content_html": "<p>Every now and then, I see developers working on bugs for a long time. (In this post, “bugs” mostly means “surprising misbehaviors of features in a web app”, since that's what I'm working on most of the time.) These developers will invest a huge amount of time and effort, but when they explain how it's going, they seem to spin their wheels and are only making very slow, undirected progress. They chip away at the problem from many different angles, hopefully hitting the solution one day.</p>\n<p>What strikes me is that these are smart people, working hard on the problem. My feeling is that they <em>could</em> solve the problem in a much shorter time, but their approaching is hindering them.</p>\n<p>Recently, I told <a href=\"https://timomeh.de/\">Timo</a> about this, and while I did, I accidentally created a metaphor: Debugging is like lifting something up and carrying it where it needs to go.</p>\n<p>You need to look at the thing, determine it's shape and weight, and find a good way to grip it.</p>\n<p>Imagine the humble moving box. Yes, you could take one hand and grip one of the open flaps. But that's so weird. You could take <em>two</em> hands and grip one of the open flaps. Still weird, stop grabbing the flaps. Actually, close the flaps. A typical moving carton has two handles to put your hands into and grip. Additionally, if you rest it against your body a bit, or you get to stretch out your arms, carrying gets much easier.</p>\n<p>(Even then, real pros will tell you that, actually, you should carry the box from the bottom, because then you will not rip the handles, and it will be easier to make your arms straight without dangling a box before your legs. But I digress.)</p>\n<p>Imagine a couch. If you need to carry it, you probably need to grab quite low, until your hands get some good purchase. Also, you probably want to remove all the cushions first (so important) and get someone to help you.</p>\n<p>In a way, the same applies to bugs. You need to find a good spot to hold them. If you notice that you didn't find a good spot yet, <em>don't grip harder</em>. You will just tire yourself out! Put it down for a second, move your hands, grip again.</p>\n<p>Don't get me wrong: I know that this is very, very difficult. If it was easy, computers could do it themselves. (I'm not interested in hearing whether LLMs <em>can</em> do this. Don't let them take this from you. It's worth it to be better than an LLM.) It takes a huge amount of skill and experience to know how to grip a problem. But there are a few things that can help you.</p>\n<ol>\n<li><strong>Really reproduce the problem.</strong> Time and time again, I see people that start debugging without experiencing the bug with their own eyes. Make it easier on yourself: Reproduce the bug, make it easy to reproduce <em>repeatedly</em> (like with an automated test), and only then start changing code.</li>\n<li><strong>Eliminate layers.</strong> If you aren't sure where exactly a bug happens, remove places where it can hide. Recently, I had to figure out why ElasticSearch in one of our Rails apps sometimes returned wrong results. I tried to skip all Rails code and used <code>curl</code> to send the queries to ElasticSearch directly – and the problem still happened! This immediately excluded 99 % of our Rails app from the debugging journey.</li>\n<li><strong>Change the (error) message.</strong> Continuously prove that you're on the right trail by changing the output. You don't even have to make the error message <em>better</em> or make it go away. Very often, I put a <code>raise &quot;hell&quot;</code> into the code, just to see that I'm editing the right file, and that the code I'm editing is really getting called.</li>\n<li><strong>Notice when you get stuck.</strong> Banging your head against the wall feels great and horrible at the same time. Don't forget to take a break, and when you do, ask yourself: Is there something better that I can try?</li>\n</ol>\n<p>The next time you're struggling with a bug for a long time, and wondering how you got there, maybe think: How can I get a real grip on this? Good luck.</p>\n",
            "url": "https://diekmeier.de/posts/2025-03-04-get-a-grip/",
            "title": "The Most Important Part of Debugging: Getting a Grip!",
            "date_modified": "2025-03-04T00:00:00.000Z"
        },
        {
            "id": "2024-11-17-gnu-parallel",
            "content_html": "<p><em>This article is basically a rant I wrote to <a href=\"https://timomeh.de\">Timo</a>, before he told me to convert it into a blogpost. Here we go!</em></p>\n<p>For years, I've been searching for a CLI tool that …</p>\n<ul>\n<li>runs multiple commands concurrently</li>\n<li>blocks until all the commands have finished</li>\n<li>returns a unified exit code (If all commands pass, it passes; if any of the commands fails, the whole thing fails.)</li>\n</ul>\n<p>Due to these requirements, I wasn't able to use <code>&amp;</code>. (At least not without some more gymnastics to track the processes and calculate the exit code. It didn't seem worth it.)</p>\n<p>Every now and again, I would stumble over <a href=\"https://www.gnu.org/software/parallel/\">GNU Parallel</a>. Enticed by the promising name, I would look at <a href=\"https://www.gnu.org/software/parallel/man.html\">the manual</a> but not find a way to do what I want. There are <a href=\"https://www.gnu.org/software/parallel/parallel_examples.html\">162 examples</a> and most of them (I haven't actually looked at <em>all</em> of them in detail) do some wild shell gymnastics, like</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-zsh\"><span class=\"line\"><span style=\"color: #B8CFE680; font-style: italic\"># Simple network scanner</span></span>\n<span class=\"line\"><span style=\"color: #73D0FF\">prips</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #DFBFFF\">130.229</span><span style=\"color: #D5FF80\">.16.0/20</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #F29E74\">|</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #95E6CB\">\\</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  </span><span style=\"color: #73D0FF\">parallel</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #95E6CB\">--timeout</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #DFBFFF\">2</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #95E6CB\">-j0</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #95E6CB\">\\</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">    </span><span style=\"color: #D5FF80\">&#39;ping -c 1 {} &gt;/dev/null &amp;&amp; echo {}&#39;</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #F29E74\">2&gt;</span><span style=\"color: #D5FF80\">/dev/null</span></span>\n<span class=\"line\"></span></code></pre>\n<p>I did not even cherry pick this so that I could be annoyed. This is literally the second example! I don't need a network scanner, I only want to run three scripts at once! Please!</p>\n<p>At this point I often closed the page, since this tool is obviously too advanced and not what I was looking for. Sure, if I ever need to <a href=\"https://www.gnu.org/software/parallel/parallel_examples.html#example-download-apollo-11-images-from-nasa-using-jq\">Download Apollo-11 images from NASA using jq</a> or <a href=\"https://www.gnu.org/software/parallel/parallel_examples.html#example-grepping-n-lines-for-m-regular-expressions\">Grep n lines for m regular expressions</a>, I might give it a go, but that's for another day.</p>\n<p>Except that this week, I somehow cracked it. I don't know how I got the idea, but I noticed that some of the examples use <code>:::</code> as a kind of argument separator. It turns out that we can pass the commands itself as arguments:</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-zsh\"><span class=\"line\"><span style=\"color: #73D0FF\">parallel</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">:::</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">&quot;pnpm lint&quot;</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">&quot;pnpm check&quot;</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">&quot;pnpm test&quot;</span></span>\n<span class=\"line\"></span></code></pre>\n<p>I almost couldn't believe it, but this works! It runs the three commands, it prints their output separately, and it returns a unified exit code. Now that I knew what I was looking for, I <em>still</em> wasn't able to find an example of this invocation in between the 162 examples. Welp! But it works!</p>\n<p>Most importantly: It really is faster. I save almost half the time:</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-zsh\"><span class=\"line\"><span style=\"color: #FFAD66\">time</span><span style=\"color: #CCCAC2\"> parallel ::: </span><span style=\"color: #D5FF80\">&quot;pnpm lint&quot;</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">&quot;pnpm check&quot;</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">&quot;pnpm test&quot;</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  </span><span style=\"color: #73D0FF\">68.06s</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">user</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #DFBFFF\">8.89</span><span style=\"color: #D5FF80\">s</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">system</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #DFBFFF\">442</span><span style=\"color: #D5FF80\">%</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">cpu</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #DFBFFF\">17.388</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">total</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #FFAD66\">time</span><span style=\"color: #CCCAC2\"> ( </span><span style=\"color: #73D0FF\">pnpm</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">lint</span><span style=\"color: #CCCAC2B3\">;</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #73D0FF\">pnpm</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">check</span><span style=\"color: #CCCAC2B3\">;</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #73D0FF\">pnpm</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">test</span><span style=\"color: #CCCAC2B3\">;</span><span style=\"color: #CCCAC2\"> )</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  </span><span style=\"color: #73D0FF\">27.05s</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">user</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #DFBFFF\">5.65</span><span style=\"color: #D5FF80\">s</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">system</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #DFBFFF\">115</span><span style=\"color: #D5FF80\">%</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">cpu</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #DFBFFF\">28.221</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">total</span></span>\n<span class=\"line\"></span></code></pre>\n<p>If you ever need to parallelize something, I hope this knowledge will come in handy. Good luck!</p>\n",
            "url": "https://diekmeier.de/posts/2024-11-17-gnu-parallel/",
            "title": "GNU Parallel: The Good Parts",
            "date_modified": "2024-11-17T00:00:00.000Z"
        },
        {
            "id": "2024-08-01-stop-using-correct-in-test-titles",
            "content_html": "<p>At work, I'm thinking a lot about testing, and what kind of tests help me to understand and maintain projects. However, I keep coming across words like &quot;correct&quot; in test titles, and it has happened often enough that I'm finally writing this blog post.</p>\n<p><em>Please stop.</em></p>\n<p>Let's start with one example in a little more detail, but there will be more at the end. I'm talking about situations like this:</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-rb\"><span class=\"line\"><span style=\"color: #CCCAC2\">describe </span><span style=\"color: #D5FF80\">&quot;#average_score&quot;</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  it </span><span style=\"color: #D5FF80\">&quot;returns correct average&quot;</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #FFAD66\">do</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">    </span><span style=\"color: #B8CFE680; font-style: italic\"># cool setup here ...</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">    expect(thing</span><span style=\"color: #CCCAC2B3\">.</span><span style=\"color: #CCCAC2\">average_score)</span><span style=\"color: #CCCAC2B3\">.</span><span style=\"color: #CCCAC2\">to eq(</span><span style=\"color: #DFBFFF\">4.2</span><span style=\"color: #CCCAC2\">)</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  </span><span style=\"color: #FFAD66\">end</span></span>\n<span class=\"line\"><span style=\"color: #FFAD66\">end</span></span>\n<span class=\"line\"></span></code></pre>\n<p>My problem with this is: What the heck is &quot;correct&quot; supposed to mean? When we look at the code, we might find something like this:</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-rb\"><span class=\"line\"><span style=\"color: #FFAD66\">def</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #FFD173\">average_score</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  ratings </span><span style=\"color: #F29E74\">=</span><span style=\"color: #CCCAC2\"> users</span><span style=\"color: #CCCAC2B3\">.</span><span style=\"color: #CCCAC2\">only_public</span><span style=\"color: #CCCAC2B3\">.</span><span style=\"color: #CCCAC2\">filter_map(</span><span style=\"color: #F29E74\">&amp;</span><span style=\"color: #D5FF80\">:max_rating</span><span style=\"color: #CCCAC2\">)</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  </span><span style=\"color: #FFAD66\">return</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #DFBFFF\">nil</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #FFAD66\">if</span><span style=\"color: #CCCAC2\"> ratings</span><span style=\"color: #CCCAC2B3\">.</span><span style=\"color: #CCCAC2\">empty?</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  ratings</span><span style=\"color: #CCCAC2B3\">.</span><span style=\"color: #CCCAC2\">sum </span><span style=\"color: #F29E74\">/</span><span style=\"color: #CCCAC2\"> ratings</span><span style=\"color: #CCCAC2B3\">.</span><span style=\"color: #CCCAC2\">size</span><span style=\"color: #CCCAC2B3\">.</span><span style=\"color: #CCCAC2\">to_f</span></span>\n<span class=\"line\"><span style=\"color: #FFAD66\">end</span></span>\n<span class=\"line\"></span></code></pre>\n<p>This is adapted from actual production code I had to work with recently. I didn't write the original, but I had to change it and wanted to make sure I didn't break anything. Thankfully, we have a test that ensures the method's behaviour, it simply has to … eh … hm … be correct!</p>\n<p>First of all: There are a bunch of different branches here, but only <em>one</em> test. Second of all: The test should, in plain terms, explain what we expect to happen.</p>\n<p>Imagine you're sitting down with a colleague, showing them your code, and they ask a question:</p>\n<p><strong>Colleague:</strong> Hey, what's <code>average_score</code> doing? <br>\n<strong>You:</strong> It's returning the correct average. <br>\n<strong>Colleague:</strong> <em>[backs away from your desk]</em></p>\n<p>No! That's unhinged!</p>\n<p><strong>Colleague:</strong> Hey, what's <code>average_score</code> doing? <br>\n<strong>You:</strong> It's returning the average of users' <code>max_rating</code>. <br>\n<strong>Colleague:</strong> Yeah, it totally does! <br>\n<strong>You:</strong> And actually, we only count public users. <br>\n<strong>Colleague:</strong> That's awesome!</p>\n<p>I want my tests to give the impression that the person who wrote them thought about what a human reading the tests probably wants to know. (Because I <em>do</em> think about that a lot!) To that end, I'd update the tests to look something like this:</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-rb\"><span class=\"line\"><span style=\"color: #CCCAC2\">describe </span><span style=\"color: #D5FF80\">&quot;#average_score&quot;</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  it </span><span style=\"color: #D5FF80\">&quot;returns average of users&#39; max_rating&quot;</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #FFAD66\">do</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">    </span><span style=\"color: #B8CFE680; font-style: italic\"># cool setup here ...</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">    expect(thing</span><span style=\"color: #CCCAC2B3\">.</span><span style=\"color: #CCCAC2\">average_score)</span><span style=\"color: #CCCAC2B3\">.</span><span style=\"color: #CCCAC2\">to eq(</span><span style=\"color: #DFBFFF\">4.2</span><span style=\"color: #CCCAC2\">)</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  </span><span style=\"color: #FFAD66\">end</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  it </span><span style=\"color: #D5FF80\">&quot;excludes users that are not public&quot;</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  it </span><span style=\"color: #D5FF80\">&quot;excludes users that don&#39;t have a max_rating&quot;</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  it </span><span style=\"color: #D5FF80\">&quot;returns nil if there are no ratings&quot;</span></span>\n<span class=\"line\"><span style=\"color: #FFAD66\">end</span></span>\n<span class=\"line\"></span></code></pre>\n<p>(I left out the test bodies for brevity, since they are not important to the point I'm trying to make.)</p>\n<p>Some might argue that this is basically just a code comment and that it's coupled too closely to the underlying code. If people want to know the behaviour of the code, they should &quot;simply&quot; read it. To that I say: Smell my shorts. Your tests deserve to be understandable to humans. Humans deserve to understand your tests.</p>\n<p>Here are some more example tests, adapted from real life, together with suggestions on rewriting their titles. Notice how the titles mention some nouns from their projects, but it's pretty much impossible to guess what the underlying logic is doing. &quot;Correctly&quot; is used as a placeholder for a real explanation, giving the impression that the title is somehow useful.</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-diff\"><span class=\"line\"><span style=\"color: #F27983\">- it &quot;returns the correct URLs&quot;</span></span>\n<span class=\"line\"><span style=\"color: #87D96C\">+ it &quot;returns URLs of visible items&quot;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #F27983\">- it &quot;strips the email address correctly&quot;</span></span>\n<span class=\"line\"><span style=\"color: #87D96C\">+ it &quot;strips spaces from the email address&quot;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #F27983\">- it &quot;returns correct number of items when given an infinite range&quot;</span></span>\n<span class=\"line\"><span style=\"color: #87D96C\">+ it &quot;returns all items after start of endless range&quot;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #F27983\">- it &quot;includes correct columns in csv&quot;</span></span>\n<span class=\"line\"><span style=\"color: #87D96C\">+ it &quot;includes &#39;id&#39;, &#39;name&#39;, &#39;sales&#39; columns in csv&quot;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #B8CFE680; font-style: italic\"># Same thing can happen with synonyms</span></span>\n<span class=\"line\"><span style=\"color: #B8CFE680; font-style: italic\"># of &quot;correct&quot;, like &quot;right&quot;:</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #F27983\">- it &quot;returns the right prices&quot;</span></span>\n<span class=\"line\"><span style=\"color: #87D96C\">+ it &quot;returns the prices plus taxes for customer&quot;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #F27983\">- it &quot;has the right slug format&quot;</span></span>\n<span class=\"line\"><span style=\"color: #87D96C\">+ it &quot;has slug in kebab case without umlauts&quot;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #F27983\">- it &quot;creates the right documents&quot;</span></span>\n<span class=\"line\"><span style=\"color: #87D96C\">+ it &quot;creates only the German tax documents&quot;</span></span>\n<span class=\"line\"></span></code></pre>\n<p>There is also the opposite case where &quot;correctly&quot; is not a placeholder for an explanation, but instead is contributing nothing. In these cases, you can skip it.</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-diff\"><span class=\"line\"><span style=\"color: #F27983\">- it &quot;correctly coerces string &#39;yes&#39; to true&quot; do</span></span>\n<span class=\"line\"><span style=\"color: #F27983\">- it &quot;correctly coerces numeric 1 to true&quot; do</span></span>\n<span class=\"line\"><span style=\"color: #87D96C\">+ it &quot;coerces &#39;yes&#39; to true&quot; do</span></span>\n<span class=\"line\"><span style=\"color: #87D96C\">+ it &quot;coerces 1 to true&quot; do</span></span>\n<span class=\"line\"></span></code></pre>\n<p>(Yes, thank you, I think I'll assume that the tests are already correct! It's actually a bit suspicious that you have to emphasise it this much.)</p>\n<p>I hope you'll think of this post when you write your next tests or when you do the next code review of tests somebody else wrote. Remember: Do the correct thing!</p>\n",
            "url": "https://diekmeier.de/posts/2024-08-01-stop-using-correct-in-test-titles/",
            "title": "Stop Using “Correct” in Test Titles",
            "date_modified": "2024-08-01T00:00:00.000Z"
        },
        {
            "id": "2024-07-31-rails-s3-connection",
            "content_html": "<p>Hello! Today, I had to switch out some AWS S3 credentials. We had them in <code>ENV</code> variables in Heroku, but we got new ones and are now saving them in the <code>credentials.yml.enc</code> file.</p>\n<p>After the deploy, I wanted to make sure the new credentials still work. Since we use the credentials for ActiveStorage, I went to the Rails Console on Heroku and entered this to download a &quot;random&quot; ActiveStorage file from S3:</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-rb\"><span class=\"line\"><span style=\"color: #5CCFE6\">ActiveStorage</span><span style=\"color: #CCCAC2B3\">::</span><span style=\"color: #5CCFE6\">Attachment</span><span style=\"color: #CCCAC2B3\">.</span><span style=\"color: #CCCAC2\">take</span><span style=\"color: #CCCAC2B3\">.</span><span style=\"color: #CCCAC2\">blob</span><span style=\"color: #CCCAC2B3\">.</span><span style=\"color: #CCCAC2\">download_chunk(</span><span style=\"color: #DFBFFF\">0</span><span style=\"color: #CCCAC2B3\">..</span><span style=\"color: #DFBFFF\">0</span><span style=\"color: #CCCAC2\">)</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2B3\">=&gt;</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">&quot;%&quot;</span></span>\n<span class=\"line\"></span></code></pre>\n<p>The <code>%</code> means: Success! (It also means that we only download the first byte of the file, since it's all we need to check the credentials.)</p>\n<p>If it didn't work, we'd get some kind of error instead:</p>\n<blockquote>\n<p>Aws::S3::Errors::SignatureDoesNotMatch: The request signature we calculated does not match the signature you provided. Check your key and signing method.</p>\n</blockquote>\n<p>Now you know!</p>\n",
            "url": "https://diekmeier.de/posts/2024-07-31-rails-s3-connection/",
            "title": "Tiny Rails Tipp: Check S3 Credentials",
            "date_modified": "2024-07-31T00:00:00.000Z"
        },
        {
            "id": "2023-11-06-streaming-files-from-sveltekit",
            "content_html": "<p><em>Disclaimer: I’m pretty sure this only applies if you use <code>@sveltejs/adapter-node</code>, because it’s using Node.js specific APIs.</em></p>\n<p>For <a href=\"https://eintrittskarten.io\">Eintrittskarten.io</a>, I wanted to build an endpoint which returns access controlled files. I didn’t want to load the complete files into RAM at once, instead I looked for a way to stream the files from the server to the client.</p>\n<p>SvelteKit does not have this “built in”, but I put the following code together and it seemed to work fine:</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-ts\"><span class=\"line\"><span style=\"color: #FFAD66\">import</span><span style=\"color: #CCCAC2\"> { Readable } </span><span style=\"color: #FFAD66\">from</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">&#39;node:stream&#39;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #FFAD66\">export</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #FFAD66\">async</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #FFAD66\">function</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #FFD173\">GET</span><span style=\"color: #CCCAC2\">(</span><span style=\"color: #DFBFFF\">{ params</span><span style=\"color: #CCCAC2B3\">,</span><span style=\"color: #DFBFFF\"> url</span><span style=\"color: #CCCAC2B3\">,</span><span style=\"color: #DFBFFF\"> locals }</span><span style=\"color: #CCCAC2\">) {</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  </span><span style=\"color: #FFAD66\">const</span><span style=\"color: #CCCAC2\"> filePath </span><span style=\"color: #F29E74\">=</span><span style=\"color: #CCCAC2\"> path</span><span style=\"color: #F29E74\">.</span><span style=\"color: #FFD173\">join</span><span style=\"color: #CCCAC2\">(MY_UPLOADS_PATH</span><span style=\"color: #CCCAC2B3\">,</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">`</span><span style=\"color: #FFAD66\">${</span><span style=\"color: #CCCAC2\">params</span><span style=\"color: #F29E74\">.</span><span style=\"color: #CCCAC2\">file</span><span style=\"color: #FFAD66\">}</span><span style=\"color: #D5FF80\">-</span><span style=\"color: #FFAD66\">${</span><span style=\"color: #CCCAC2\">template</span><span style=\"color: #FFAD66\">}</span><span style=\"color: #D5FF80\">.pdf`</span><span style=\"color: #CCCAC2\">)</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  </span><span style=\"color: #B8CFE680; font-style: italic\">// DO NOT COPY THIS INTO YOUR APP. READ ON.</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  </span><span style=\"color: #FFAD66\">const</span><span style=\"color: #CCCAC2\"> fileStream </span><span style=\"color: #F29E74\">=</span><span style=\"color: #CCCAC2\"> Readable</span><span style=\"color: #F29E74\">.</span><span style=\"color: #FFD173\">toWeb</span><span style=\"color: #CCCAC2\">((fs</span><span style=\"color: #F29E74\">.</span><span style=\"color: #FFD173\">createReadStream</span><span style=\"color: #CCCAC2\">(filePath))) </span><span style=\"color: #FFAD66\">as</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #73D0FF\">BodyInit</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  </span><span style=\"color: #FFAD66\">return</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #F29E74\">new</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #FFD173\">Response</span><span style=\"color: #CCCAC2\">(fileStream)</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">}</span></span>\n<span class=\"line\"></span></code></pre>\n<p>Create a good old Node.js ReadStream, use an (at the time of this writing) “experimental” function to transform it into another kind of Readable Stream, and send it off in the <code>Response</code>. Easy! Too easy!</p>\n<p>After deploying this, every now and then, I’d get this error delivered to my Sentry instance:</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-\"><span class=\"line\"><span style=\"color: #cccac2\">TypeError: Invalid state: Controller is already closed</span></span>\n<span class=\"line\"><span style=\"color: #cccac2\">  File &quot;node:internal/errors&quot;, line 406, col 5, in new NodeError</span></span>\n<span class=\"line\"><span style=\"color: #cccac2\">  File &quot;node:internal/webstreams/readablestream&quot;, line 1056, col 13, in ReadableStreamDefaultController.close</span></span>\n<span class=\"line\"><span style=\"color: #cccac2\">  File &quot;node:internal/webstreams/adapters&quot;, line 454, col 16, in ReadStream.&lt;anonymous&gt;</span></span>\n<span class=\"line\"><span style=\"color: #cccac2\">  File &quot;node:internal/util&quot;, line 531, col 12, in ReadStream.&lt;anonymous&gt;</span></span>\n<span class=\"line\"><span style=\"color: #cccac2\">  File &quot;node:internal/streams/end-of-stream&quot;, line 162, col 14, in ReadStream.onclose</span></span>\n<span class=\"line\"><span style=\"color: #cccac2\">  File &quot;node:events&quot;, line 514, col 28, in ReadStream.emit</span></span>\n<span class=\"line\"><span style=\"color: #cccac2\">  File &quot;node:domain&quot;, line 488, col 12, in ReadStream.emit</span></span>\n<span class=\"line\"><span style=\"color: #cccac2\">  File &quot;node:internal/streams/destroy&quot;, line 132, col 10, in emitCloseNT</span></span>\n<span class=\"line\"><span style=\"color: #cccac2\">  File &quot;node:internal/process/task_queues&quot;, line 81, col 21, in process.processTicksAndRejections</span></span>\n<span class=\"line\"><span style=\"color: #cccac2\"></span></span></code></pre>\n<p>I could not make sense of it. This error would of course be more helpful if my application code would be somewhere in there, but no luck.</p>\n<p>Googling for it brings me to (unrelated issues in) <a href=\"https://github.com/nodejs/undici/\">Undici</a>. Undici is the new HTTP client in Node.js, so I understand that it’s related to me trying to stream a file, but it’s completely unclear to me <em>why</em> this error is happening or what I could do to prevent it. I was also never able to reproduce the error locally.</p>\n<p>I <em>think</em> what is happening is that if a user stops the <code>Response</code> file download mid-stream (e.g. by closing the browser), the stream is closed once, but when the Node.js stream has read the whole file from disk, it tries to close the stream again – Leading to the error. But this is just a guess.</p>\n<p>Anyway, after clicking deeper and deeper into the Undici source code, I found a <s>terrible hack</s> nice convenience that you can/should use instead:</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-diff\"><span class=\"line\"><span style=\"color: #CCCAC2\"> import { Readable } from &#39;node:stream&#39;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\"> export async function GET({ params, url, locals }) {</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">   const filePath = path.join(MY_UPLOADS_PATH, `${params.file}-${template}.pdf`)</span></span>\n<span class=\"line\"><span style=\"color: #F27983\">-  const fileStream = Readable.toWeb((fs.createReadStream(filePath))) as BodyInit</span></span>\n<span class=\"line\"><span style=\"color: #87D96C\">+  const fileStream = fs.createReadStream(filePath) as unknown as BodyInit</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">   return new Response(fileStream)</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\"> }</span></span>\n<span class=\"line\"></span></code></pre>\n<p>You can pass a Node.js stream <em>directly</em> to <code>Response</code>, because Undici has a special case for this! (Even though this is not part of the spec for <code>Response</code>.)</p>\n<p><small>(Yes, I’m sorry about the <code>as unknown as BodyInit</code>, but it <em>does</em> work. Something is wrong with the types.)</small></p>\n<p><s>I haven't had the error pop up in Sentry even a single time since deploying this change. So, I guess by <em>using the platform</em>, SvelteKit <em>does</em> have streaming built in. Really makes you think!</s></p>\n<h3>Update, July 2025</h3>\n<p>Sadly, the error did not go away after all. It might have occured less often, and I think depending on the exact version of Node and Undici, it might not have occured at all for periods of time. But it always ended up coming back.</p>\n<p>But a few weeks ago, there was an exciting addition to Node.js. From the <a href=\"https://nodejs.org/en/blog/release/v22.17.0#-fsfilehandlereadablewebstream-gets-autoclose-option\">changelog for v22.17.0</a>:</p>\n<blockquote>\n<p><code>fs.FileHandle.readableWebStream</code> gets <code>autoClose</code> option</p>\n<p>This gives developers explicit control over whether the file descriptor should be closed when the stream ends. Helps avoid subtle resource leaks.</p>\n</blockquote>\n<p>Subtle resource leaks? When the stream ends? Like, idk, an invalid state when the controller is already closed? Are you seeing what I’m seeing? Here we go again:</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-diff\"><span class=\"line\"><span style=\"color: #CCCAC2\"> import { Readable } from &#39;node:stream&#39;</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\"> import fs from &#39;node:fs/promises&#39;</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\"> import path from &#39;node:path&#39;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\"> export async function GET({ params, url, locals }) {</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">   const filePath = path.join(MY_UPLOADS_PATH, `${params.file}-${template}.pdf`)</span></span>\n<span class=\"line\"><span style=\"color: #F27983\">-  const fileStream = fs.createReadStream(filePath) as unknown as BodyInit</span></span>\n<span class=\"line\"><span style=\"color: #87D96C\">+  const fileHandle = await fs.open(filePath)</span></span>\n<span class=\"line\"><span style=\"color: #87D96C\">+  // @ts-expect-error: @types/node doesn&#39;t know this yet</span></span>\n<span class=\"line\"><span style=\"color: #87D96C\">+  const fileStream = fileHandle.readableWebStream({ autoClose: true }) as BodyInit</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">   return new Response(fileStream)</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\"> }</span></span>\n<span class=\"line\"></span></code></pre>\n<p>Ever since deploying this a few weeks ago, the error has disappeared. Fingers crossed that it will stay away this time!</p>\n",
            "url": "https://diekmeier.de/posts/2023-11-06-streaming-files-from-sveltekit/",
            "title": "Streaming Files from SvelteKit",
            "date_modified": "2023-11-06T00:00:00.000Z"
        },
        {
            "id": "2023-05-07-finally-understanding-finally",
            "content_html": "<p>I've been writing JavaScript since around 1973, but I've never understood the point of the <code>finally</code> Keyword. The following two implementations of <code>coolFunction</code> are equivalent, so why bother with the additional curly braces?</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-js\"><span class=\"line\"><span style=\"color: #FFAD66\">function</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #FFD173\">coolFunction</span><span style=\"color: #CCCAC2\">() {</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  </span><span style=\"color: #FFAD66\">try</span><span style=\"color: #CCCAC2\"> {</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">    </span><span style=\"color: #FFD173\">thisFunctionThrows</span><span style=\"color: #CCCAC2\">()</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  } </span><span style=\"color: #FFAD66\">catch</span><span style=\"color: #CCCAC2\"> (error) {</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">    console</span><span style=\"color: #F29E74\">.</span><span style=\"color: #FFD173\">log</span><span style=\"color: #CCCAC2\">(</span><span style=\"color: #D5FF80\">&#39;whoops&#39;</span><span style=\"color: #CCCAC2\">)</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  } </span><span style=\"color: #FFAD66\">finally</span><span style=\"color: #CCCAC2\"> {</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">    console</span><span style=\"color: #F29E74\">.</span><span style=\"color: #FFD173\">log</span><span style=\"color: #CCCAC2\">(</span><span style=\"color: #D5FF80\">&#39;dont worry, i got u&#39;</span><span style=\"color: #CCCAC2\">)</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  }</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">}</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #FFAD66\">function</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #FFD173\">coolFunction</span><span style=\"color: #CCCAC2\">() {</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  </span><span style=\"color: #FFAD66\">try</span><span style=\"color: #CCCAC2\"> {</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">    </span><span style=\"color: #FFD173\">thisFunctionThrows</span><span style=\"color: #CCCAC2\">()</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  } </span><span style=\"color: #FFAD66\">catch</span><span style=\"color: #CCCAC2\"> (error) {</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">    console</span><span style=\"color: #F29E74\">.</span><span style=\"color: #FFD173\">log</span><span style=\"color: #CCCAC2\">(</span><span style=\"color: #D5FF80\">&#39;whoops&#39;</span><span style=\"color: #CCCAC2\">)</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  }</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  console</span><span style=\"color: #F29E74\">.</span><span style=\"color: #FFD173\">log</span><span style=\"color: #CCCAC2\">(</span><span style=\"color: #D5FF80\">&#39;dont worry, i got u&#39;</span><span style=\"color: #CCCAC2\">)</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">}</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #B8CFE680; font-style: italic\">// both of these print the same thing:</span></span>\n<span class=\"line\"><span style=\"color: #FFD173\">coolFunction</span><span style=\"color: #CCCAC2\">()</span></span>\n<span class=\"line\"><span style=\"color: #B8CFE680; font-style: italic\">// &#39;whoops&#39;</span></span>\n<span class=\"line\"><span style=\"color: #B8CFE680; font-style: italic\">// &#39;dont worry, i got u&#39;</span></span>\n<span class=\"line\"></span></code></pre>\n<p>What I didn't understand was that you can use it to run some other code in the last moment before leaving the function – for example if you want to return early or throw an error. This can come in handy when you need to clean up some other resources, no matter in which way you leave the function.</p>\n<p>While this can be extremely useful, <code>finally</code> is also not completely straightforward. For example, the order of execution gets a little weird. Consider this example, which surprised me:</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-js\"><span class=\"line\"><span style=\"color: #FFAD66\">function</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #FFD173\">hello</span><span style=\"color: #CCCAC2\">() {</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  </span><span style=\"color: #FFAD66\">try</span><span style=\"color: #CCCAC2\"> {</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">    console</span><span style=\"color: #F29E74\">.</span><span style=\"color: #FFD173\">log</span><span style=\"color: #CCCAC2\">(</span><span style=\"color: #D5FF80\">&#39;hello&#39;</span><span style=\"color: #CCCAC2\">)</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">    </span><span style=\"color: #FFAD66\">return</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">&#39;world&#39;</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  } </span><span style=\"color: #FFAD66\">finally</span><span style=\"color: #CCCAC2\"> {</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">    console</span><span style=\"color: #F29E74\">.</span><span style=\"color: #FFD173\">log</span><span style=\"color: #CCCAC2\">(</span><span style=\"color: #D5FF80\">&#39;finally&#39;</span><span style=\"color: #CCCAC2\">)</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  }</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">}</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">console</span><span style=\"color: #F29E74\">.</span><span style=\"color: #FFD173\">log</span><span style=\"color: #CCCAC2\">(</span><span style=\"color: #FFD173\">hello</span><span style=\"color: #CCCAC2\">())</span></span>\n<span class=\"line\"><span style=\"color: #B8CFE680; font-style: italic\">// &#39;hello&#39;</span></span>\n<span class=\"line\"><span style=\"color: #B8CFE680; font-style: italic\">// &#39;finally&#39;</span></span>\n<span class=\"line\"><span style=\"color: #B8CFE680; font-style: italic\">// &#39;world&#39;</span></span>\n<span class=\"line\"></span></code></pre>\n<p>And while I'm at it, this double-<code>return</code> also feels weird:</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-js\"><span class=\"line\"><span style=\"color: #FFAD66\">function</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #FFD173\">hello</span><span style=\"color: #CCCAC2\">() {</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  </span><span style=\"color: #FFAD66\">try</span><span style=\"color: #CCCAC2\"> {</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">    </span><span style=\"color: #FFAD66\">return</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">&quot;world&quot;</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  } </span><span style=\"color: #FFAD66\">finally</span><span style=\"color: #CCCAC2\"> {</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">    </span><span style=\"color: #FFAD66\">return</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">&quot;finally&quot;</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  }</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">}</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">console</span><span style=\"color: #F29E74\">.</span><span style=\"color: #FFD173\">log</span><span style=\"color: #CCCAC2\">(</span><span style=\"color: #FFD173\">hello</span><span style=\"color: #CCCAC2\">())</span></span>\n<span class=\"line\"><span style=\"color: #B8CFE680; font-style: italic\">// &#39;finally&#39;</span></span>\n<span class=\"line\"></span></code></pre>\n<p>Maybe don't overdo the esoteric stuff.</p>\n<h3>Time for a Practical Use Case</h3>\n<p>Here's an example from <a href=\"https://eintrittskarten.io\">Eintrittskarten.io</a> (edited for length and width) where we render a PDF from a URL:</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-js\"><span class=\"line\"><span style=\"color: #FFAD66\">async</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #FFAD66\">function</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #FFD173\">renderPDF</span><span style=\"color: #CCCAC2\">(</span><span style=\"color: #DFBFFF\">url</span><span style=\"color: #CCCAC2B3\">,</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #DFBFFF\">filePath</span><span style=\"color: #CCCAC2\">) {</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  </span><span style=\"color: #FFAD66\">const</span><span style=\"color: #CCCAC2\"> browser </span><span style=\"color: #F29E74\">=</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #FFAD66\">await</span><span style=\"color: #CCCAC2\"> puppeteer</span><span style=\"color: #F29E74\">.</span><span style=\"color: #FFD173\">launch</span><span style=\"color: #CCCAC2\">({ headless</span><span style=\"color: #CCCAC2B3\">:</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #DFBFFF\">true</span><span style=\"color: #CCCAC2\"> })</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  </span><span style=\"color: #FFAD66\">const</span><span style=\"color: #CCCAC2\"> page </span><span style=\"color: #F29E74\">=</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #FFAD66\">await</span><span style=\"color: #CCCAC2\"> browser</span><span style=\"color: #F29E74\">.</span><span style=\"color: #FFD173\">newPage</span><span style=\"color: #CCCAC2\">()</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  </span><span style=\"color: #FFAD66\">const</span><span style=\"color: #CCCAC2\"> response </span><span style=\"color: #F29E74\">=</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #FFAD66\">await</span><span style=\"color: #CCCAC2\"> page</span><span style=\"color: #F29E74\">.</span><span style=\"color: #FFD173\">goto</span><span style=\"color: #CCCAC2\">(url)</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  </span><span style=\"color: #FFAD66\">await</span><span style=\"color: #CCCAC2\"> page</span><span style=\"color: #F29E74\">.</span><span style=\"color: #FFD173\">pdf</span><span style=\"color: #CCCAC2\">({ path</span><span style=\"color: #CCCAC2B3\">:</span><span style=\"color: #CCCAC2\"> filePath })</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  </span><span style=\"color: #FFAD66\">await</span><span style=\"color: #CCCAC2\"> browser</span><span style=\"color: #F29E74\">.</span><span style=\"color: #FFD173\">close</span><span style=\"color: #CCCAC2\">()</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">}</span></span>\n<span class=\"line\"></span></code></pre>\n<p>Rendering PDFs from URLs is a thankless job. In the past, we've accidentally sent automated emails where we had attached a PDF of our webapp showing an error message. (I actually find this hilarious.) To protect us from these mistakes in the future, we added a check that throws an error if we don't get a response from the server, or if the HTTP status is not <code>200</code>.</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-diff\"><span class=\"line\"><span style=\"color: #CCCAC2\">async function renderPDF(url, filePath) {</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  const browser = await puppeteer.launch({ headless: true })</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  const page = await browser.newPage()</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  const response = await page.goto(url)</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #87D96C\">+ if (!response) {</span></span>\n<span class=\"line\"><span style=\"color: #87D96C\">+   throw new Error(`PDF Renderer: No response from ${url}`)</span></span>\n<span class=\"line\"><span style=\"color: #87D96C\">+ }</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #87D96C\">+ if (response.status() !== 200) {</span></span>\n<span class=\"line\"><span style=\"color: #87D96C\">+   throw new Error(</span></span>\n<span class=\"line\"><span style=\"color: #87D96C\">+     `PDF Renderer: Expected page status to be 200, ` +</span></span>\n<span class=\"line\"><span style=\"color: #87D96C\">+     `was ${response.status()} for ${url}`</span></span>\n<span class=\"line\"><span style=\"color: #87D96C\">+   )</span></span>\n<span class=\"line\"><span style=\"color: #87D96C\">+ }</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  await page.pdf({ path: filePath })</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  await browser.close()</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">}</span></span>\n<span class=\"line\"></span></code></pre>\n<p>But sadly, bugs are often fractal, so while this check <em>does</em> save us from sending incorrect PDFs to customers, it introduces a new bug: <strong>Whenever we throw an error, the browser we start with <code>puppeteer.launch(...)</code> does not get closed</strong>. This can be a problem if your server does not have infinite RAM or is expected to work. Sadly, both of these are true for us.</p>\n<p>Combined with automatic retry in the case of errors, I built a magnificent machine that crashes itself whenever there is a problem with the PDFs. Annoyingly, this bug only surfaced while I was at a ramen restaurant, trying to enjoy a nice bowl of Tantan Ramen while rebooting the server from my iPhone.</p>\n<p>This is when the usefulness of <code>finally</code> finally dawned on me. This is the perfect use case: I want to make sure that I close the browser, but I also want to be able to <code>throw</code> errors if something goes wrong!</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-diff\"><span class=\"line\"><span style=\"color: #CCCAC2\">async function renderPDF(url, filePath) {</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  const browser = await puppeteer.launch({ headless: true })</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #87D96C\">+ try {</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">    const page = await browser.newPage()</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">    const response = await page.goto(url)</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">    if (!response) {</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">      throw new Error(`PDF Renderer: No response from ${url}`)</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">    }</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">    if (response.status() !== 200) {</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">      throw new Error(</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">        `PDF Renderer: Expected page status to be 200, ` +</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">        `was ${response.status()} for ${url}`</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">      )</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">    }</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">    await page.pdf({ path: filePath })</span></span>\n<span class=\"line\"><span style=\"color: #87D96C\">+ } finally {</span></span>\n<span class=\"line\"><span style=\"color: #87D96C\">+   // We have to close the browser or it will</span></span>\n<span class=\"line\"><span style=\"color: #87D96C\">+   // keep running in the background.</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">    await browser.close()</span></span>\n<span class=\"line\"><span style=\"color: #87D96C\">+ }</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">}</span></span>\n<span class=\"line\"></span></code></pre>\n<p>In my local testing, this worked great. (Thankfully, the bug was very reproducible, so I'm pretty confident I fixed it.) This feels pretty good! I'm excited to find out which even tinyer bug hides in the new code, but I'll be ready whenever it shows itself.</p>\n",
            "url": "https://diekmeier.de/posts/2023-05-07-finally-understanding-finally/",
            "title": "Finally Understanding `finally` in JavaScript",
            "date_modified": "2023-05-07T00:00:00.000Z"
        },
        {
            "id": "2023-05-05-nodejs-test-runner",
            "content_html": "<p><strong>TL;DR</strong>: I converted four old Node.js projects to use the brand new <a href=\"https://nodejs.org/api/test.html\">built in test runner</a>. This removed hundreds of dependencies and will make it easier to maintain these projects in the future.</p>\n<p>I own a few <a href=\"https://www.npmjs.com/~danieldiekmeier\">npm packages</a> that basically nobody uses. Despite this fact, Github sends me a lot of Dependabot alerts about critical security problems in some ancient version of <code>minimist</code> in a dependency of a dev dependency of a package I barely use.</p>\n<p>I don't really care. This adds a lot of noise to my Github life and makes me more likely to miss <em>important</em> alerts. I already turned off Dependabot Alerts for a lot of old projects – especially if I don't use them myself.</p>\n<p>Also, I'm currently reading <a href=\"https://sustainable-rails.com/\">Sustainable Web Development with Ruby on Rails</a> by David Bryant Copeland. A big topic is the <em>carrying cost</em> of decisions you make while building your projects. (The book is very insightful and I recommend reading it.)</p>\n<p>A carrying cost in this case is additional work you have to put in while trying to work on the project. For example, updating dependencies when they stop working or have security problems. Or fixing tests that break because of a change in a dependency. This is closely related to technical debt, but not quite the same. Technical debt is like paying of a loan you took out in the past. Carrying costs are more like the rent you pay for the house you live in.</p>\n<p>One of my takeaways from the book is that whenever possible, <strong>you should try to make decisions that reduce the carrying cost of your project.</strong></p>\n<p>While not <em>enormous</em>, the carrying cost of my old Node.js projects is also not <em>zero</em>. I have to deal with Dependabot alerts, and I have to make sure that the tests still run.</p>\n<p>Thankfully, the stars have finally aligned to make this a bit easier: Node.js v20 has <a href=\"https://nodejs.org/en/blog/announcements/v20-release-announce#stable-test-runner\">just been released</a>, and with it, Node.js now has a stable built in test runner: <code>node:test</code>.</p>\n<p>I think this is great news. In my older packages, I often installed the <a href=\"https://github.com/avajs/ava\">Ava test runner</a>. This pulled in about 300 gazillion transitive dependencies, which, down the line, would get marked as terrible security problems by Dependabot. With the new <code>node:test</code> module, I was able to remove this dependency completely.</p>\n<p>The changes boiled down to this:</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-diff\"><span class=\"line\"><span style=\"color: #B8CFE680; font-style: italic\"># Switching from ava to node:test</span></span>\n<span class=\"line\"><span style=\"color: #F27983\">- import test from &#39;ava&#39;</span></span>\n<span class=\"line\"><span style=\"color: #87D96C\">+ import { test } from &#39;node:test&#39;</span></span>\n<span class=\"line\"><span style=\"color: #87D96C\">+ import assert from &#39;node:assert&#39;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #B8CFE680; font-style: italic\"># Switching from t.is to assert.strictEqual</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  test(&#39;converts to string&#39;, (t) =&gt; {</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">   const result = Spoons.convert(1)</span></span>\n<span class=\"line\"><span style=\"color: #F27983\">-  t.is(result, &#39;1 tsp&#39;)</span></span>\n<span class=\"line\"><span style=\"color: #87D96C\">+  assert.strictEqual(result, &#39;1 tsp&#39;)</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  }</span></span>\n<span class=\"line\"></span></code></pre>\n<p>And running the tests is now as easy as <code>node --test</code>.</p>\n<p>So, over the course of the weekend, I dusted off four old projects and migrated them to modern alternatives.</p>\n<ul>\n<li><strong><code>@danieldiekmeier/async-worker</code></strong>: I converted the project to ESM and removed all dependencies. <a href=\"https://github.com/danieldiekmeier/async-worker/commit/8b2433796a9c6b126494c1007463425aee3d41c0\">Commit <code>8b24337</code></a>, +40/-4,468 lines</li>\n<li><strong><code>todo-or-die</code></strong>: I converted the project to ESM and removed all dependencies. <a href=\"https://github.com/danieldiekmeier/todo-or-die/commit/2e6b9488de311a1c86b2972ed73dbf98356e77f3\">Commit <code>2e6b948</code></a>, +39/-4,588 lines</li>\n<li><a href=\"https://danieldiekmeier.de/salt/\"><strong>Salt Bae</strong></a>: I switched from Parcel to SvelteKit and from Ava to the built in test runner. <a href=\"https://github.com/danieldiekmeier/salt-bae/commit/d986fa03aca0be2b393f8c4c31870b9ae4e48461\">Commit <code>d986fa0</code></a> +671/-5,956 lines, <a href=\"https://github.com/danieldiekmeier/salt-bae/commit/3b4eb4be9332145f08114db5d752198eacf63c17\"><code>3b4eb4b</code></a>, +5,987/-8600 lines</li>\n<li><a href=\"https://spotify.danieldiekmeier.de\"><strong>Spotify Latest Releases</strong></a>: I switched from Vue, Koa and Webpack to SvelteKit. I moved from axios to native fetch and from moment.js to plain <code>Date</code>. <a href=\"https://github.com/danieldiekmeier/spotify-latest-releases/commit/5100758818e470f5aae63d030bd4de1e49c7951e\">Commit <code>5100758</code></a>, +1,330/-5,011 lines</li>\n</ul>\n<p>Most of these deletions (around 20,000 lines!) stem from <code>package-lock.json</code> files (or equivalent files from <code>yarn</code> or <code>pnpm</code>). This is amazing! This means that I probably have hundreds, if not thousands of dependencies less than when I started.</p>\n<p>I don't know what the future will bring, but I'm <em>pretty sure</em> that I will have to do less work to keep these projects running. If you have small Node.js projects that don't benefit from dedicated test runners, I recommend you give <code>node:test</code> a try.</p>\n",
            "url": "https://diekmeier.de/posts/2023-05-05-nodejs-test-runner/",
            "title": "Using the Built In Test Runner to make Node.js projects more sustainable",
            "date_modified": "2023-05-05T00:00:00.000Z"
        },
        {
            "id": "2023-03-19-many-to-many-rails",
            "content_html": "<p>A few weeks ago, I had to implement a Label feature. Picture Github’s labels for Issues and Pull Requests:</p>\n<img src=\"/_app/immutable/assets/github-labels.DZTSXtlO.png\" alt=\"Github Labels\" width=\"356\" height=\"600\" />\n<p>This is a classic many-to-many relationship: A label can be assigned to many issues, and an issue can have many labels.</p>\n<p>For this project, we use Rails, so I created a <code>Label</code> model and connected it to our existing <code>Issue</code> model with <code>has_and_belongs_to_many</code>:</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-ruby\"><span class=\"line\"><span style=\"color: #FFAD66\">class</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #73D0FF\">Label</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #F29E74\">&lt;</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #5CCFE6\">ApplicationRecord</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  has_and_belongs_to_many </span><span style=\"color: #D5FF80\">:issues</span></span>\n<span class=\"line\"><span style=\"color: #FFAD66\">end</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #FFAD66\">class</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #73D0FF\">Issue</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #F29E74\">&lt;</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #5CCFE6\">ApplicationRecord</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  has_and_belongs_to_many </span><span style=\"color: #D5FF80\">:labels</span></span>\n<span class=\"line\"><span style=\"color: #FFAD66\">end</span></span>\n<span class=\"line\"></span></code></pre>\n<p>This worked fine to create the many-to-many relationship I was after. I implemented the UI and was ready to call it a day.</p>\n<p>I’m not sure how I missed it for so long, but I finally noticed that RuboCop complained about the <code>has_and_belongs_to_many</code>. According to the rule <a href=\"https://www.rubydoc.info/gems/rubocop/0.58.1/RuboCop/Cop/Rails/HasAndBelongsToMany\">Rails/HasAndBelongsToMany</a>, you should <em>never</em> use it and <em>always</em> prefer <code>has_many ... through</code>.</p>\n<p>I found that surprising! The rule itself does not explain a reason, so I looked around and found a few answers <a href=\"https://stackoverflow.com/questions/2780798/has-and-belongs-to-many-vs-has-many-through\">here on StackOverflow</a>.</p>\n<p>In most cases, people were concerned that <code>has_many :through</code> will probably be needed <em>everywhere</em> at some point, which makes it the future-proof choice:</p>\n<blockquote>\n<p>You should use <code>has_many :through</code> if you need validations, callbacks, or extra attributes on the join model.</p>\n</blockquote>\n<blockquote>\n<p>From my experience it's always better to use <code>has_many :through</code> because you can add timestamps to the table.</p>\n</blockquote>\n<blockquote>\n<p>If you decided to use <code>has_and_belongs_to_many</code>, and want to add one simple datapoint or validation 2 years down the road, migrating this change will be extremely difficult and bug-prone. To be safe, default to <code>has_many :through</code></p>\n</blockquote>\n<p>While writing this post, I found the corresponding entry in the <a href=\"https://rails.rubystyle.guide/#has-many-through\">Rails Style Guide</a>, which indeed explains:</p>\n<blockquote>\n<p>Using has_many :through allows additional attributes and validations on the join model.</p>\n</blockquote>\n<p>For myself, I ended up with the following conclusion: I you <em>ever</em> want to talk about the relationship itself (and you probably will!), you should use <code>has_many :through</code>. I expect this will even help me outside of Rails, because many-to-many relationships are a common pattern in many projects.</p>\n<p>I rewrote my code to <code>has_many :through</code> and it was no problem – especially because RuboCop helped me to catch this so early. I even ended up adding timestamps to the join table, which wouldn’t have been possible with <code>has_and_belongs_to_many</code>.</p>\n",
            "url": "https://diekmeier.de/posts/2023-03-19-many-to-many-rails/",
            "title": "Why does RuboCop want me to use `has_many :through` instead of `has_and_belongs_to_many`?",
            "date_modified": "2023-03-19T00:00:00.000Z"
        },
        {
            "id": "2023-02-19-deploying-sveltekit-on-uberspace",
            "content_html": "<p>This blog is built with <a href=\"https://kit.svelte.dev/\">SvelteKit</a> and their <a href=\"https://kit.svelte.dev/docs/adapter-static\">Static Adapter</a>. Running <code>npm run build</code> gives me a bunch of what we in the business call: “files”. Now I just need to upload them somewhere.</p>\n<p><a href=\"https://uberspace.de/en/\">Uberspace</a> is my favourite web host. I’ve been using them since 2012! The <a href=\"https://lesetagebu.ch\">Lesetagebuch</a> has been running on Uberspace since 2013. They taught me to use the command line before I ever thought about becoming a software developer. Give them a try!</p>\n<p>Over the years, they have made it incredibly easy to deploy a website – Especially if the website only consists of some static files.</p>\n<p>Nevertheless, there were a few things I had to figure out, and now I’m telling you about them!</p>\n<h3>Always add trailing slashes</h3>\n<p>When I first deployed the site, I could open the root <code>https://diekmeier.de</code>, but none of the articles. I could <em>navigate</em> to the articles from the root, thanks to SvelteKit’s client side navigation, but that was it. If I tried to open the URLs directly, I got a “Permission Denied” error.</p>\n<p>Thank god this is not my first rodeo. After looking into the build output, I noticed how the different pages were saved in the form <code>/posts/example.html</code>. I’d assumed they’d be saved as <code>/posts/example/index.html</code>. Indeed, with this hint, I found the relevant part of documentation:</p>\n<blockquote>\n<p>You must ensure SvelteKit's <code>trailingSlash</code> option is set appropriately for your environment. If your host does not render <code>/a.html</code> upon receiving a request for <code>/a</code> then you will need to set <code>trailingSlash: 'always'</code> to create <code>/a/index.html</code> instead.</p>\n</blockquote>\n<p>That’s exactly what I did, and everything started working immediately.</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-ts\"><span class=\"line\"><span style=\"color: #B8CFE680; font-style: italic\">// +layout.ts</span></span>\n<span class=\"line\"><span style=\"color: #FFAD66\">export</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #FFAD66\">const</span><span style=\"color: #CCCAC2\"> prerender </span><span style=\"color: #F29E74\">=</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #DFBFFF\">true</span><span style=\"color: #CCCAC2B3\">;</span></span>\n<span class=\"line\"><span style=\"color: #FFAD66\">export</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #FFAD66\">const</span><span style=\"color: #CCCAC2\"> trailingSlash </span><span style=\"color: #F29E74\">=</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">&#39;always&#39;</span><span style=\"color: #CCCAC2B3\">;</span></span>\n<span class=\"line\"></span></code></pre>\n<h3>Don’t forget your cache headers</h3>\n<p>I have a habit of running most of the sites that I manage through Lighthouse every now and again. (Probably a little too often.) After deploying the first version of this blog, Lighthouse was <em>furious</em> about missing cache headers on all my files.</p>\n<p>Luckily, both SvelteKit and Uberspace are prepared for this. SvelteKit actually produces a dedicated <code>immutable</code> folder that contains most assets and generated files. Fittingly, Uberspace makes it incredibly easy to add custom headers for any path:</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-sh\"><span class=\"line\"><span style=\"color: #73D0FF\">$</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">uberspace</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">web</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">header</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">set</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">diekmeier.de/_app/immutable</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #95E6CB\">\\</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">    </span><span style=\"color: #D5FF80\">Cache-Control</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">&quot;max-age=31536000&quot;</span></span>\n<span class=\"line\"></span></code></pre>\n<p>With this small change, all my <code>immutable</code> assets are cached for a year!</p>\n<h3>Automatic™ Deployment</h3>\n<p>I don’t need a Deployment Pipeline for a <em>blog</em>. I can execute a script, like it’s the 80s! The script builds the static files, and then uses rsync to yeet them onto my server. I <em>love</em> rsync. It is one of those tools in my toolbelt that becomes useful again and again and again.</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-sh\"><span class=\"line\"><span style=\"color: #B8CFE680; font-style: italic\"># scripts/sync.sh</span></span>\n<span class=\"line\"><span style=\"color: #73D0FF\">npm</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">run</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">build</span></span>\n<span class=\"line\"><span style=\"color: #73D0FF\">rsync</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #95E6CB\">--verbose</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #95E6CB\">--recursive</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #95E6CB\">--delete</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #95E6CB\">-e</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">ssh</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">./build/</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">danjel7@diekmeier.de:/var/www/virtual/danjel7/diekmeier.de</span></span>\n<span class=\"line\"></span></code></pre>\n<p>If I <code>time</code> this, it runs in just under 5 seconds:</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-sh\"><span class=\"line\"><span style=\"color: #73D0FF\">$</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">time</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">scripts/sync.sh</span></span>\n<span class=\"line\"><span style=\"color: #B8CFE680; font-style: italic\"># lots of output later</span></span>\n<span class=\"line\"><span style=\"color: #73D0FF\">scripts/sync.sh</span><span style=\"color: #CCCAC2\">  </span><span style=\"color: #DFBFFF\">5.42</span><span style=\"color: #D5FF80\">s</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">user</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #DFBFFF\">0.58</span><span style=\"color: #D5FF80\">s</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">system</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #DFBFFF\">128</span><span style=\"color: #D5FF80\">%</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">cpu</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #DFBFFF\">4.665</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">total</span></span>\n<span class=\"line\"></span></code></pre>\n<p>Not bad!</p>\n",
            "url": "https://diekmeier.de/posts/2023-02-19-deploying-sveltekit-on-uberspace/",
            "title": "Deploying SvelteKit on Uberspace",
            "date_modified": "2023-02-19T00:00:00.000Z"
        },
        {
            "id": "2023-02-18-check-all-your-rails-routes",
            "content_html": "<p>I think sometimes it’s a good idea to make broad, sweeping checks across your whole application. Sometimes, you want to say categorically: “This is the way we do things. Time to draw an RSpec shaped line in the sand.”</p>\n<p>At work, I recently stumbled across a test case that was hidden deep inside an integration test, which looked like this:</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-rb\"><span class=\"line\"><span style=\"color: #B8CFE680; font-style: italic\"># hundreds of lines above</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">it </span><span style=\"color: #D5FF80\">&quot;does not include umlauts&quot;</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #FFAD66\">do</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  expect(confirmation_path </span><span style=\"color: #F29E74\">=~</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #5CCFE6\">URI</span><span style=\"color: #CCCAC2B3\">::</span><span style=\"color: #CCCAC2\">UNSAFE)</span><span style=\"color: #CCCAC2B3\">.</span><span style=\"color: #CCCAC2\">to be_nil</span></span>\n<span class=\"line\"><span style=\"color: #FFAD66\">end</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #B8CFE680; font-style: italic\"># hundreds of lines below</span></span>\n<span class=\"line\"></span></code></pre>\n<p>This had a <s>good</s> historic reason: The path in question is <code>/bestaetigen</code> (the german word for “confirm”)\nand, very much on purpose, does not include an <code>ä</code> (even though that would be theoretically possible).</p>\n<p>Someone <em>almost</em> changed it to <code>/bestätigen</code> once, but stopped at the last second because nobody was sure if this would work with our external CRM, HubSpot. Maybe the CRM doesn’t support umlauts? Maybe some other part of our system doesn’t? Who knows?</p>\n<p>In any case, the developer decided to revert the change and to cement this decision with a test: This special URL should never contain an umlaut.</p>\n<p>This is not a bad idea, but personally, I feel it’s a bit short sighted. If we’re afraid of this change, then we should probably also be afraid for <em>all</em> our paths!</p>\n<p>I decided to delete the test case and add a new file:</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-rb\"><span class=\"line\"><span style=\"color: #B8CFE680; font-style: italic\"># spec/routing/route_path_naming_spec.rb</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #FFAD66\">require</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">&quot;rails_helper&quot;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">describe </span><span style=\"color: #D5FF80\">&quot;list of all paths&quot;</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #FFAD66\">do</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  it </span><span style=\"color: #D5FF80\">&quot;does not contain characters that need to be escaped&quot;</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #FFAD66\">do</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">    </span><span style=\"color: #B8CFE680; font-style: italic\"># Get an array of all paths in the whole Rails app.</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">    </span><span style=\"color: #B8CFE680; font-style: italic\"># No, `.routes.routes` is not a typo. 🙃</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">    paths </span><span style=\"color: #F29E74\">=</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #5CCFE6\">Rails</span><span style=\"color: #CCCAC2B3\">.</span><span style=\"color: #CCCAC2\">application</span><span style=\"color: #CCCAC2B3\">.</span><span style=\"color: #CCCAC2\">routes</span><span style=\"color: #CCCAC2B3\">.</span><span style=\"color: #CCCAC2\">routes</span><span style=\"color: #CCCAC2B3\">.</span><span style=\"color: #CCCAC2\">map </span><span style=\"color: #FFAD66\">do</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #CCCAC2B3\">|</span><span style=\"color: #CCCAC2\">route</span><span style=\"color: #CCCAC2B3\">|</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">      route</span><span style=\"color: #CCCAC2B3\">.</span><span style=\"color: #CCCAC2\">path</span><span style=\"color: #CCCAC2B3\">.</span><span style=\"color: #CCCAC2\">spec</span><span style=\"color: #CCCAC2B3\">.</span><span style=\"color: #CCCAC2\">to_s</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">    </span><span style=\"color: #FFAD66\">end</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">    paths</span><span style=\"color: #CCCAC2B3\">.</span><span style=\"color: #CCCAC2\">each </span><span style=\"color: #FFAD66\">do</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #CCCAC2B3\">|</span><span style=\"color: #CCCAC2\">path</span><span style=\"color: #CCCAC2B3\">|</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">      expect(path)</span><span style=\"color: #CCCAC2B3\">.</span><span style=\"color: #CCCAC2\">not_to match(</span><span style=\"color: #5CCFE6\">URI</span><span style=\"color: #CCCAC2B3\">::</span><span style=\"color: #CCCAC2\">UNSAFE)</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">    </span><span style=\"color: #FFAD66\">end</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  </span><span style=\"color: #FFAD66\">end</span></span>\n<span class=\"line\"><span style=\"color: #FFAD66\">end</span></span>\n<span class=\"line\"></span></code></pre>\n<p>This spec runs through all our static routes in milliseconds. It even found two offenders that had slipped through, which was fun.</p>\n<p>I’m really happy with how this turned out. I think there is value in specs that assert something about the system as a whole.</p>\n<p>“We don’t use umlauts in paths“ could have been a rule in the <code>README.md</code>, or a sentence in a long forgotten Confluence document. But now, it’s part of the app and will always be enforced. This is a kind of automation I really enjoy.</p>\n",
            "url": "https://diekmeier.de/posts/2023-02-18-check-all-your-rails-routes/",
            "title": "Check all your Rails Routes at once",
            "date_modified": "2023-02-18T00:00:00.000Z"
        },
        {
            "id": "2023-01-04-git-reset-soft",
            "content_html": "<p>At work, I switch between different Git branches all the time. Often, I’m working on a larger feature, but need to switch to some other branches for some quick fixes or because I’m reviewing someone elses code.</p>\n<p>When I do that, I want to save my progress to the current branch.</p>\n<p>I know, I know: I could use <code>git stash</code> for this, but I don’t really like it. It feels like throwing all your clothes on that chair in the corner of your room, hoping that you’ll find them again when you need them.</p>\n<p>Instead, I got into the habit of committing all my changes to the current branch as a <code>WIP</code> commit.</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-sh\"><span class=\"line\"><span style=\"color: #73D0FF\">git</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">add</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">.</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #CCCAC2B3\">&amp;&amp;</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #73D0FF\">git</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">commit</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #95E6CB\">-m</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">&quot;WIP&quot;</span></span>\n<span class=\"line\"></span></code></pre>\n<p>⚠️ <strong>Note:</strong> Don’t push this to the remote repository! It’s just a temporary commit to save your current progress.</p>\n<p>This way, I can easily switch to another branch, do whatever needs to be done, and then bring back my changes:</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-sh\"><span class=\"line\"><span style=\"color: #73D0FF\">git</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">reset</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #95E6CB\">--soft</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">&quot;HEAD^&quot;</span></span>\n<span class=\"line\"></span></code></pre>\n<p>By using <code>--soft</code> here, we bring back the changes to the working directory, and with <code>&quot;HEAD^&quot;</code>, we only undo the last commit.</p>\n<hr>\n<p><strong>Update, February 18, 2023</strong></p>\n<p><a href=\"https://timomeh.de/\">Timo</a> saw this post and created a <a href=\"https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases\">Git Alias</a> so he can easily WIP and un-WIP his changes:</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-sh\"><span class=\"line\"><span style=\"color: #73D0FF\">wip</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">=</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">!&quot;[[ $(</span><span style=\"color: #73D0FF\">git</span><span style=\"color: #D5FF80\"> log </span><span style=\"color: #95E6CB\">-1</span><span style=\"color: #D5FF80\"> </span><span style=\"color: #95E6CB\">--pretty=%B</span><span style=\"color: #D5FF80\">) == </span><span style=\"color: #95E6CB\">\\&quot;</span><span style=\"color: #D5FF80\">WIP</span><span style=\"color: #95E6CB\">\\&quot;</span><span style=\"color: #D5FF80\"> ]] &amp;&amp; (git reset --soft </span><span style=\"color: #95E6CB\">\\&quot;</span><span style=\"color: #D5FF80\">HEAD^</span><span style=\"color: #95E6CB\">\\&quot;</span><span style=\"color: #D5FF80\">) || (git add . &amp;&amp; git commit -m </span><span style=\"color: #95E6CB\">\\&quot;</span><span style=\"color: #D5FF80\">WIP</span><span style=\"color: #95E6CB\">\\&quot;</span><span style=\"color: #D5FF80\">)&quot;</span></span>\n<span class=\"line\"></span></code></pre>\n<p>At first glance, this seemed like magic outside my comfort zone (when I see <code>[[</code> in bash, I’m out), but it merely checks whether your latest commit was already called <code>WIP</code>. If it was, it does the soft reset, otherwise it creates the commit. So you can use <code>git wip</code> to toggle between the two states.</p>\n<p>Personally, I am not a big fan of toggling, so I adapted his idea into two different aliased commands:</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-sh\"><span class=\"line\"><span style=\"color: #73D0FF\">wip</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">=</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">!&quot;git add . &amp;&amp; git commit -m </span><span style=\"color: #95E6CB\">\\&quot;</span><span style=\"color: #D5FF80\">WIP</span><span style=\"color: #95E6CB\">\\&quot;</span><span style=\"color: #D5FF80\">&quot;</span></span>\n<span class=\"line\"><span style=\"color: #73D0FF\">unwip</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">=</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">!&quot;git reset --soft </span><span style=\"color: #95E6CB\">\\&quot;</span><span style=\"color: #D5FF80\">HEAD^</span><span style=\"color: #95E6CB\">\\&quot;</span><span style=\"color: #D5FF80\"> &amp;&amp; git status --short&quot;</span></span>\n<span class=\"line\"></span></code></pre>\n<p>Through the <code>git status</code>, I can even see what my working directory looks like after un-WIPping:</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-sh\"><span class=\"line\"><span style=\"color: #73D0FF\">$</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">git</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">wip</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">[main </span><span style=\"color: #DFBFFF\">2836</span><span style=\"color: #CCCAC2\">fcf] WIP</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\"> </span><span style=\"color: #73D0FF\">2</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">files</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">changed,</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #DFBFFF\">12</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">insertions</span><span style=\"color: #CCCAC2\">(</span><span style=\"color: #73D0FF\">+</span><span style=\"color: #CCCAC2\">)</span><span style=\"color: #D5FF80\">,</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #DFBFFF\">37</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">deletions</span><span style=\"color: #CCCAC2\">(</span><span style=\"color: #73D0FF\">-</span><span style=\"color: #CCCAC2\">)</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #73D0FF\">$</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">git</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">unwip</span></span>\n<span class=\"line\"><span style=\"color: #73D0FF\">M</span><span style=\"color: #CCCAC2\">  </span><span style=\"color: #D5FF80\">README.md</span></span>\n<span class=\"line\"><span style=\"color: #73D0FF\">M</span><span style=\"color: #CCCAC2\">  </span><span style=\"color: #D5FF80\">src/posts/2023-01-04-git-reset-soft/post.md</span></span>\n<span class=\"line\"></span></code></pre>\n",
            "url": "https://diekmeier.de/posts/2023-01-04-git-reset-soft/",
            "title": "Undo your last commit with `git reset --soft \"HEAD^\"` for a better™ stash workflow",
            "date_modified": "2023-01-04T00:00:00.000Z"
        },
        {
            "id": "2023-01-03-npm-diff",
            "content_html": "<p>I need to tell you about a cool tool that I found: It’s <a href=\"https://github.com/juliangruber/npm-diff\"><code>npm-diff</code> by Julian Gruber</a>.</p>\n<p>At work, we use <a href=\"https://depfu.com/\">Depfu</a> to keep our dependencies up to date. (I guess we could also use Dependabot? But somehow Depfu seems to be a little bit less annoying? I'm actually not sure!)</p>\n<p>Anyway. Depfu creates a pull request for each new version of your dependencies. More importantly (for this blog post), it also tries to show you the changelog. But sometimes, the changelog is not very helpful. Often, Depfu can't actually find it – this happens often if the dependency is part of a monorepo, or if it moved, or if Depfu just doesn't feel well. In other cases, the changelog just contains a list of commits, which is very noisy and hard to understand.</p>\n<p>The <a href=\"https://github.com/googleapis/google-api-ruby-client\">Google API Ruby Client</a> is especially bad at this. The Changelog only says that the API Client was <a href=\"https://github.com/googleapis/google-api-ruby-client/blob/f8453440f7d395356e46b91008f1bb0a3056d6d6/generated/google-apis-drive_v3/CHANGELOG.md\">automatically regenerated</a>.</p>\n<p>Wouldn't it be nice if we could see the actual changes in the new version?</p>\n<p>An example is probably worth a thousand words. This command shows the changes between the <code>4.1.3</code> and <code>4.1.4</code> versions of the <code>@splidejs/splide</code> package:</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-sh\"><span class=\"line\"><span style=\"color: #73D0FF\">npx</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">npm-diff</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">@splidejs/splide</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #DFBFFF\">4.1</span><span style=\"color: #D5FF80\">.3</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #DFBFFF\">4.1</span><span style=\"color: #D5FF80\">.4</span></span>\n<span class=\"line\"></span></code></pre>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-diff\"><span class=\"line\"><span style=\"color: #C594C5\">--- 4.1.3/package.json\t1985-10-26 09:15:00</span></span>\n<span class=\"line\"><span style=\"color: #C594C5\">+++ 4.1.4/package.json\t1985-10-26 09:15:00</span></span>\n<span class=\"line\"><span style=\"color: #C594C5\">@@ -1,6 +1,6 @@</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\"> {</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">   &quot;name&quot;: &quot;@splidejs/splide&quot;,</span></span>\n<span class=\"line\"><span style=\"color: #F27983\">-  &quot;version&quot;: &quot;4.1.3&quot;,</span></span>\n<span class=\"line\"><span style=\"color: #87D96C\">+  &quot;version&quot;: &quot;4.1.4&quot;,</span></span>\n<span class=\"line\"><span style=\"color: #C594C5\">@@ -91,15 +91,16 @@</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">   ],</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">   &quot;exports&quot;: {</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">     &quot;.&quot;: {</span></span>\n<span class=\"line\"><span style=\"color: #87D96C\">+      &quot;types&quot;: &quot;./dist/types/index.d.ts&quot;,</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">       &quot;require&quot;: &quot;./dist/js/splide.cjs.js&quot;,</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">       &quot;import&quot;: &quot;./dist/js/splide.esm.js&quot;,</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">       &quot;default&quot;: &quot;./dist/js/splide.esm.js&quot;</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">     },</span></span>\n<span class=\"line\"></span></code></pre>\n<p>(The actual output is a bit longer, but this is enough to get the idea.)</p>\n<p>Now we know: It looks like the main change is that the package now exports its types. If CI passes, this looks like a safe change to me.</p>\n<p><strong>Bonus:</strong> If you’re using Ruby, there is also a Bundler plugin that does the same thing for Ruby Gems: <a href=\"https://github.com/readysteady/bundle-diff\">https://github.com/readysteady/bundle-diff</a>.</p>\n",
            "url": "https://diekmeier.de/posts/2023-01-03-npm-diff/",
            "title": "Compensate for Missing Changelogs with npm-diff",
            "date_modified": "2023-01-03T00:00:00.000Z"
        },
        {
            "id": "2023-01-02-sveltekit-transitions",
            "content_html": "<p>Hello! I just added a few transitions to my SvelteKit app. They run when adding or removing an element from a list. The effect is quite nice and I was (once again) impressed by how easy it is to add transitions to Svelte.</p>\n<p>This is all it took:</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-svelte\"><span class=\"line\"><span style=\"color: #5CCFE680\">&lt;</span><span style=\"color: #5CCFE6\">script</span><span style=\"color: #5CCFE680\">&gt;</span></span>\n<span class=\"line\"><span style=\"color: #FFAD66\">import</span><span style=\"color: #CCCAC2\"> { fade } </span><span style=\"color: #FFAD66\">from</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #D5FF80\">&#39;svelte/transition&#39;</span></span>\n<span class=\"line\"><span style=\"color: #5CCFE680\">&lt;/</span><span style=\"color: #5CCFE6\">script</span><span style=\"color: #5CCFE680\">&gt;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">{#</span><span style=\"color: #FFAD66\">each</span><span style=\"color: #CCCAC2\"> items </span><span style=\"color: #FFAD66\">as</span><span style=\"color: #CCCAC2\"> item}</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  </span><span style=\"color: #5CCFE680\">&lt;</span><span style=\"color: #5CCFE6\">div</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #FFAD66\">transition</span><span style=\"color: #CCCAC2\">:</span><span style=\"color: #73D0FF\">fade</span><span style=\"color: #5CCFE680\">&gt;</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">    </span><span style=\"color: #FFAD66\">{</span><span style=\"color: #CCCAC2\">item</span><span style=\"color: #F29E74\">.</span><span style=\"color: #CCCAC2\">name</span><span style=\"color: #FFAD66\">}</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  </span><span style=\"color: #5CCFE680\">&lt;/</span><span style=\"color: #5CCFE6\">div</span><span style=\"color: #5CCFE680\">&gt;</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">{/</span><span style=\"color: #FFAD66\">each</span><span style=\"color: #CCCAC2\">}</span></span>\n<span class=\"line\"></span></code></pre>\n<p>Now, whenever the list changes, items fade in or out.</p>\n<p>But I noticed that the transitions <em>also</em> run when navigating to a different page. This was a bit unexpected.</p>\n<p>This is especially annoying when navigating <em>away</em>, because the navigation only happens <em>after</em> the transition has finished. The navigation is delayed by a few hundred milliseconds while I look at all my list items fading away. That's so weird!</p>\n<p>Thankfully, this was easy to fix. I just needed to add a <code>|local</code> modifier to the transition:</p>\n<pre class=\"shiki \" style=\"background-color: #1f2430\" tabindex=\"0\"><code class=\"language-svelte\"><span class=\"line\"><span style=\"color: #CCCAC2\">{#</span><span style=\"color: #FFAD66\">each</span><span style=\"color: #CCCAC2\"> items </span><span style=\"color: #FFAD66\">as</span><span style=\"color: #CCCAC2\"> item}</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  </span><span style=\"color: #5CCFE680\">&lt;</span><span style=\"color: #5CCFE6\">div</span><span style=\"color: #CCCAC2\"> </span><span style=\"color: #FFAD66\">transition</span><span style=\"color: #CCCAC2\">:</span><span style=\"color: #73D0FF\">fade</span><span style=\"color: #CCCAC2B3\">|</span><span style=\"color: #F28779\">local</span><span style=\"color: #5CCFE680\">&gt;</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">    </span><span style=\"color: #FFAD66\">{</span><span style=\"color: #CCCAC2\">item</span><span style=\"color: #F29E74\">.</span><span style=\"color: #CCCAC2\">name</span><span style=\"color: #FFAD66\">}</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">  </span><span style=\"color: #5CCFE680\">&lt;/</span><span style=\"color: #5CCFE6\">div</span><span style=\"color: #5CCFE680\">&gt;</span></span>\n<span class=\"line\"><span style=\"color: #CCCAC2\">{/</span><span style=\"color: #FFAD66\">each</span><span style=\"color: #CCCAC2\">}</span></span>\n<span class=\"line\"></span></code></pre>\n<p>Now I can leave pages immediately, and don’t have to wait for transitions! Incredible!</p>\n",
            "url": "https://diekmeier.de/posts/2023-01-02-sveltekit-transitions/",
            "title": "SvelteKit: Don't Run Transitions When Navigating",
            "date_modified": "2023-01-02T00:00:00.000Z"
        }
    ]
}