<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Andreas Bergström</title>
    <description>The latest articles on Forem by Andreas Bergström (@andreasbergstrom).</description>
    <link>https://forem.com/andreasbergstrom</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F153469%2F5c1970f5-0d22-46e9-af0c-6931bb91d856.jpg</url>
      <title>Forem: Andreas Bergström</title>
      <link>https://forem.com/andreasbergstrom</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/andreasbergstrom"/>
    <language>en</language>
    <item>
      <title>Using FastMCP with OpenAI and Avoiding Session Termination Issues</title>
      <dc:creator>Andreas Bergström</dc:creator>
      <pubDate>Sun, 10 Aug 2025 10:32:13 +0000</pubDate>
      <link>https://forem.com/andreasbergstrom/using-fastmcp-with-openai-and-avoiding-session-termination-issues-k3h</link>
      <guid>https://forem.com/andreasbergstrom/using-fastmcp-with-openai-and-avoiding-session-termination-issues-k3h</guid>
      <description>&lt;h1&gt;
  
  
  Using FastMCP with OpenAI: Avoiding Session Termination Issues
&lt;/h1&gt;

&lt;p&gt;When integrating &lt;strong&gt;FastMCP&lt;/strong&gt; as a &lt;a href="https://openai.github.io/openai-agents-js/guides/mcp/" rel="noopener noreferrer"&gt;Model Context Protocol (MCP)&lt;/a&gt; server for OpenAI’s &lt;strong&gt;Responses API&lt;/strong&gt;, you may encounter a frustrating issue:&lt;br&gt;&lt;br&gt;
OpenAI sends &lt;code&gt;DELETE&lt;/code&gt; requests to end the MCP session after each call, without automatically creating new sessions for subsequent requests. This will result in FastMCP responding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"jsonrpc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"server-error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-32600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Not Found: Session has been terminated"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Fix: &lt;code&gt;stateless_http=True&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;When instantiating your FastMCP server, set:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastmcp&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastMCP&lt;/span&gt;

&lt;span class="n"&gt;mcp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastMCP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MyToolServer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;stateless_http&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;  &lt;span class="c1"&gt;# crucial for streaming stability
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@mcp.tool&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;mcp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;transport&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.0.0.0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8000&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why This Works
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;stateless_http=True&lt;/code&gt; disables stateful session tracking.&lt;br&gt;
Every request is handled independently, so OpenAI’s DELETE calls don’t break the connection.&lt;br&gt;
Without it, streaming sessions will be terminated prematurely.&lt;br&gt;
More details: OpenAI Forum Thread&lt;/p&gt;

&lt;h2&gt;
  
  
  Caveats
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Session IDs won’t persist between requests, so advanced workflows relying on session state won’t work.&lt;/li&gt;
&lt;li&gt;Sampling and certain bi-directional streaming patterns may not be supported in stateless mode.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;If your OpenAI + FastMCP streaming requests fail after one call,&lt;br&gt;
set &lt;code&gt;stateless_http=True&lt;/code&gt; when starting the server.&lt;br&gt;
It’s the simplest fix to keep your MCP server ready for every new streaming request.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>fastmcp</category>
      <category>openai</category>
      <category>mcp</category>
    </item>
    <item>
      <title>Redirecting mobile users to App or Play Store in NextJS</title>
      <dc:creator>Andreas Bergström</dc:creator>
      <pubDate>Mon, 27 Nov 2023 19:53:11 +0000</pubDate>
      <link>https://forem.com/andreasbergstrom/redirecting-mobile-users-to-app-or-play-store-using-nextjs-3pp1</link>
      <guid>https://forem.com/andreasbergstrom/redirecting-mobile-users-to-app-or-play-store-using-nextjs-3pp1</guid>
      <description>&lt;p&gt;So here is the case: you have a mobile app for both iOS and Android and you have decided to promote it. While you could simply ask people to search for it on App Store or Google Play, that's not ideal. But you also don't want to use multiple URLs and let the audience write/click/scan the appropriate one for them. &lt;/p&gt;

&lt;p&gt;Also, a substantial amount of users don't know if they use iOS or Android. They are simply interested in testing your app but unless they can just click a button to get it, you will loose them. Or at least make them irritated before they even installed your app.&lt;/p&gt;

&lt;p&gt;While there are many services that provide a way to use a single URL and QR-code that redirects a mobile user to the correct app store depending on her platform, it is extremely easy to implement a homegrown solution. Let us see how this can be done when using Next.&lt;/p&gt;

&lt;h1&gt;
  
  
  Overview of the Approach
&lt;/h1&gt;

&lt;p&gt;The solution involves two main components in a NextJS application:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Middleware&lt;/strong&gt; (&lt;code&gt;middleware.ts&lt;/code&gt;): This file is responsible for detecting the user's device type and redirecting them to the correct app store.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A Placeholder Page&lt;/strong&gt; (&lt;code&gt;app/get.tsx&lt;/code&gt;): This page serves as a trigger for the middleware.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's delve into the details of these components.&lt;/p&gt;

&lt;h1&gt;
  
  
  Creating the Middleware (middleware.ts)
&lt;/h1&gt;

&lt;p&gt;The middleware is the heart of our solution. It detects the user's device type and then redirects them to the appropriate store. Here’s the breakdown:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextRequest&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userAgent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ua&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;userAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/iP&lt;/span&gt;&lt;span class="se"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;hone|ad|od&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ua&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://apps.apple.com/in/app/yourapp/id123456789&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/Android/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ua&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://play.google.com/store/apps/details?id=com.yourapp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://yourdomain.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;matcher&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/get&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We use a middleware to return the redirect as early as possible before rendering anything to the user.&lt;/p&gt;

&lt;p&gt;Key Points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Device Detection&lt;/strong&gt;: We use regular expressions to determine whether the user's device is an iPhone, iPad, iPod, or Android.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redirection&lt;/strong&gt;: Depending on the device type, we redirect the user to either the App Store or Google Play Store.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fallback&lt;/strong&gt;: For non-mobile users, we redirect them to a default website.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For iOS the redirect should open App Store straight away, while on Android the user will be taken to the web version of Play Store but a modal will be displayed about opening your app in the native Play Store app. There are solutions to this which involve different ways of launching Play store but that's for another article.&lt;/p&gt;

&lt;h1&gt;
  
  
  Setting Up the Placeholder Page (app/get.tsx)
&lt;/h1&gt;

&lt;p&gt;This page serves as a trigger for the middleware. This would normally never be executed unless the middleware for some reason fails to redirect the user. It's a simple component that redirects to the home page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;redirect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/navigation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;DownloadAppRoute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Own the contact points
&lt;/h1&gt;

&lt;p&gt;That's it! From here you can evolve this solution futher, for example by adding stats. One easy tweak could be to change the fallback to a page about your app.&lt;/p&gt;

&lt;p&gt;By hosting the solution yourself you maintain control of the contact point to the end-user, any SEO-boost is given to your domain and any QR-codes you use will be pointed to your domain directly. This is in contrast to using 3rd party services where the redirect goes through their  domains, so if you ever stop paying the invoices any printed links or QR-codes will be rendered useless.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>mobile</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Python del vs assigning to None</title>
      <dc:creator>Andreas Bergström</dc:creator>
      <pubDate>Sat, 11 Nov 2023 16:37:38 +0000</pubDate>
      <link>https://forem.com/andreasbergstrom/python-del-vs-assigning-to-none-5387</link>
      <guid>https://forem.com/andreasbergstrom/python-del-vs-assigning-to-none-5387</guid>
      <description>&lt;p&gt;Python utilizes garbage collection to free the developer from the hassle of manually handling allocating and de-allocating memory. But there are still some details that could suprise you unless you are aware of them.&lt;/p&gt;

&lt;p&gt;Because even though the Python runtime will take care of memory management, sometimes developers will want to manually tell the garbage colletor that a variable is no longer needed. Either because they are doing some edge-case optimization and really know what they are doing or they think they are smart but have no idea what they are doing. Most likely the latter as the Python runtime most often does not release unused memory back to the operating system.&lt;/p&gt;

&lt;p&gt;But when someone need to somehow mark a variable as ready to be freed by the garbage collector, there are usually two solutions they come across:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;del&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The difference is that &lt;code&gt;x = None&lt;/code&gt; will free whatever it referenced but keep the name around even though it’s just referencing &lt;code&gt;None&lt;/code&gt; (which is a type, &lt;code&gt;NoneType&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;On the other hand &lt;code&gt;del x&lt;/code&gt; will completely remove both the name and what it referenced. If you thereafter try to use x an NameError will be thrown (or &lt;code&gt;AttributeError&lt;/code&gt; in case of a object property).&lt;/p&gt;

&lt;p&gt;So in practice, by assigning &lt;code&gt;None&lt;/code&gt; to a name you can still use it in expressions while using del the name is completely removed. In the first case a few bytes is needed to keep the name in memory, while the later completely clears all memory usage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;gc&lt;/span&gt;

&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'Some text here to give the variable a decent size'&lt;/span&gt;
&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'x value before deletion: {}'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'x size before deletion: {} bytes'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getsizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'y value before deletion: {}'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;span class="k"&gt;del&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;
&lt;span class="n"&gt;gc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;collect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# Not really needed, just to show garbage collection has been done hereafter
&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'x value after deletion: {}'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'x size after deletion: {} bytes'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getsizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="c1"&gt;# A few bytes needed to keep symbol name
&lt;/span&gt;&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'x type after deletion: {}'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Can still use x!'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'y value after deletion: {}'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# Will throw NameError (AttributeError in case of class property)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;x value before deletion: Some text here to give the variable a decent size
x size before deletion: 98 bytes
y value before deletion: 2
x value after deletion: None
x size after deletion: 16 bytes
x &lt;span class="nb"&gt;type &lt;/span&gt;after deletion: &amp;lt;class &lt;span class="s1"&gt;'NoneType'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
Can still use x!
Traceback &lt;span class="o"&gt;(&lt;/span&gt;most recent call last&lt;span class="o"&gt;)&lt;/span&gt;:
  File &lt;span class="s2"&gt;"Untitled.py"&lt;/span&gt;, line 21, &lt;span class="k"&gt;in&lt;/span&gt; &amp;lt;module&amp;gt;
    print&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'y value after deletion: {}'&lt;/span&gt;.format&lt;span class="o"&gt;(&lt;/span&gt;y&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="c"&gt;# Will throw NameError (AttributeError in case of class property)&lt;/span&gt;
NameError: name &lt;span class="s1"&gt;'y'&lt;/span&gt; is not defined
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see in the error above, if you for whatever reason need to hook into the memory management, unless you know the difference between assigning to None and using del it could confuse you.&lt;/p&gt;

&lt;p&gt;Let us now look at the bytecode to see the technical difference:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;gc&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;dis&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;using_none&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="c1"&gt;# &amp;lt;-- ASSIGNING TO NONE
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;using_del&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="k"&gt;del&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="c1"&gt;# &amp;lt;-- USING DEL
&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Bytecode when assigning to None:"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;dis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;using_none&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Bytecode when using del:"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;dis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;using_del&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Bytecode when assigning to None:
  5           0 LOAD_CONST               1 &lt;span class="o"&gt;(&lt;/span&gt;1&lt;span class="o"&gt;)&lt;/span&gt;
              2 STORE_FAST               0 &lt;span class="o"&gt;(&lt;/span&gt;x&lt;span class="o"&gt;)&lt;/span&gt;

  7           4 LOAD_CONST               0 &lt;span class="o"&gt;(&lt;/span&gt;None&lt;span class="o"&gt;)&lt;/span&gt;
              6 STORE_FAST               0 &lt;span class="o"&gt;(&lt;/span&gt;x&lt;span class="o"&gt;)&lt;/span&gt;

              8 LOAD_CONST               0 &lt;span class="o"&gt;(&lt;/span&gt;None&lt;span class="o"&gt;)&lt;/span&gt;
             10 RETURN_VALUE

Bytecode when using del:
 10           0 LOAD_CONST               1 &lt;span class="o"&gt;(&lt;/span&gt;1&lt;span class="o"&gt;)&lt;/span&gt;
              2 STORE_FAST               0 &lt;span class="o"&gt;(&lt;/span&gt;x&lt;span class="o"&gt;)&lt;/span&gt;

 12           4 DELETE_FAST              0 &lt;span class="o"&gt;(&lt;/span&gt;x&lt;span class="o"&gt;)&lt;/span&gt;
              6 LOAD_CONST               0 &lt;span class="o"&gt;(&lt;/span&gt;None&lt;span class="o"&gt;)&lt;/span&gt;
              8 RETURN_VALUE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So using del results in only one bytecode, &lt;code&gt;DELETE_FAST&lt;/code&gt;, while assigning to None actually runs a full assignment using &lt;code&gt;LOAD_CONST&lt;/code&gt; and &lt;code&gt;STORE_FAST&lt;/code&gt;. The last &lt;code&gt;LOAD_CONST&lt;/code&gt; before &lt;code&gt;RETURN_VALUE&lt;/code&gt; in both functions is simply the return value None that every Python function implicitly returns.&lt;/p&gt;

</description>
      <category>python</category>
      <category>performance</category>
    </item>
    <item>
      <title>Node 21 brings built-in WebSocket support</title>
      <dc:creator>Andreas Bergström</dc:creator>
      <pubDate>Mon, 16 Oct 2023 18:19:32 +0000</pubDate>
      <link>https://forem.com/andreasbergstrom/node-21-might-have-websockets-built-in-24f3</link>
      <guid>https://forem.com/andreasbergstrom/node-21-might-have-websockets-built-in-24f3</guid>
      <description>&lt;p&gt;Update 2023-10-17: Node 21 has now shipped with WebSocket support as predicted, read more:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nodejs.org/en/blog/announcements/v21-release-announce#built-in-websocket-client" rel="noopener noreferrer"&gt;https://nodejs.org/en/blog/announcements/v21-release-announce#built-in-websocket-client&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc99mczof058mk707t7dl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc99mczof058mk707t7dl.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're a part of the JavaScript jungle, you know how we all have been longing for some native WebSocket love in Node. WebSockets are like that secret sauce to making any app conversation go smoothly in real-time, back and forth between the client and server. But hey, Node has been playing hard to get on this one for a while. However, recent pull request activity suggest that Node version 21 might just be the game changer we've been waiting for, thanks to some community heroes putting in the elbow grease.&lt;/p&gt;

&lt;p&gt;Now, let's talk about a recent pull request that's caught the eye over at the Undici project, which is Node’s own client for handling HTTP. This &lt;a href="https://github.com/nodejs/undici/pull/2217" rel="noopener noreferrer"&gt;pull request&lt;/a&gt; is all about bringing WebSocket support to the table. It's like a beacon of hope for us, showcasing that, yeah, Node isn't going to let the modern web sprint ahead while it’s tying its shoelaces.&lt;/p&gt;

&lt;p&gt;There’s an &lt;a href="https://github.com/nodejs/node/issues/19308" rel="noopener noreferrer"&gt;issue&lt;/a&gt; that popped up in the Node repo a while ago, which screams the community’s long-standing wish for some WebSocket magic. This thread is like a saga of devs dreaming about WebSockets dancing in Node natively.&lt;/p&gt;

&lt;p&gt;So, what’s the big deal with WebSockets in Node? Well, it's not just about making real-time chit-chat easier; it's also about shipping Node with batteries included and gaining a small performance boost out of it. As Node version 21 is gearing up to see the daylight, having native WebSocket support could mean we get to build snazzier, more interactive apps.&lt;/p&gt;

&lt;p&gt;Keep in mind Deno and Bun already comes with WebSocket support out of the box. Node should do to.&lt;/p&gt;

&lt;p&gt;Read more about &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSocket" rel="noopener noreferrer"&gt;WebSocket at MDN&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>node</category>
    </item>
    <item>
      <title>Configure TypeORM migrations in 5 minutes</title>
      <dc:creator>Andreas Bergström</dc:creator>
      <pubDate>Sun, 15 Oct 2023 08:39:24 +0000</pubDate>
      <link>https://forem.com/andreasbergstrom/configure-typeorm-migrations-in-5-minutes-2njg</link>
      <guid>https://forem.com/andreasbergstrom/configure-typeorm-migrations-in-5-minutes-2njg</guid>
      <description>&lt;p&gt;Database migrations are a crucial part of any robust, scalable application, allowing you to manipulate your database schema without touching the data. If you're building a NestJS application, you'll find that TypeORM is one of the most powerful tools available for this. In this blog post, we'll delve into how to manage database migrations effectively in TypeORM.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up the NestJS App Module
&lt;/h2&gt;

&lt;p&gt;The first step to handling migrations in TypeORM is to set up your &lt;code&gt;app.module.ts&lt;/code&gt; file. You can configure the &lt;code&gt;TypeOrmModule&lt;/code&gt; to automatically run migrations when the application starts.&lt;/p&gt;

&lt;p&gt;Here is an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app.module.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Module&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/common&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;TypeOrmModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/typeorm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ConfigService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;TypeOrmModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forRootAsync&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ConfigService&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;useFactory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ConfigService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;postgres&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DB_URL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;migrations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/migrations/*{.ts,.js}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;migrationsTableName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_migrations&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;migrationsRun&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// Auto-run migrations&lt;/span&gt;
        &lt;span class="na"&gt;entities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dist/**/*.entity{.ts,.js}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;synchronize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DB_SYNC&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="c1"&gt;// Other modules&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key Points
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;migrationsRun: true&lt;/code&gt;: This will run the migration files automatically when your application starts.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;synchronize: false&lt;/code&gt;: This should be set to false in production as it can drop your database tables.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Install TS-Node
&lt;/h2&gt;

&lt;p&gt;You will need &lt;code&gt;ts-node&lt;/code&gt; to execute TypeScript files directly for migration purposes.&lt;/p&gt;

&lt;p&gt;Install it as a development dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;ts-node &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  NPM Scripts for Migrations
&lt;/h2&gt;

&lt;p&gt;Add these scripts in your &lt;code&gt;package.json&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"typeorm"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ts-node ./node_modules/typeorm/cli"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"typeorm:run-migrations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npm run typeorm migration:run -- -d ./typeOrm.config.ts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"typeorm:generate-migration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npm run typeorm -- -d ./typeOrm.config.ts migration:generate ./migrations/$npm_config_name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"typeorm:create-migration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npm run typeorm -- migration:create ./migrations/$npm_config_name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"typeorm:revert-migration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npm run typeorm -- -d ./typeOrm.config.ts migration:revert"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  TypeORM Configuration
&lt;/h2&gt;

&lt;p&gt;Create a &lt;code&gt;typeorm.config.ts&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// typeorm.config.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DataSource&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;typeorm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ConfigService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;configService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ConfigService&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;DataSource&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;postgres&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;configService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DB_URL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;entities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dist/**/*.entity{.ts,.js}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;migrations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dist/migrations/*.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Magic of &lt;code&gt;generate-migration&lt;/code&gt;: Auto-detecting Changes in Entities
&lt;/h2&gt;

&lt;p&gt;One of the most powerful features of TypeORM is its ability to automatically detect changes in your entities and generate the appropriate migration files for you. This saves you the manual labor of writing SQL queries for each change in your entity. The &lt;code&gt;generate-migration&lt;/code&gt; command comes in very handy for this purpose.&lt;/p&gt;

&lt;h3&gt;
  
  
  How It Works
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;generate-migration&lt;/code&gt; command compares the entities in your project with your database's current state and generates a new migration file containing all the SQL queries needed to transition your database schema to match your entities.&lt;/p&gt;

&lt;p&gt;Here's how you can use it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run typeorm:generate-migration &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;YourMigrationName
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;YourMigrationName&lt;/code&gt; with a name that describes the changes in this migration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;Suppose you have an existing &lt;code&gt;User&lt;/code&gt; entity, and you add a new column &lt;code&gt;email&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;PrimaryGeneratedColumn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;// Newly added&lt;/span&gt;
  &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you run &lt;code&gt;generate-migration&lt;/code&gt;, TypeORM will automatically detect the new &lt;code&gt;email&lt;/code&gt; column and generate the necessary SQL query to add this column to the &lt;code&gt;user&lt;/code&gt; table in your database.&lt;/p&gt;

&lt;h3&gt;
  
  
  Important Note
&lt;/h3&gt;

&lt;p&gt;Although this feature is incredibly helpful, it's not a complete substitute for understanding your database schema and migrations. It is good practice to review the generated migration files and test them in a controlled environment before applying them to your production database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the NPM Scripts
&lt;/h2&gt;

&lt;p&gt;Now you can use the following commands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run Migrations: &lt;code&gt;\&lt;/code&gt;&lt;code&gt;npm run typeorm:run-migrations\&lt;/code&gt;&lt;code&gt;\&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Generate Migrations: &lt;code&gt;\&lt;/code&gt;&lt;code&gt;npm run typeorm:generate-migration -- --name=MigrationName\&lt;/code&gt;&lt;code&gt;\&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Create Empty Migration: &lt;code&gt;\&lt;/code&gt;&lt;code&gt;npm run typeorm:create-migration -- --name=MigrationName\&lt;/code&gt;&lt;code&gt;\&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Revert Last Migration: &lt;code&gt;\&lt;/code&gt;&lt;code&gt;npm run typeorm:revert-migration\&lt;/code&gt;&lt;code&gt;\&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that's it! You're now ready to manage your database schema changes effectively using migrations in TypeORM with a NestJS application.&lt;/p&gt;

&lt;p&gt;Would you like to know more details about any specific part of the process? I'd be happy to clarify or go into more detail!&lt;/p&gt;

</description>
      <category>nestjs</category>
      <category>typeorm</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Easily style active links in Tanstack Router</title>
      <dc:creator>Andreas Bergström</dc:creator>
      <pubDate>Sat, 14 Oct 2023 07:45:23 +0000</pubDate>
      <link>https://forem.com/andreasbergstrom/easily-style-active-links-in-tanstack-router-7n</link>
      <guid>https://forem.com/andreasbergstrom/easily-style-active-links-in-tanstack-router-7n</guid>
      <description>&lt;p&gt;UI/UX has both high hanging and low hanging fruits, and this is certainly one of the more low hanging ones to enhance the experience. A main navigation, be it a navbar or a navigation tree on either side, that indicates where in it the user is currently browsing is one of the more basic things. This is perhaps also the oldest UX tool the web has, dating back to the first HTML pages and browsers in the 90's.&lt;/p&gt;

&lt;p&gt;TanStack Router, liked for its typesafe approach that borrows lots of ideas from Vue/Angular routers, offers a smooth solution to this UI necessity through the &lt;code&gt;activeProps&lt;/code&gt; attribute of its &lt;code&gt;Link&lt;/code&gt; element. This attribute allows developers to apply specific styles to active links, enhancing the navigation experience. Let's delve into a practical example to see &lt;code&gt;activeProps&lt;/code&gt; in action.&lt;/p&gt;

&lt;h2&gt;
  
  
  Constructing the Navigation Component
&lt;/h2&gt;

&lt;p&gt;In our scenario, we'll construct a &lt;code&gt;MainNav&lt;/code&gt; component to render a navigation menu with two items: Dashboard and Messages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;dashboardRoute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;threadsRoute&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/Router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@tanstack/react-router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;MainNav&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;menuItems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Dashboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dashboardRoute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fullPath&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Messages&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;messagesRoute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fullPath&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;nav&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hidden md:flex items-center space-x-4 lg:space-x-6 mx-4 text-gray-500&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;menuItems&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Link&lt;/span&gt;
            &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text-sm font-medium transition-colors hover:text-black&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
            &lt;span class="nx"&gt;activeProps&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text-black&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
          &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Link&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;})}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/nav&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s a breakdown of the key parts in the code snippet above:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We defined a &lt;code&gt;MainNav&lt;/code&gt; function component.&lt;/li&gt;
&lt;li&gt;We created an array &lt;code&gt;menuItems&lt;/code&gt; to store our navigation items, where each item has a name and a path.&lt;/li&gt;
&lt;li&gt;Within the &lt;code&gt;nav&lt;/code&gt; element, we iterated over &lt;code&gt;menuItems&lt;/code&gt; to generate &lt;code&gt;Link&lt;/code&gt; elements for each navigation item.&lt;/li&gt;
&lt;li&gt;For each &lt;code&gt;Link&lt;/code&gt; element, we applied common styling via the &lt;code&gt;className&lt;/code&gt; attribute and used the &lt;code&gt;activeProps&lt;/code&gt; attribute to specify the styling for active links. When a link is active, the &lt;code&gt;text-black&lt;/code&gt; class is applied, changing its text color to black.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;code&gt;activeProps&lt;/code&gt; attribute offers a neat and intuitive way to style active links, improving user orientation and the overall user experience. The use of &lt;code&gt;activeProps&lt;/code&gt; in TanStack Router's &lt;code&gt;Link&lt;/code&gt; element demonstrates a practical solution for achieving a polished, user-friendly navigation system.&lt;/p&gt;

&lt;p&gt;For further insights and use-cases, refer to the official TanStack documentation on &lt;a href="https://tanstack.com/router/v1/docs/guide/navigation#active--inactive-props"&gt;Navigation&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>webdev</category>
      <category>ux</category>
    </item>
    <item>
      <title>Finally you can skip dotenv in Node</title>
      <dc:creator>Andreas Bergström</dc:creator>
      <pubDate>Sat, 09 Sep 2023 07:33:31 +0000</pubDate>
      <link>https://forem.com/andreasbergstrom/finally-you-can-skip-dotenv-in-node-14ml</link>
      <guid>https://forem.com/andreasbergstrom/finally-you-can-skip-dotenv-in-node-14ml</guid>
      <description>&lt;p&gt;Node.js has been at the forefront of backend development for over a decade now, largely due to its scalability and efficient performance. Every new release brings with it a myriad of features aimed at simplifying development, and Node.js v20.6 is no exception. One small but highly appreciated feature in this release is the built-in &lt;code&gt;.env&lt;/code&gt; file support for configuring environment variables.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are .env Files?
&lt;/h2&gt;

&lt;p&gt;Environment variables are a crucial part of modern development workflows. They let you store sensitive information, application configurations, and even runtime settings away from your application code. &lt;code&gt;.env&lt;/code&gt; files have become the de facto standard for managing these variables. While environment variables are usually injected into production containers, during local development it is common to have the variables in files such as &lt;code&gt;.env.test&lt;/code&gt; and &lt;code&gt;.env.development&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Does it Work?
&lt;/h2&gt;

&lt;p&gt;Prior to v20.6, handling environment variables often involved using external libraries like &lt;code&gt;dotenv&lt;/code&gt;, which would parse &lt;code&gt;.env&lt;/code&gt; files and inject the variables into &lt;code&gt;process.env&lt;/code&gt;. With this new feature, you can directly pass the &lt;code&gt;.env&lt;/code&gt; file as an argument to the Node.js runtime.&lt;/p&gt;

&lt;h2&gt;
  
  
  Syntax
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;.env&lt;/code&gt; file should be formatted as an INI file, meaning each line contains a key-value pair for an environment variable. For example, your &lt;code&gt;.env&lt;/code&gt; file might look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="py"&gt;DB_URL&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;foo&lt;/span&gt;
&lt;span class="py"&gt;JWT_SECRET&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;foo&lt;/span&gt;
&lt;span class="py"&gt;LOG_LEVEL&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;debug&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Running your Application
&lt;/h2&gt;

&lt;p&gt;You can initialize your Node.js application with predefined configurations using the following CLI command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node &lt;span class="nt"&gt;--env-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;config.env index.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will load all the environment variables from &lt;code&gt;config.env&lt;/code&gt; into your application's environment. For example, you can now access the password as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;DB_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB_URL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  NODE_OPTIONS in .env
&lt;/h2&gt;

&lt;p&gt;This new feature doesn't just stop at handling your custom environment variables. It extends to built-in Node.js options as well. Traditionally, defining &lt;code&gt;NODE_OPTIONS&lt;/code&gt; would involve including them in your &lt;code&gt;package.json&lt;/code&gt; or setting them in your shell before running your application. With this new built-in &lt;code&gt;.env&lt;/code&gt; support, you can include NODE_OPTIONS directly in your &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;For example, your &lt;code&gt;.env&lt;/code&gt; file could contain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="py"&gt;NODE_OPTIONS&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;--experimental-modules --inspect&lt;/span&gt;
&lt;span class="py"&gt;LOG_LEVEL&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;debug&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why Is This Important?
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Simplified Workflow&lt;/em&gt;&lt;br&gt;
This change simplifies the developer experience by natively incorporating what was already a de facto standard in Node.js development.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Less Dependence on External Packages&lt;/em&gt;&lt;br&gt;
By incorporating this feature into the core, Node.js reduces the number of third-party packages that developers need to be familiar with, making it easier to get up and running.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Unified Configuration&lt;/em&gt;&lt;br&gt;
This feature also encourages a more unified approach to configuration, bringing environment variables and Node options into a single, easily manageable file.&lt;/p&gt;

&lt;h2&gt;
  
  
  You might still need 3rd party libraries for frontend
&lt;/h2&gt;

&lt;p&gt;While Node.js 20.6 has streamlined environment variable management with its built-in &lt;code&gt;.env&lt;/code&gt; support, it's important to note that this feature doesn't extend to React and React Native. These frameworks don't utilize the Node.js runtime in production and have their own build processes and runtimes. As a result, developers may still need to rely on existing methods for environment variable management. For instance, legacy React projects often make use of tools like &lt;code&gt;create-react-app&lt;/code&gt;, which handles &lt;code&gt;.env&lt;/code&gt; files in its own way, while React Native developers may turn to libraries such as &lt;code&gt;react-native-config&lt;/code&gt;. Any newer projects would probably use Vite, Astro and similiar which has built-in support.&lt;/p&gt;

&lt;p&gt;Node.js v20.6's addition of built-in &lt;code&gt;.env&lt;/code&gt; file support is more than just a convenience feature; it's a strategic move to maintain its competitive edge in a landscape increasingly influenced by newcomers like Deno and BUN. These emerging technologies have placed a significant emphasis on developer experience right out of the box, pushing Node.js to evolve and incorporate such enhancements natively. This update is not just about streamlining application development in Node.js; it's also about responding to the challenges and setting the bar high in a rapidly evolving ecosystem.&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>npm</category>
    </item>
    <item>
      <title>How to style for print in Tailwind</title>
      <dc:creator>Andreas Bergström</dc:creator>
      <pubDate>Sun, 13 Aug 2023 18:21:07 +0000</pubDate>
      <link>https://forem.com/andreasbergstrom/how-to-easily-use-media-queries-for-print-in-tailwind-2o9a</link>
      <guid>https://forem.com/andreasbergstrom/how-to-easily-use-media-queries-for-print-in-tailwind-2o9a</guid>
      <description>&lt;p&gt;Ever been merrily coding away when suddenly the thought strikes, "What if someone... prints this page?" And the more ominous: "What if it looks like a Picasso painting after a rough night when they do?"&lt;/p&gt;

&lt;p&gt;For a web app that's more of an interface than a classic document, you probably don't care that much about its print appearance as it's unlikely someone would print something there. But for a typical document-oriented website with lot's of text and image content, you might wanna have a look at its print preview. Looks terrible, right? How do we fix this without resorting to the hell of custom CSS classes and files? Like this?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="n"&gt;print&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;inherit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;text-decoration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Well, no! With Tailwind's ever-so-handy &lt;code&gt;print&lt;/code&gt; and &lt;code&gt;screen&lt;/code&gt; modifiers, your website can look fabulous on screens AND on paper. No more nightmares about confetti-like printouts!&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up print and screen prefixes in Tailwind
&lt;/h2&gt;

&lt;p&gt;Tailwind is the awsome utility-first CSS framework we wish we could use in every client or work project. It's like the Swiss Army knife of styling - just without the tiny, almost useless, scissors. Most utilities are activated right from the get-go. But some? They're like hidden Easter eggs waiting for you to find. Enter: the &lt;code&gt;print&lt;/code&gt; and &lt;code&gt;screen&lt;/code&gt; modifiers.&lt;/p&gt;

&lt;p&gt;From the get-go it's not available, but luckily you don't need to install any plugin to get started. Simply open up the &lt;code&gt;tailwind.config.js&lt;/code&gt; file and extend the available screens:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ... rest of tailwind config&lt;/span&gt;
  &lt;span class="na"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;screens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;print&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;print&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;screen&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way, Tailwind will now auto-generate media queries prefixes that you can use in your classes. You can use them to entirely show or hide elements depending on print or not, or tweak any CSS you want accordingly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"print:text-xl screen:text-sm"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;I’ll look big on paper but compact on screen!&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's go through a few other examples of where you would want to tweak the print styling on your page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hide navigation and footer elements
&lt;/h2&gt;

&lt;p&gt;When a user prints a webpage, they typically don't need the website's navigation bar, footer, or any site-wide banner elements. These are essentially useful only in a digital context. Therefore, it's a common practice to hide these elements in the print version.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;nav&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"print:hidden"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; ... &lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Hide interactive elements
&lt;/h3&gt;

&lt;p&gt;Interactive elements, such as buttons, dropdowns, and forms, serve no purpose on a printed page. It's a good idea to hide them to avoid confusing the reader.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"print:hidden"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Click Me!&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Display URLs for links
&lt;/h2&gt;

&lt;p&gt;Hyperlinks are interactive elements that work wonders on screens but are dormant on paper. To provide context, it can be helpful to display the URL next to the link text in the print version so readers can manually access them if needed.&lt;/p&gt;

&lt;p&gt;For this one we do need to add a custom CSS class to our global CSS, but only one!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="n"&gt;print&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;href&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="nd"&gt;:after&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;" ("&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;href&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="s1"&gt;")"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Optimize images and graphics
&lt;/h3&gt;

&lt;p&gt;High-color images might not always print well, especially in grayscale. You might want to enhance the contrast, remove background images, or even swap colored images with their grayscale counterparts to ensure clarity.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"colored-image.jpg"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"screen:block print:hidden"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"grayscale-image.jpg"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"screen:hidden print:block"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Considering the distinct nature of screens and printed pages, these tweaks can significantly improve the clarity, relevance, and aesthetics of printed content.&lt;/p&gt;

</description>
      <category>tailwindcss</category>
      <category>webdev</category>
      <category>css</category>
    </item>
    <item>
      <title>Understanding Cache-Control and ETag for efficient web caching</title>
      <dc:creator>Andreas Bergström</dc:creator>
      <pubDate>Thu, 10 Aug 2023 07:49:17 +0000</pubDate>
      <link>https://forem.com/andreasbergstrom/understanding-cache-control-and-etag-for-efficient-web-caching-2nf5</link>
      <guid>https://forem.com/andreasbergstrom/understanding-cache-control-and-etag-for-efficient-web-caching-2nf5</guid>
      <description>&lt;p&gt;Web performance is essential in delivering a seamless user experience. One way to boost this performance is by implementing efficient caching strategies. Among numerous techniques available, two HTTP headers that play a central role in this endeavor are &lt;code&gt;Cache-Control&lt;/code&gt; and &lt;code&gt;ETag&lt;/code&gt;. These headers can help your website load faster by minimizing unnecessary network requests while ensuring that your users always see the most up-to-date content.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cache-Control: Mastering the Basics
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;Cache-Control&lt;/code&gt; header, as its name suggests, dictates how HTTP responses should be cached by browsers and other intermediate caches. It uses various directives to control the caching behavior:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;max-age&lt;/code&gt;: Specifies how long (in seconds) a resource is considered fresh. After this time, the cache deems the resource stale and tries to re-fetch it.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;no-cache&lt;/code&gt;: The cache must validate the stored copy with the server before serving it to the client, even if it's not yet stale.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;no-store&lt;/code&gt;: The response should not be stored in any cache.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;public&lt;/code&gt; and &lt;code&gt;private&lt;/code&gt;: Define whether the response can be cached in a public cache (like a CDN) or only in a private cache (like a user's browser).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;must-revalidate&lt;/code&gt;: Once the resource is stale, the cache must not use its stored copy without successful validation with the server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For instance, &lt;code&gt;Cache-Control: max-age=3600&lt;/code&gt; instructs the client to consider the cached resource fresh for one hour. After that, the cache should consider the resource stale and try to re-fetch it.&lt;/p&gt;

&lt;h2&gt;
  
  
  ETag: The Freshness Validator
&lt;/h2&gt;

&lt;p&gt;While &lt;code&gt;Cache-Control&lt;/code&gt; provides general caching directives, &lt;code&gt;ETag&lt;/code&gt; (Entity Tag) works as a validator, ensuring the freshness of a cached resource. An &lt;code&gt;ETag&lt;/code&gt; is a unique identifier for a specific version of a resource. The server includes this tag in its response, and the client stores this &lt;code&gt;ETag&lt;/code&gt; value along with the cached resource.&lt;/p&gt;

&lt;p&gt;When the client needs the same resource again, it sends the stored &lt;code&gt;ETag&lt;/code&gt; value in an &lt;code&gt;If-None-Match&lt;/code&gt; header. The server then compares the current &lt;code&gt;ETag&lt;/code&gt; value of the resource with the client's value. If they match, the client's cached version is still fresh, and the server returns a &lt;code&gt;304 Not Modified&lt;/code&gt; status, allowing the client to use its cached copy. If they don't match, the server sends the new resource with a new &lt;code&gt;ETag&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Cache-Control and ETag together
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Cache-Control&lt;/code&gt; and &lt;code&gt;ETag&lt;/code&gt; often work together to effectively manage caching. Here's an example of how:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;

&lt;/span&gt;&lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt; &lt;span class="ne"&gt;OK&lt;/span&gt;&lt;br&gt;
&lt;span class="na"&gt;Cache-Control&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;max-age=3600&lt;/span&gt;&lt;br&gt;
&lt;span class="na"&gt;ETag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"12345"&lt;/span&gt;&lt;br&gt;
&lt;span class="na"&gt;Content-Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;text/html&lt;/span&gt;

&lt;p&gt;In this scenario, &lt;code&gt;Cache-Control&lt;/code&gt; instructs the client to cache the response and consider it fresh for one hour. Meanwhile, the &lt;code&gt;ETag&lt;/code&gt; header is provided for validation in case the resource needs to be re-fetched after that hour.&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Benefits of Using Both Cache-Control and ETag&lt;br&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Optimal Efficiency and Freshness:&lt;/strong&gt;&lt;br&gt;
By combining the expiration-based caching mechanism of &lt;code&gt;Cache-Control&lt;/code&gt; with the validation-based approach of &lt;code&gt;ETag&lt;/code&gt;, developers can ensure that a client doesn't even attempt to re-fetch a resource until necessary, but when it does, it's validated for freshness.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reduced Server Load&lt;/strong&gt;: With &lt;code&gt;Cache-Control&lt;/code&gt; set to a specific &lt;code&gt;max-age&lt;/code&gt;, requests for a resource don't hit the server until that age is reached. This means fewer requests overall, reducing the server's load. However, once that age is reached or if &lt;code&gt;must-revalidate&lt;/code&gt; is set, having &lt;code&gt;ETag&lt;/code&gt; ensures that a full resource doesn't have to be resent if nothing has changed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bandwidth Efficiency&lt;/strong&gt;: By setting an &lt;code&gt;ETag&lt;/code&gt;, if the resource hasn't changed when validation is sought, the server can send back a &lt;code&gt;304 Not Modified&lt;/code&gt; without sending the actual resource data again, thus saving bandwidth.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Granular Control Over Caching&lt;/strong&gt;: Using &lt;code&gt;Cache-Control&lt;/code&gt;, you can define caching rules for different types of resources. For instance, images and stylesheets that change infrequently can have a longer &lt;code&gt;max-age&lt;/code&gt;, while dynamic content might have a shorter one or even a &lt;code&gt;no-cache&lt;/code&gt; directive. This granularity ensures optimal user experience and server performance.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why not just use ETag and skip cache-control?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi4dl969kcoehmqjtetmk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi4dl969kcoehmqjtetmk.png" alt="http headers showing etag and cache-control"&gt;&lt;/a&gt;Combining both ETag and Cache-Control allows for the most efficient caching possible.&lt;/p&gt;

&lt;p&gt;Certainly, you can use only &lt;code&gt;ETag&lt;/code&gt; for cache validation, but there are caveats:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Increased Server Requests&lt;/strong&gt;: Without &lt;code&gt;Cache-Control&lt;/code&gt;, clients might check with the server more frequently for resource validation. Even if the server is only returning &lt;code&gt;304 Not Modified&lt;/code&gt; statuses, it still means increased requests to handle and more round trips, causing slight delays.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Missed Optimization Opportunities&lt;/strong&gt;: &lt;code&gt;Cache-Control&lt;/code&gt; directives like &lt;code&gt;immutable&lt;/code&gt; can be invaluable for resources you're certain won't change, like versioned files. Without using these directives, you could be missing out on optimal caching behaviors.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lack of Control Over Where Content is Cached&lt;/strong&gt;: &lt;code&gt;Cache-Control&lt;/code&gt; allows you to specify whether a resource can be cached publicly (e.g., by CDNs) or only privately (e.g., by a user's browser). Without it, you lose this specificity.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Potential Over-Reliance on Validation&lt;/strong&gt;: If you only rely on &lt;code&gt;ETag&lt;/code&gt;, you're effectively forcing a check with the server every time a resource is requested, which might not always be necessary. It's like having a conversation where you continuously ask, "Has this changed?" instead of being told, "This won't change for the next hour."&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In summary, while &lt;code&gt;ETag&lt;/code&gt; alone offers a robust mechanism to ensure the freshness of cached content, combining it with &lt;code&gt;Cache-Control&lt;/code&gt; provides a more comprehensive and efficient caching strategy. It's the synergy between the "how long to cache" of &lt;code&gt;Cache-Control&lt;/code&gt; and the "has this changed" of &lt;code&gt;ETag&lt;/code&gt; that delivers the best results in web performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Love the cache
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Cache-Control&lt;/code&gt; and &lt;code&gt;ETag&lt;/code&gt; are instrumental in efficient web caching. Understanding and implementing these headers can drastically improve your website's load time and performance. While &lt;code&gt;Cache-Control&lt;/code&gt; sets the caching guidelines, &lt;code&gt;ETag&lt;/code&gt; validates the cached resources' freshness, ensuring that your users always get the latest and fastest content. By properly leveraging these two, developers can deliver a smoother and more efficient user experience.&lt;/p&gt;

</description>
      <category>http</category>
      <category>webdev</category>
      <category>webperf</category>
      <category>caching</category>
    </item>
    <item>
      <title>Simplify TypeScript builds with esbuild and skip tsc/tsx</title>
      <dc:creator>Andreas Bergström</dc:creator>
      <pubDate>Wed, 09 Aug 2023 07:49:22 +0000</pubDate>
      <link>https://forem.com/andreasbergstrom/simplify-typescript-builds-with-esbuild-and-skip-tsctsx-2124</link>
      <guid>https://forem.com/andreasbergstrom/simplify-typescript-builds-with-esbuild-and-skip-tsctsx-2124</guid>
      <description>&lt;p&gt;The JavaScript ecosystem constantly undergoes innovations. One of the more recent game-changers is esbuild, a lightning-fast JavaScript and TypeScript bundler. Unlike traditional TypeScript compilers like tsc, esbuild offers rapid compile times and a straightforward configuration. This post will delve into using esbuild to handle TypeScript compilation, emphasizing the vast array of parameters it offers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why esbuild over tsc?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: esbuild leverages Go's performance benefits, offering incredibly fast bundling times compared to other bundlers and compilers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplicity&lt;/strong&gt;: esbuild's configuration is relatively straightforward, making it easy to integrate into existing projects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexibility&lt;/strong&gt;: esbuild provides various options, like the ability to output to different formats, set the platform target, and more.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F461fh8uqnj6pl8hnv3wg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F461fh8uqnj6pl8hnv3wg.png" alt="esbuild running in watch mode"&gt;&lt;/a&gt;&lt;/p&gt;
Running esbuild in watch mode will allow you to use the same tool for production and development, without sacrificing performance!



&lt;h2&gt;
  
  
  Configuring esbuild for TypeScript
&lt;/h2&gt;

&lt;p&gt;Firstly, ensure esbuild is part of your project:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npm &lt;span class="nb"&gt;install &lt;/span&gt;esbuild &lt;span class="nt"&gt;--save-dev&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here's our proposed NPM script configuration using esbuild:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"esbuild `find src &lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;( -name '*.ts' &lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;)` --platform=node --target=esnext --outdir=build --format=cjs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"build:watch"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npm run build -- --watch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node build | npx pino-pretty"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"start:watch"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node --watch -r dotenv/config build | npx pino-pretty"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"concurrently &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;npm:build:watch&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;npm:start:watch&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;



&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;esbuild Parameters Explained:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Input Files&lt;/strong&gt;: The &lt;code&gt;find src \\( -name '*.ts' \\)&lt;/code&gt; portion locates all TypeScript files within the src&lt;code&gt;&lt;/code&gt;directory, feeding them to esbuild.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;platform&lt;/strong&gt;: The &lt;code&gt;--platform=node&lt;/code&gt; flag ensures the code is compatible with a Node.js environment. Other possible values include &lt;code&gt;browser&lt;/code&gt; for browser-specific output.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;target&lt;/strong&gt;: With &lt;code&gt;--target=esnext&lt;/code&gt;, we instruct esbuild to output the latest version of ECMAScript. This is invaluable when you want to leverage the latest language features. Other values could be &lt;code&gt;es6&lt;/code&gt;, &lt;code&gt;es2016&lt;/code&gt;, etc., depending on your needs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;outdir&lt;/strong&gt;: The &lt;code&gt;--outdir=build&lt;/code&gt; option specifies the output directory for our compiled files. Replace &lt;code&gt;build&lt;/code&gt; with any directory name of your choosing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;format&lt;/strong&gt;: The &lt;code&gt;--format=cjs&lt;/code&gt; command dictates the module system to be used. We've chosen CommonJS (&lt;code&gt;cjs&lt;/code&gt;) here, but esbuild also supports &lt;code&gt;esm&lt;/code&gt; (ES Modules), &lt;code&gt;iife&lt;/code&gt;, and more.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;watch&lt;/strong&gt;: Adding &lt;code&gt;--watch&lt;/code&gt; makes esbuild monitor file changes and recompile as necessary. This is invaluable during development, negating the need to manually trigger recompiles.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Concurrently&lt;/strong&gt;: Not an esbuild parameter, but vital for our setup. &lt;code&gt;concurrently&lt;/code&gt; runs multiple commands concurrently. In our script, it allows us to watch and build, and then run our application simultaneously.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Reaping the Rewards of esbuild
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bypass tsc/tsx&lt;/strong&gt;: Transitioning to esbuild means a direct reduction in compile times.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Simplified Build Pipeline&lt;/strong&gt;: The amalgamation of bundling and compiling under a single tool, esbuild, streamlines our pipeline.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Parameter-Driven Configuration&lt;/strong&gt;: esbuild's parameters allow developers to easily craft a build process tailored to their specific requirements.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;esbuild's emergence as a go-to TypeScript compiler promises faster development cycles and simplified build processes. Its array of parameters allows fine-grained control over the build, catering to a myriad of configurations. If you haven't yet, now might be the time to consider the switch from traditional &lt;code&gt;tsc&lt;/code&gt; compilation. Happy building!&lt;/p&gt;

</description>
      <category>node</category>
      <category>typescript</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>package.json: Not just a file, but a Developer's Toolkit</title>
      <dc:creator>Andreas Bergström</dc:creator>
      <pubDate>Tue, 08 Aug 2023 05:51:17 +0000</pubDate>
      <link>https://forem.com/andreasbergstrom/packagejson-not-just-a-file-but-a-developers-toolkit-2666</link>
      <guid>https://forem.com/andreasbergstrom/packagejson-not-just-a-file-but-a-developers-toolkit-2666</guid>
      <description>&lt;p&gt;Optimizing workflow is paramount for efficiency and productivity. A key player in achieving this within the Node.js ecosystem is the package.json file, a cornerstone for project configuration. This article delves into strategies that enhance the utility of npm scripts housed within package.json, guiding you from rudimentary implementations to intricate solutions tailored for sophisticated project demands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Script Hooks to Integrate Pre- and Post-Tasks
&lt;/h2&gt;

&lt;p&gt;Script hooks in &lt;code&gt;package.json&lt;/code&gt; provide the ability to set up preliminary or follow-up tasks around a primary script. By using the &lt;code&gt;pre&lt;/code&gt; and &lt;code&gt;post&lt;/code&gt; prefixes, you create an automated sequence of operations that run before or after your main task.&lt;/p&gt;

&lt;p&gt;Use Case: Consider a scenario where you want to lint your code before testing, and then clean up any generated artifacts after the test. Script hooks effortlessly weave these tasks together, ensuring your testing process is bracketed by necessary housekeeping tasks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"pretest"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"eslint ."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
  &lt;/span&gt;&lt;span class="nl"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
  &lt;/span&gt;&lt;span class="nl"&gt;"posttest"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rm -rf ./coverage"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Harness Environment Variables for Dynamic Script Execution
&lt;/h2&gt;

&lt;p&gt;Environment variables function as dynamic parameters within your scripts, enabling them to react to or utilize different settings or configurations. By tapping into &lt;code&gt;process.env.npm_package_*&lt;/code&gt;, you can access any field in your &lt;code&gt;package.json&lt;/code&gt;, letting scripts adapt based on the project's metadata.&lt;/p&gt;

&lt;p&gt;Use Case: Suppose you've created multiple deployment environments for your application. By utilizing environment variables, you can ensure your scripts adjust accordingly, fetching the correct configurations or assets for each environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-app"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node index.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"info"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"echo The current app is $npm_package_name@$npm_package_version"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Ensure Cross-Platform Compatibility with Adaptive Scripts
&lt;/h2&gt;

&lt;p&gt;Cross-platform compatibility ensures that your npm scripts perform consistently across different operating systems. By leveraging tools like &lt;code&gt;cross-env&lt;/code&gt;, you can write scripts that adapt and execute flawlessly, whether on Unix, Windows, or other platforms.&lt;/p&gt;

&lt;p&gt;Use Case: You're developing an application that will be deployed on various servers running different OS. To avoid deployment hiccups, ensuring that build, test, and other scripts run identically across these platforms is critical.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cross-env NODE_ENV=development node index.js"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Employ Concurrent Task Runners for Efficient Workflow
&lt;/h2&gt;

&lt;p&gt;Executing multiple tasks concurrently can streamline your workflow. Tools like &lt;code&gt;concurrently&lt;/code&gt; and &lt;code&gt;npm-run-all&lt;/code&gt; manage the simultaneous execution of scripts, helping save time and resources.&lt;/p&gt;

&lt;p&gt;Use Case: Imagine you're working on a web application. While the backend server runs, you might also want a file-watcher active, reloading the front end whenever changes are detected. Concurrent task runners make this multitasking a breeze.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"start:server"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node server.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"start:watch"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"nodemon ."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"concurrently npm:start:*"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Utilize Command Line Arguments to Customize Script Behavior
&lt;/h2&gt;

&lt;p&gt;With the aid of command-line arguments, npm scripts can be tuned on the fly, giving you finer control over their execution. By using the -- syntax, you can pass additional parameters or options directly to your scripts.&lt;/p&gt;

&lt;p&gt;Use Case: During development, you may need your server to run on different ports based on certain requirements or to avoid conflicts. Command line arguments offer the flexibility to alter this setting directly when running the script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node index.js --port=3000"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Embrace npm Lifecycle Scripts for Stage-Managed Operations
&lt;/h2&gt;

&lt;p&gt;npm lifecycle scripts determine the sequence of operations at different stages of your project's lifecycle. They provide structure and order, from initial setup (&lt;code&gt;prepublish&lt;/code&gt;) to subsequent updates or deployments (&lt;code&gt;postinstall&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Use Case: Before publishing a package to the npm registry, you might want to run tests and build the final version. Lifecycle scripts ensure these steps are followed in the right sequence, every time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"prepublish"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npm run test &amp;amp;&amp;amp; npm run build"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Document with Script Descriptions for Better Clarity
&lt;/h2&gt;

&lt;p&gt;Starting with npm v7, the ability to annotate your scripts using the &lt;code&gt;description&lt;/code&gt; field was introduced. This facilitates better documentation within the &lt;code&gt;package.json&lt;/code&gt; itself, aiding in understanding and collaboration.&lt;/p&gt;

&lt;p&gt;Use Case: As your project grows and more team members get involved, the purpose of certain scripts might become ambiguous. By providing descriptions, you ensure every team member understands each script's role, leading to smoother development cycles.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understand the Trade-offs: &amp;amp;&amp;amp; / &amp;amp; vs concurrently / npm-run-all
&lt;/h2&gt;

&lt;p&gt;The choice between using &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; / &lt;code&gt;&amp;amp;&lt;/code&gt; operators and tools like &lt;code&gt;concurrently&lt;/code&gt; or &lt;code&gt;npm-run-all&lt;/code&gt; might seem nuanced, but each has its advantages. The &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; operator ensures sequential execution, while &lt;code&gt;&amp;amp;&lt;/code&gt; runs scripts in parallel. However, for more sophisticated management of parallel tasks, including error handling and cross-platform compatibility, &lt;code&gt;concurrently&lt;/code&gt; and &lt;code&gt;npm-run-all&lt;/code&gt; offer more robust solutions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"start:server"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node server.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"start:watch"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"nodemon ."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"concurrently npm:start:*"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In further exploring the capabilities of npm scripts, it becomes evident that they encompass a comprehensive range of functionalities. The methodologies outlined here, ranging from foundational to advanced, serve as a structural basis upon which further optimizations can be instituted. It is recommended to adapt these strategies in alignment with the unique requirements and operational processes of your project.&lt;/p&gt;

&lt;p&gt;Use Case: In a project where you want to compile your code, start a server, and launch a watcher all at once, merely using the &amp;amp; operator could result in messy logs and unhandled errors. Tools like &lt;code&gt;concurrently&lt;/code&gt; allow you to run these tasks together but with cleaner output and better error management.&lt;/p&gt;

</description>
      <category>node</category>
      <category>npm</category>
    </item>
    <item>
      <title>The future of AI assistants might begin in your app settings</title>
      <dc:creator>Andreas Bergström</dc:creator>
      <pubDate>Mon, 07 Aug 2023 12:28:22 +0000</pubDate>
      <link>https://forem.com/andreasbergstrom/the-future-of-ai-assistants-revolutionizing-app-settings-using-large-language-models-382e</link>
      <guid>https://forem.com/andreasbergstrom/the-future-of-ai-assistants-revolutionizing-app-settings-using-large-language-models-382e</guid>
      <description>&lt;p&gt;In today's software-driven world the complexity of applications and their settings often overwhelms users. Every app seems to come with its own intricacies and nuances, which can often lead to an overwhelming number of customization options. We've all heard the phrase, "don't make everything a setting." It's an attempt to curb the confusion that arises when an app presents too many options to the user. However, as we strive to create more personalized user experiences, the challenge to balance accessibility and customization continues to persist.&lt;/p&gt;

&lt;p&gt;Enter the future of AI assistants, powered by Large Language Models (LLMs).&lt;/p&gt;

&lt;p&gt;LLMs are transforming the way we interact with applications by providing an innovative solution to this issue. AI assistants, backed by these robust models, are adept at understanding and manipulating complex information. The idea is to let these intelligent assistants take the reins and manage your app settings based on your preferences and patterns.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_fRy2UAI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lwl2lcia73go075ng31k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_fRy2UAI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lwl2lcia73go075ng31k.png" alt="Digging through app settings like these to find what you are looking for or just what's possible to configure might soon be as obsolete as floppy disks are today" width="355" height="712"&gt;&lt;/a&gt;Digging through app settings like these to find what you are looking for or just what's possible to configure might soon be as obsolete as floppy disks are today&lt;/p&gt;

&lt;h2&gt;
  
  
  How does this work?
&lt;/h2&gt;

&lt;p&gt;When you download an app, instead of sifting through a maze of settings, you could simply express your preferences to your AI assistant. For instance, you might tell it, "I like a dark theme, I don't want notifications while I'm at work, and I prefer to have privacy settings at the maximum." The AI assistant would understand these preferences, navigate the app's settings, and make the appropriate adjustments for you.&lt;/p&gt;

&lt;p&gt;Imagine never having to trawl through an application's settings or dig through online forums to understand how to change a particular setting. This would not only streamline the process but also make it far more user-friendly, particularly for those who might not be as technologically adept.&lt;/p&gt;

&lt;p&gt;Moreover, these AI assistants could also learn and adapt to your behavior over time. If the assistant notices that you usually mute a particular app during your working hours, it can suggest or automatically make this setting for you.&lt;/p&gt;

&lt;p&gt;The benefits are numerous. App developers can continue to provide a rich array of settings to cater to every possible user preference without overwhelming them. Users, on the other hand, get to enjoy a personalized experience without having to understand the intricacies of every app they use.&lt;/p&gt;

&lt;p&gt;As we lean into this AI-dominated paradigm, an interesting trend emerges: the gradual phasing out of traditional, hand-built UIs in favor of more fluid, AI-driven interfaces. The classic app settings menu, with its myriad of toggles and sliders, might just be the first casualty in this shift. In place of visually navigating through structured menus, users could soon be engaging in more conversational interactions with their software, simply expressing preferences or commands verbally or through text. This not only simplifies the interaction but also allows for a more organic relationship between user and application. &lt;/p&gt;

&lt;p&gt;Just as we saw the transition from command-line interfaces to graphical user interfaces, we might be on the cusp of another transformative shift: moving from static, user-driven settings interfaces to dynamic, AI-mediated conversations. This evolution could redefine our expectations of how software should respond and adapt to individual needs.&lt;/p&gt;

&lt;p&gt;However, like any transformative technology, this approach comes with its challenges. Privacy and security are prime concerns, as is the potential for AI bias. App developers and AI researchers need to work together to ensure that AI assistants are reliable, secure, and fair, and that they operate in a manner that respects user privacy.&lt;/p&gt;

&lt;p&gt;As we look to the future, one thing is clear: The advent of LLM-backed AI assistants is set to revolutionize how we interact with apps. By eliminating the need for users to grapple with complex settings, we are paving the way for a more seamless and intuitive user experience. We're on the brink of a new era where technology adapts to us, rather than the other way around. It's a future that promises to make our digital interactions more personalized, intuitive, and effortless.&lt;/p&gt;

</description>
      <category>llm</category>
      <category>ai</category>
      <category>machinelearning</category>
      <category>chatgpt</category>
    </item>
  </channel>
</rss>
