<?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>DEV Community: ByungJoon Lee</title>
    <description>The latest articles on DEV Community by ByungJoon Lee (@imjuni).</description>
    <link>https://dev.to/imjuni</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%2F1118217%2Fb9b4b755-bf16-428c-ab1c-da405082be1e.png</url>
      <title>DEV Community: ByungJoon Lee</title>
      <link>https://dev.to/imjuni</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/imjuni"/>
    <language>en</language>
    <item>
      <title>jin-frame: Declarative, Type-Safe HTTP Requests in TypeScript</title>
      <dc:creator>ByungJoon Lee</dc:creator>
      <pubDate>Mon, 25 Aug 2025 17:00:00 +0000</pubDate>
      <link>https://dev.to/imjuni/jin-frame-declarative-type-safe-http-requests-in-typescript-1j7m</link>
      <guid>https://dev.to/imjuni/jin-frame-declarative-type-safe-http-requests-in-typescript-1j7m</guid>
      <description>&lt;h2&gt;
  
  
  A Common Story
&lt;/h2&gt;

&lt;p&gt;One day, a teammate reaches out:  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“We’ve rolled out a new version of the API server. But the host has changed, so please update your client.”  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Suddenly, your mind goes blank. You’ve hardcoded &lt;strong&gt;&lt;code&gt;https://old-api.example.com&lt;/code&gt;&lt;/strong&gt; all over the place.&lt;br&gt;&lt;br&gt;
Now you’ll have to track down and replace every instance.  &lt;/p&gt;

&lt;p&gt;Another day, a data architect says:  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“For APIs a, b, and c, we need logging whenever they fail. Right now we have no logs, and it’s impossible to trace errors.”  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The problem? These APIs are called in dozens of places.&lt;br&gt;&lt;br&gt;
Adding error logging to every call would be a painful refactor.  &lt;/p&gt;

&lt;p&gt;Sound familiar?&lt;br&gt;&lt;br&gt;
This is exactly why I built &lt;strong&gt;jin-frame&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why jin-frame?
&lt;/h2&gt;

&lt;p&gt;jin-frame isn’t just another Axios wrapper.&lt;br&gt;&lt;br&gt;
It lets you define HTTP requests &lt;strong&gt;declaratively and type-safely using classes and decorators&lt;/strong&gt;.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🎩 &lt;strong&gt;Declarative API definitions&lt;/strong&gt; with decorators (&lt;code&gt;@Param&lt;/code&gt;, &lt;code&gt;@Query&lt;/code&gt;, &lt;code&gt;@Header&lt;/code&gt;, &lt;code&gt;@Body&lt;/code&gt;, &lt;code&gt;@ObjectBody&lt;/code&gt;)
&lt;/li&gt;
&lt;li&gt;⛑️ &lt;strong&gt;Type safety&lt;/strong&gt; enforced at compile-time
&lt;/li&gt;
&lt;li&gt;🎢 &lt;strong&gt;Production-ready features&lt;/strong&gt;: retry, timeout, hooks, file upload, mocking
&lt;/li&gt;
&lt;li&gt;🏭 &lt;strong&gt;Axios ecosystem compatibility&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;🎪 &lt;strong&gt;Extensible via inheritance&lt;/strong&gt;, so you can centralize config like host, timeout, or hooks
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Example: Inheritance for Clean API Structure
&lt;/h2&gt;

&lt;p&gt;With jin-frame, inheritance solves the exact problems we saw earlier:&lt;br&gt;&lt;br&gt;
“Host changed everywhere” or “Add common logging logic” becomes a one-line fix.&lt;/p&gt;

&lt;h3&gt;
  
  
  Base Class with Common Config
&lt;/h3&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;randomUUID&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;crypto&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;Get&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;host&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://pokeapi.co&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PokemonAPI&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;JinFrame&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PokeRes&lt;/span&gt;&lt;span class="o"&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="nd"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kr"&gt;declare&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="na"&gt;tid&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="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;override&lt;/span&gt; &lt;span class="nf"&gt;getDefaultValues&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="na"&gt;tid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;randomUUID&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="nx"&gt;override&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;$_postHook&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;reply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;debugInfo&lt;/span&gt;&lt;span class="p"&gt;)&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="nx"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`[Error] &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;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="c1"&gt;// add your logging ...&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;ul&gt;
&lt;li&gt;Every Pokémon API request shares the same &lt;strong&gt;host/timeout&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;tid&lt;/code&gt; field is automatically added for request tracing
&lt;/li&gt;
&lt;li&gt;A common &lt;strong&gt;postHook&lt;/strong&gt; handles error logging
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Child Class: Pokémon by Name
&lt;/h3&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;Get&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/v2/pokemon/:name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PokemonByName&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;PokemonAPI&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IPokemonData&lt;/span&gt;&lt;span class="o"&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="nd"&gt;Param&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kr"&gt;declare&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="na"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Inherits host, timeout, and hooks from the parent
&lt;/li&gt;
&lt;li&gt;Child only needs to define its own &lt;code&gt;path&lt;/code&gt; and &lt;code&gt;name&lt;/code&gt; param
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Usage
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;frame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;PokemonByName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&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;pikachu&lt;/span&gt;&lt;span class="dl"&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;reply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now when the API host changes, you only update the &lt;strong&gt;parent class&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
When common logging is required, update the &lt;strong&gt;parent hook&lt;/strong&gt;—all children inherit it.&lt;br&gt;&lt;br&gt;
And if needed, child classes can override hooks for special cases.  &lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Centralized config&lt;/strong&gt;: Manage host, timeout, and hooks in one place
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extensibility&lt;/strong&gt;: Override only what you need in child classes
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Traceability&lt;/strong&gt;: Automatic fields (e.g. &lt;code&gt;tid&lt;/code&gt;) for request tracking
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistency&lt;/strong&gt;: Every API request looks and behaves the same
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of scattering functions across your codebase, inheritance keeps things clean.&lt;br&gt;&lt;br&gt;
As projects grow, this structure dramatically reduces maintenance overhead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;jin-frame is built for developers who:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Are tired of repetitive, scattered HTTP request code
&lt;/li&gt;
&lt;li&gt;Need easy-to-apply features like retry, logging, and timeout
&lt;/li&gt;
&lt;li&gt;Want a request layer reusable across Next.js RSC and CSR
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 &lt;a href="https://imjuni.github.io/jin-frame/" rel="noopener noreferrer"&gt;Check out jin-frame&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;With jin-frame, you’ll never again panic over “The host changed, now what?”&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>axios</category>
      <category>opensource</category>
      <category>msa</category>
    </item>
    <item>
      <title>AsyncContext, easily managing shared data</title>
      <dc:creator>ByungJoon Lee</dc:creator>
      <pubDate>Mon, 25 Mar 2024 18:00:00 +0000</pubDate>
      <link>https://dev.to/imjuni/asynccontext-easily-managing-shared-data-ih</link>
      <guid>https://dev.to/imjuni/asynccontext-easily-managing-shared-data-ih</guid>
      <description>&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;This document introduces the &lt;a href="https://github.com/tc39/proposal-async-context"&gt;AsyncContext&lt;/a&gt; feature. AsyncContext is a feature in TC39 &lt;a href="https://tc39.es/process-document/"&gt;Stage2&lt;/a&gt;. I introduce it because it has been included in the Node.js environment since v12 and continues to be improved in versions like v16, v18, v20, etc.&lt;/p&gt;

&lt;p&gt;When running a synchronous function, creating a context before running the function allows the function to maintain and utilize the context while it runs. Synchronous functions can utilize the context because no other functions are executed while it is executed, so the value of the context can be guaranteed if the executing function does not change it, but asynchronous functions cannot guarantee the value of the context because other functions may be executed. Therefore, it is inconvenient to keep passing values such as tracking id, request id, etc. for tracking or settings such as language, cache life cycle, etc. as arguments to the function.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Polyglot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node-polyglot&lt;/span&gt;&lt;span class="dl"&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;polyglot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;ko&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Polyglot&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;phrases&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;hello_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;안녕하세요! %{name}님&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="na"&gt;en&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Polyglot&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;phrases&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;hello_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;Hola %{name}&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;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;child01&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lang&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;polyglot&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello_name&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="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;hello&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;child02&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lang&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;child01&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lang&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;child03&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lang&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;child02&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;child04&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lang&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;child03&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;child05&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lang&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;child04&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;parent&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;FastifyRequest&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;lang&lt;/span&gt; &lt;span class="o"&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;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;accpet-language&lt;/span&gt;&lt;span class="dl"&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;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;child05&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lang&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="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&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;In the example above, the parent function uses the child05 function to get the message value, but the child05 function actually runs several other functions to get the message.&lt;/p&gt;

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

&lt;p&gt;In the example code above, you can see that child02, child03, child04, and child05 don't use the language argument value, but the lang value is still passed as an argument to the child01 function to pass the language value. However, we can easily change this structure by utilizing context.&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AsyncLocalStorage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;AsyncResource&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;async_hooks&lt;/span&gt;&lt;span class="dl"&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;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AsyncLocalStorage&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;Polyglot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node-polyglot&lt;/span&gt;&lt;span class="dl"&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;polyglot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;ko&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Polyglot&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;phrases&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;hello_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;안녕하세요! %{name}님&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="na"&gt;en&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Polyglot&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;phrases&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;hello_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;Hola %{name}&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;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;child01&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;currentStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getStore&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;language: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;currentStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lang&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;polyglot&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;currentStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello_name&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="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;hello&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;child02&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="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;child01&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;child03&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="nf"&gt;child02&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&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;child04&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="nf"&gt;child03&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&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;child05&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="nf"&gt;child04&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&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;parent&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="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt; &lt;span class="o"&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;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;accpet-language&lt;/span&gt;&lt;span class="dl"&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;store&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="nx"&gt;lang&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="k"&gt;async &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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AsyncResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fastify-async-context&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="nx"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;runInAsyncScope&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;child05&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lang&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="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&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;return&lt;/span&gt; &lt;span class="nx"&gt;result&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;In this example, unlike before, you can see that the lang value is not passed as an argument to the child01, child02, child03, child04, and child05 functions. Even though it is not passed as an argument, you can see that the child01 function uses AsyncContext to read the language value.&lt;/p&gt;

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

&lt;p&gt;You can expect to be more productive and better able to utilize a variety of data because you won't have to keep passing AsyncContext the information it needs as function arguments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Case study of AsyncContext
&lt;/h2&gt;

&lt;p&gt;I'm going to describe in more detail my experience using AsyncContext in a useful way. However, browsers don't support AsyncContext yet, so we have to use alternatives like &lt;a href="https://www.npmjs.com/package/zone.js"&gt;zone.js&lt;/a&gt;. So let's take a look at how we can utilize AsyncContext in a Node.js environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Request ID &amp;amp; Tracking ID
&lt;/h3&gt;

&lt;p&gt;Giving every request a unique ID is useful for analyzing problems in case of failures, bugs, etc. fastify.js provides the ability to generate Request IDs.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tidSymbol&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tid&lt;/span&gt;&lt;span class="dl"&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;fastify&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fastify&lt;/span&gt;&lt;span class="dl"&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;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fastify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; 
  &lt;span class="na"&gt;genReqId&lt;/span&gt;&lt;span class="p"&gt;:&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="o"&gt;=&amp;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;tid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;randomUUID&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;tidSymbol&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tid&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;tid&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;The request is now given a unique UUID, and once we have this UUID, we can track the request. Let's make it a little more useful. Store the UUID in the AsyncContext.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fastify&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fastify&lt;/span&gt;&lt;span class="dl"&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;AsyncResource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;executionAsyncId&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;async_hooks&lt;/span&gt;&lt;span class="dl"&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;fastifyRequestContext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@fastify/request-context&lt;/span&gt;&lt;span class="dl"&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;crypto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;crypto&lt;/span&gt;&lt;span class="dl"&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;tidSymbol&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fastify-request-context-tracking-id&lt;/span&gt;&lt;span class="dl"&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;resourceType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fastify-request-context&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Create fastify server with request ID generator&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fastify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; 
  &lt;span class="na"&gt;genReqId&lt;/span&gt;&lt;span class="p"&gt;:&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="o"&gt;=&amp;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;tid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randomUUID&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;tidSymbol&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tid&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;tid&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="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fastifyRequestContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;defaultStoreValues&lt;/span&gt;&lt;span class="p"&gt;:&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;tid&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;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;lang&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;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;accept-language&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;resourceType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;triggerAsyncId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;executionAsyncId&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="na"&gt;createAsyncResource&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;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AsyncResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resourceType&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;Now we can access &lt;code&gt;req.id&lt;/code&gt; from every fastify request handlers, and use &lt;code&gt;AsyncContext&lt;/code&gt; in other functions to extract the request ID.&lt;/p&gt;

&lt;h3&gt;
  
  
  TypeORM with AsyncContext
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://typeorm.io/"&gt;TypeORM&lt;/a&gt; is a library that allows various databases to be used in the Node.js environment. ORM libraries provide the ability to log the queries they execute. TypeORM also provides the feature to log all queries, slow queries, query errors, and more. Combining the logging features with the Request ID mentioned earlier makes for a useful log.&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;AbstractLogger&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="s2"&gt;typeorm&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;class&lt;/span&gt; &lt;span class="nc"&gt;MyCustomLogger&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AbstractLogger&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="cm"&gt;/**
   * Write log to specific output.
  */&lt;/span&gt;
  &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nf"&gt;writeLog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LogLevel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;logMessage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LogMessage&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;LogMessage&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;
        &lt;span class="nx"&gt;queryRunner&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;QueryRunner&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;// implementation of writeLog ...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cm"&gt;/**
   * Logs query that is slow.
   */&lt;/span&gt;
  &lt;span class="nf"&gt;logQuerySlow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;time&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="nx"&gt;query&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="nx"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;_queryRunner&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;QueryRunner&lt;/span&gt;&lt;span class="p"&gt;)&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="nf"&gt;isFalse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isLogEnabledFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;query-slow&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;return&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;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getAsyncStore&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`[&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tid&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nf"&gt;randomUUID&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;][&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;]show query: `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;parameters&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;The example above logs the slow query with a tid, where tid is the &lt;code&gt;request.id&lt;/code&gt; you stored in AsyncLocalStorage before. This allows you to quickly track which APIs are causing the slow queries, and is useful for planning fixes by knowing how often your APIs are being called.&lt;/p&gt;

&lt;h3&gt;
  
  
  translate with AsyncContext
&lt;/h3&gt;

&lt;p&gt;I use the i18n library to create multilingual messages. I use &lt;a href="https://www.npmjs.com/package/node-polyglot"&gt;node-polyglot&lt;/a&gt;, which requires me to decide which language to use before using the translate function. To determine the language, I have to keep passing the language to different functions, as mentioned in the background, and this is where AsyncContext can be used to simplify the process.&lt;/p&gt;

&lt;h3&gt;
  
  
  getAsyncStore function
&lt;/h3&gt;

&lt;p&gt;We've seen situations where it's useful to use AsyncContext, so let's see how we can get AsyncLocalStorage. There are two ways you can get AsyncLocalStorage. The first way is to use Hooks to create a copy of the AsyncResource when it is created and destroyed. This approach is explained in &lt;a href="https://blog.besson.co/nodejs_async_hooks_to_get_per_request_context/"&gt;Getting per-request context in NodeJS with async_hooks&lt;br&gt;
&lt;/a&gt;. The second method is to use &lt;code&gt;executionAsyncResource&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;executionAsyncResource&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;node:async_hooks&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;randomUUID&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;node:crypto&lt;/span&gt;&lt;span class="dl"&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;function&lt;/span&gt; &lt;span class="nf"&gt;getAsyncStore&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="nx"&gt;key&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="nx"&gt;unknown&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;acquiredExecutionAsyncResource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;executionAsyncResource&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;unknown&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;keys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getOwnPropertySymbols&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;acquiredExecutionAsyncResource&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;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;acquiredExecutionAsyncResource&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;tid&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&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="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;tid&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&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="s2"&gt;`unde&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;randomUUID&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&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;return&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tid&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;You can use the &lt;code&gt;Object.getOwnPropertySymbols&lt;/code&gt; function to extract the key of the AsyncResource, and that way you can get the AsyncLocalStorage. It doesn't matter which method you choose, but in my personal experience, the first method sometimes doesn't retrieve the AsyncLocalStorage, so if you want it to work every time, I recommend using the second method.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;AsyncContext is still in Stage 2, and if you look at the official Node.js &lt;a href="https://nodejs.org/api/async_hooks.html"&gt;reference documentation&lt;/a&gt;, each version has a slightly different implementation, so it may be difficult to use if you are using Node.js v16 or lower. Also, the specification may change because it is in Stage 2. Nevertheless, AsyncContext is attractive. It's very useful to be able to get a common value from somewhere without having to add all the arguments to a function, so if you're building a new environment or using Node.js v16 or later, you should definitely take a look at it. Thank you for reading the documentation so far!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>ctix - barrel file generator using TypeScript Compiler API</title>
      <dc:creator>ByungJoon Lee</dc:creator>
      <pubDate>Tue, 14 Nov 2023 10:00:00 +0000</pubDate>
      <link>https://dev.to/imjuni/ctix-barrel-file-generator-using-typescript-compiler-api-5549</link>
      <guid>https://dev.to/imjuni/ctix-barrel-file-generator-using-typescript-compiler-api-5549</guid>
      <description>&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;In the past, I've written barrel files for various open source projects and work-related libraries. &lt;a href="https://basarat.gitbook.io/typescript/main-1/barrel"&gt;Barrel files&lt;/a&gt; are often used to simplify import statements, or to allow libraries to be exported to other projects. I've seen them in action recently, especially in the Next.js project, where they've been utilized to improve performance.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://basarat.gitbook.io/typescript/main-1/barrel"&gt;TypeScript Deep Dive - barrel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vercel.com/blog/how-we-optimized-package-imports-in-next-js"&gt;How we optimized package imports in Next.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Problems when developers write their own barrel files
&lt;/h2&gt;

&lt;p&gt;At first, you'll probably write most of your barrel files by hand, but since it's a fairly repetitive task, you'll probably want to find a tool to automate it. There are a couple of tools to automatically write barrel files.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CLI

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/bencoveney/barrelsby"&gt;barrelsby&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/stolinski/barrelbot"&gt;barrelbot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/gajus/create-index"&gt;create-index&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;IDE

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=eliostruyf.vscode-typescript-exportallmodules"&gt;VSCODE - TypeScript Barrel Generator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://plugins.jetbrains.com/plugin/14990-barrels"&gt;WebStorm - Barrels&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These tools are awesome, but they mostly work based on directory traversal and filenames. While this works well in many cases, it has limitations in some situations. For example, &lt;a href="https://github.com/airbnb/javascript"&gt;eslint-config-airbnb&lt;/a&gt; recommends writing a class or function in a single file, and thus prefers to use &lt;code&gt;default export&lt;/code&gt;. In the case of &lt;code&gt;default export&lt;/code&gt;, the filename and the name of the &lt;code&gt;default export&lt;/code&gt; statement may not match, but directory traversal and filename-based approaches cannot separate filenames from variable names.&lt;/p&gt;

&lt;p&gt;These tools also have the limitation of not being recognized for empty files or test cases. Test cases can be filtered out through the glob pattern, but recognizing empty files is a challenge. Furthermore, barrel files are a collection of multiple &lt;code&gt;export&lt;/code&gt; statements in one file, which can cause compilation errors if there are duplicate names. It is difficult to reliably filter out these duplicates with filename-based processing.&lt;/p&gt;

&lt;p&gt;Considering these points, I came to the conclusion that while directory traversal and filename-based approaches are quick and easy, they may not be useful in complex projects. I recognized the need for a different approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automate barrel file writing with the TypeScript Compiler API
&lt;/h2&gt;

&lt;p&gt;At first, I tried to solve the problem with a directory traversal and filename-based approach. I developed and used &lt;a href="https://github.com/imjuni/create-ts-index"&gt;create-ts-index&lt;/a&gt; for this purpose, but after experiencing the previously mentioned issues, I recognized the limitations of this approach. I decided that it needed to be improved, so I developed and used &lt;a href="https://github.com/imjuni/ctix"&gt;ctix&lt;/a&gt;. ctix utilizes the &lt;a href="https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API"&gt;Typescript Compiler API&lt;/a&gt; to write barrel files. This approach solved most of the problems I mentioned earlier.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;default export&lt;/code&gt; statement can handle different filenames and variable names&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;// button.component.ts&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="o"&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="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getInitialProps&lt;/span&gt; &lt;span class="o"&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="cm"&gt;/* ... */&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="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The file is named &lt;code&gt;button.component.ts&lt;/code&gt;, but in the export statement it is named &lt;code&gt;Button&lt;/code&gt;. Since &lt;a href="https://github.com/imjuni/ctix"&gt;ctix&lt;/a&gt; uses the Typescript compiler API to get variable names, the above can be added to the barrel file without error.&lt;/p&gt;

&lt;p&gt;When there are multiple &lt;code&gt;export statements&lt;/code&gt; in a file, it is possible to exclude only some of them from the barrel 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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;dog&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// @ctix-exclude-next&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;peach&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&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;function&lt;/span&gt; &lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&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 look at the code above, you'll see that I've excluded &lt;code&gt;peach&lt;/code&gt;, which has a different personality, from the barrel file. In this case, the barrel file is written as shown below.&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;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;dog&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cat&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;./animal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In addition, &lt;a href="https://github.com/imjuni/ctix"&gt;ctix&lt;/a&gt; can write barrel files with filenames using module mode since version 2.1. Front-end component projects such as &lt;a href="https://vuejs.org/"&gt;Vue&lt;/a&gt; and &lt;a href="https://svelte.dev/"&gt;Svelte&lt;/a&gt; have a different syntax and cannot be parsed using the TypeScript compiler API, so typically Vue and Svelte components use filenames as names and are registered as modules in TypeScript as type files.&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="kr"&gt;declare&lt;/span&gt; &lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*.vue&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="nx"&gt;Vue&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;vue&lt;/span&gt;&lt;span class="dl"&gt;'&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="nx"&gt;Vue&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;The above code is a type file written to make files with the &lt;code&gt;.vue&lt;/code&gt; extension recognized as modules by Typescript. With this setup, Typescript cannot directly parse the contents of a &lt;code&gt;.vue&lt;/code&gt; file, but it will recognize it as a module. &lt;a href="https://github.com/imjuni/ctix"&gt;ctix&lt;/a&gt; takes advantage of this, first writing barrel files for Vue components based on filenames and directory traversal.&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;/// &amp;lt;reference path="../types/vue.d.ts" /&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Button&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;./Button.vue&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="nx"&gt;Accordion&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;./Accordion.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Accordion&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unfortunately, the reference setting with the triple slash in the first line must be handled by the developer. It can be passed using the &lt;a href="https://github.com/imjuni/ctix/blob/master/doc/OPTION_BUILD_MODULE.md"&gt;directive option&lt;/a&gt;. This will automatically add the TypeScript compiler API to the barrel file and affect the next barrel file writing operation, meaning that both actual TypeScript files and Vue components will be able to write barrel files. I've uploaded a working example to &lt;a href="https://github.com/imjuni/ctix/blob/master/example/type10"&gt;example/type10&lt;/a&gt; and a &lt;a href="https://github.com/imjuni/ctix/blob/master/example/type10/.ctirc"&gt;configuration file&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Duplicate &lt;code&gt;export statement&lt;/code&gt;s can also be better detected.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;marvel.ts&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ironman&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ironman is awesome!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;avengers.ts&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ironman&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;avengers assemble!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because of the different file names, duplicate detection is difficult to do with filename and directory traversal, but it can be achieved using the Typescript compiler API. To prevent errors in situations like this, &lt;a href="https://github.com/imjuni/ctix"&gt;ctix&lt;/a&gt; excludes duplicate statements and outputs warning messages to help developers recognize errors.&lt;/p&gt;

&lt;p&gt;By using the TypeScript compiler API, it can correctly handle most of the &lt;a href="https://github.com/imjuni/ctix/blob/master/src/compilers/getExportedKind.ts"&gt;export syntax&lt;/a&gt; used by TypeScript, and it can write barrel files using actual code, as compared to the filename and directory traversal approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/imjuni/ctix"&gt;ctix&lt;/a&gt; is a tool that writes barrel files correctly in a variety of situations. It's designed to free developers from having to care about barrel files themselves, and offers a number of features including duplicate detection, exclusion of particular statements, and support for Vue and Svelte components. However, because it uses the TypeScript compiler API, it is slower than barrel file writing based on filenames and directory traversal. It also requires a tsconfig.json file to be provided for it to work correctly. To solve these problems, I've added the ability to generate a configuration file via an interactive prompt with the &lt;code&gt;init&lt;/code&gt; command, and improved performance by minimizing the scope of the TypeScript compiler API's project analysis.&lt;/p&gt;

&lt;p&gt;With &lt;a href="https://github.com/imjuni/ctix"&gt;ctix&lt;/a&gt;, you can automate the hassle of writing barrel files. Give it a try and let us know what you think so for us to make &lt;a href="https://github.com/imjuni/ctix"&gt;ctix&lt;/a&gt; even better!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>barrel</category>
      <category>typescript</category>
      <category>cli</category>
    </item>
    <item>
      <title>In-Depth guide for TypeScript Library</title>
      <dc:creator>ByungJoon Lee</dc:creator>
      <pubDate>Mon, 13 Nov 2023 12:12:45 +0000</pubDate>
      <link>https://dev.to/imjuni/in-depth-guide-for-typescript-library-project-o1j</link>
      <guid>https://dev.to/imjuni/in-depth-guide-for-typescript-library-project-o1j</guid>
      <description>&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;It's a common approach in development projects to separate common business logic into functions or classes within the same project for reuse. As a project grows in size, some logic may be more efficiently isolated into separate packages and used in other projects. In my experience, functions like login, logout, and logging are easier to maintain and adapt in the long run if they are separated into separate library packages. I've reviewed several articles on writing library packages, but here I'm going to summarize some of the more specialized topics that aren't covered in those articles.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's the problem?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Barrel file, edit over and over again
&lt;/h3&gt;

&lt;p&gt;To simplify the &lt;code&gt;import&lt;/code&gt; syntax, the file that holds the &lt;code&gt;export&lt;/code&gt; syntax is called a &lt;a href="https://basarat.gitbook.io/typescript/main-1/barrel"&gt;barrel file&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;barrel file&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Button&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;./button/index.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Accordion&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;./accordion/index.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Notification&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;./notification/index.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;other file&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&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;Button&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;../../src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Barrel files are commonly found in component library projects. For example, you can find a &lt;a href="https://github.com/mantinedev/ui.mantine.dev/blob/master/lib/index.ts"&gt;Barrel file&lt;/a&gt; in the &lt;a href="https://github.com/mantinedev/ui.mantine.dev"&gt;Mantine&lt;/a&gt; project. Since there are often no dependencies between each component or feature in a library project, it often happens that the bundler does not include all the files even when using a dependency graph. This is where the barrel file comes into handy. By specifying the barrel file in the main and module fields of the &lt;code&gt;package.json&lt;/code&gt; file, it also serves as a point of execution for the Node.js interpreter or the browser's script tag. Barrel files are often written by developers themselves because they fulfill an important function.&lt;/p&gt;

&lt;p&gt;However, it is a big challenge for developers to write barrel files themselves. In projects like &lt;a href="https://github.com/mantinedev/ui.mantine.dev"&gt;Mantine&lt;/a&gt; and &lt;a href="https://github.com/date-fns/date-fns"&gt;date-fns&lt;/a&gt;, which are already very large, it is not easy to write a barrel file every time there is a change, and if it is included in a VCS(e.g. &lt;code&gt;git&lt;/code&gt;), it increases the probability of conflicts when multiple developers collaborate. Therefore, I thought there is a need for a way to automatically generate barrel files based on certain rules and not include them in a VCS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use &lt;a href="https://www.typescriptlang.org/tsconfig#paths"&gt;Paths Re-Maps&lt;/a&gt; ?
&lt;/h3&gt;

&lt;p&gt;To import classes, functions, constants, etc. from another script in TypeScript and JavaScript, you need to enter the relative path to the script you want to call from the current script.&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="nx"&gt;chunkArray&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;../../tools/array/chunkArray&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getBulkInsertFruit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fruits&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="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunkArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fruits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&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="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunk&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;In the example code above, you can see that we imported the function with a relative path. Using relative paths is inconvenient because the import statement is always different. Using a barrel file doesn't improve things much, and it's a difficult problem to solve without the help of an IDE. That's why TypeScript provides the &lt;a href="https://www.typescriptlang.org/tsconfig#paths"&gt;Paths Re-Map&lt;/a&gt; feature.&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="nx"&gt;chunkArray&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;#/tools/array/chunkArray&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getBulkInsertFruit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fruits&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="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunkArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fruits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&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="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunk&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 look at the example code above, you can see that we've imported the &lt;code&gt;chunkArray&lt;/code&gt; function as if we were using an absolute path. This feature allows you to use the same import statement for all your files and reduces the amount of work when refactoring to change paths or filenames. However, since this feature is not provided by ECMA Script, it creates a number of problems: not only do you have to tell your test frameworks like jest and vitest to set up Paths Re-Map, but you also have to tell your bundlers about it. It also affects the bundling of &lt;code&gt;.d.ts&lt;/code&gt; files, which we will discuss in the next chapter. Since this issue is the same for library packages and applications alike, we also need a way to work around it.&lt;/p&gt;

&lt;h3&gt;
  
  
  bundling for &lt;code&gt;.d.ts&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;In order for a TypeScript-based library package to be used by other TypeScript projects, it is necessary to provide the type files (.d.ts) along with the JavaScript files. To do this, the &lt;code&gt;types&lt;/code&gt; field in the &lt;code&gt;package.json&lt;/code&gt; file sets the entry point for the type files. However, there is no official way to effectively bundle type files. There was a discussion about this, but the issue was closed without a clear solution to the problem.&lt;/p&gt;

&lt;p&gt;Using TypeScript's Paths Re-Map feature further complicates matters. TypeScript has &lt;a href="https://github.com/microsoft/TypeScript/issues/5039"&gt;defined module renaming for Paths Re-Mapped modules as the role of the bundler&lt;/a&gt;, which means that when using Paths Re-Map, providing a type file requires you to do two things: convert the Paths Re-Map of that type file to a relative path and bundle it. This can make it difficult for library package developers to efficiently manage and ship type files.&lt;/p&gt;

&lt;h2&gt;
  
  
  How can we solve it?
&lt;/h2&gt;

&lt;p&gt;If you don't use bundlers and Paths Re-Map, you can avoid the issues involved. However, you'll still need to manually write your barrel files, and as your library package grows in size, it can be inefficient to use only the basic functionality. So, let's take a look at how you can solve the problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Automatically generate a barrel file
&lt;/h3&gt;

&lt;p&gt;I've been working on automating barrel files for a long time, and in the process have developed &lt;a href="https://github.com/imjuni/ctix"&gt;ctix&lt;/a&gt;. The 1.x version had some inconveniences, but with the 2.x version, I've improved these issues and made it more user-friendly. &lt;a href="https://github.com/imjuni/ctix"&gt;ctix&lt;/a&gt; uses the TypeScript Compiler API to automatically generate barrel files by extracting statements containing the &lt;code&gt;export&lt;/code&gt; keyword. The advantage of ctix is that barrel files are automatically generated, so you don't have to manage them separately in your version control system (VCS), e.g. git. It also has the advantage of always generating compilable barrel files because it uses the TypeScript Compiler API to extract only &lt;code&gt;export&lt;/code&gt; statements.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;.d.ts&lt;/code&gt; bundling
&lt;/h3&gt;

&lt;p&gt;This is a really hard problem. For now, there are &lt;a href="https://github.com/Microsoft/TypeScript/issues/4433"&gt;discussions&lt;/a&gt; going on within the TypeScript community to resolve this issue, but they are inconclusive, and have been for a long time. So we need to use external tools to solve this problem. Currently, the popular &lt;code&gt;.d.ts&lt;/code&gt; bundling tools are as follows&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://api-extractor.com/"&gt;API Extractor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/timocov/dts-bundle-generator"&gt;dts-bundle-generator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Swatinem/rollup-plugin-dts"&gt;rollup-plugin-dts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/wessberg/rollup-plugin-ts"&gt;rollup-plugin-ts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jeremyben/tsc-prog"&gt;tsc-prog&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are many more tools than those listed above. You can check out &lt;a href="https://github.com/Microsoft/TypeScript/issues/4433"&gt;discussion&lt;/a&gt; and &lt;a href="https://github.com/timocov/dts-bundle-generator/discussions/68"&gt;comparison&lt;/a&gt; of bundling tools. Unfortunately, choosing the right tool among them is a process that you'll have to experiment with and decide for your own project needs. For example, &lt;a href="https://github.com/timocov/dts-bundle-generator"&gt;dts-bundle-generator&lt;/a&gt;, &lt;a href="https://api-extractor.com/"&gt;API Extractor&lt;/a&gt;, and &lt;a href="https://github.com/Swatinem/rollup-plugin-dts"&gt;rollup-plugin-dts&lt;/a&gt; do not support &lt;code&gt;.d.ts.map&lt;/code&gt; files. Also, &lt;a href="https://api-extractor.com/"&gt;API Extractor&lt;/a&gt; and &lt;a href="https://github.com/timocov/dts-bundle-generator"&gt;dts-bundle-generator&lt;/a&gt; do not have chunking capabilities, &lt;a href="https://github.com/Swatinem/rollup-plugin-dts"&gt;rollup-plugin-dts&lt;/a&gt; is currently in maintenance mode, and the &lt;code&gt;default export&lt;/code&gt; and &lt;code&gt;export&lt;/code&gt; statements differ in the way different bundlers generate output. Therefore, you should carefully select and use the most appropriate tool based on your project's configuration.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/timocov/dts-bundle-generator"&gt;dts-bundle-generator&lt;/a&gt; is a lightweight and easy tool. If you pass a barrel file generated using &lt;a href="https://github.com/imjuni/ctix"&gt;ctix&lt;/a&gt; to &lt;a href="https://github.com/timocov/dts-bundle-generator"&gt;dts-bundle-generator&lt;/a&gt; and just specify the path to the output file, it will work fine in most cases without any additional setup. However, if you are using the latest version of &lt;a href="https://fastify.dev/"&gt;Fastify.js&lt;/a&gt; in your backend development, you may encounter an issue where bundling fails because &lt;code&gt;Symbol.asyncDispose&lt;/code&gt; is not found. This is due to the way the &lt;a href="https://github.com/timocov/dts-bundle-generator"&gt;dts-bundle-generator&lt;/a&gt; loads only necessary modules for performance optimization, which prevents it from loading some &lt;code&gt;.d.ts&lt;/code&gt; files. There is a &lt;a href="https://github.com/timocov/dts-bundle-generator/discussions/232"&gt;workaround&lt;/a&gt; being discussed for this, but it didn't work in my case. Nevertheless, the tool generally works well and is easy to use with a few simple option settings, and I recommend testing in a live environment if you are considering adopting it.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/Swatinem/rollup-plugin-dts"&gt;rollup-plugin-dts&lt;/a&gt; is a plugin that is currently in maintenance mode, but still works well. However, this plugin only performs bundling correctly for &lt;code&gt;.d.ts&lt;/code&gt; files that do not use Paths Re-Map. By the way, even if you create a &lt;code&gt;.d.ts&lt;/code&gt; file using &lt;a href="https://github.com/rollup/plugins/tree/master/packages/typescript"&gt;@rollup/plugin-typescript&lt;/a&gt;, this does not fully resolve Paths Re-Map. For this, you need to use &lt;a href="https://github.com/justkey007/tsc-alias"&gt;tsc-alias&lt;/a&gt; to resolve Paths Re-Map issues. After resolving Paths Re-Map, bundling with &lt;a href="https://github.com/wessberg/rollup-plugin-ts"&gt;rollup-plugin-ts&lt;/a&gt; works well to generate a &lt;code&gt;.d.ts&lt;/code&gt; file. However, even with this method, the ability to generate &lt;code&gt;.map&lt;/code&gt; files and the &lt;code&gt;chunking&lt;/code&gt; feature is not available. Given that library projects are often bundled as part of JavaScript projects, I think these limitations are acceptable.&lt;/p&gt;

&lt;p&gt;I use &lt;a href="https://github.com/imjuni/ctix"&gt;ctix&lt;/a&gt; for barrel file generation and &lt;a href="https://github.com/Swatinem/rollup-plugin-dts"&gt;rollup-plugin-dts&lt;/a&gt; and &lt;a href="https://github.com/justkey007/tsc-alias"&gt;tsc-alias&lt;/a&gt; for bundling. However, this method may not be suitable for monorepos consisting of multiple packages or if the &lt;code&gt;composite&lt;/code&gt; option is set in &lt;code&gt;tsconfig&lt;/code&gt;. Before introducing &lt;a href="https://github.com/imjuni/ctix"&gt;ctix&lt;/a&gt; or &lt;code&gt;.d.ts&lt;/code&gt; bundling tools to your ongoing library packages, it is important to test them and make sure they are suitable before applying them.&lt;/p&gt;

&lt;h3&gt;
  
  
  default export, export
&lt;/h3&gt;

&lt;p&gt;There has been some &lt;a href="https://github.com/airbnb/javascript/issues/1365"&gt;discussion&lt;/a&gt; about the use of &lt;code&gt;default export&lt;/code&gt; vs &lt;code&gt;export&lt;/code&gt;, but it's hard to conclude unequivocally that one is better. For example, &lt;a href="https://github.com/airbnb/javascript#modules--prefer-default-export"&gt;eslint-config-airbnb&lt;/a&gt; recommends using &lt;code&gt;default export&lt;/code&gt;. However, when developing &lt;a href="https://github.com/imjuni/ctix"&gt;ctix&lt;/a&gt; and using the TypeScript Compiler API, I noticed that all of the &lt;code&gt;default export&lt;/code&gt;s were named &lt;code&gt;default&lt;/code&gt;. Since all of the import statements in a barrel file are collected in one place, duplicate names can cause problems. The &lt;code&gt;default export&lt;/code&gt; is similar to an anonymous export because it has the same name. If the original statement has a name, you can use the &lt;code&gt;alias&lt;/code&gt; keyword to give it the original name, but since different &lt;code&gt;.d.ts&lt;/code&gt; bundlers handle aliases differently, the result may not be what you intended.&lt;/p&gt;

&lt;p&gt;Thus, &lt;code&gt;default export&lt;/code&gt; can cause complicated syntax issues in library packages that need to be used by other projects. Because different bundling tools work differently, and because developers have different preferences on how to handle them, I believe that &lt;code&gt;default export&lt;/code&gt; should only be used in components that cannot be handled by TypeScript, such as Vue and Svelte. In other cases, using &lt;code&gt;export&lt;/code&gt; minimizes the chance of problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Library package projects are useful when developing. With &lt;a href="http://npmjs.com/"&gt;npm&lt;/a&gt;, there are tons of library packages available. I've been creating and using libraries out of necessity, and in doing so, I've felt the need to organize how I go about scaffolding my library package projects. There's a lot of good material out there about setting up bundlers and overall scaffolding, but topics like Paths Re-Map and &lt;code&gt;.d.ts&lt;/code&gt; bundling are relatively uninformed, so I've put together some thoughts on that. The following is by no means a definitive answer, but it's the way I apply it when working on library projects.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Automatically generate an barrel file using &lt;a href="https://github.com/imjuni/ctix"&gt;ctix&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Bundling &lt;code&gt;.d.ts&lt;/code&gt; files using &lt;a href="https://github.com/Swatinem/rollup-plugin-dts"&gt;rollup-plugin-dts&lt;/a&gt; and &lt;a href="https://github.com/justkey007/tsc-alias"&gt;tsc-alias&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Bundling with &lt;a href="https://esbuild.github.io/"&gt;esbuild&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;use &lt;a href="https://vitest.dev/"&gt;vitest&lt;/a&gt; or &lt;a href="https://jestjs.io/"&gt;jest&lt;/a&gt; as a test runner

&lt;ol&gt;
&lt;li&gt;use &lt;a href="https://www.npmjs.com/package/vite-tsconfig-paths"&gt;vite-tsconfig-paths&lt;/a&gt; to pass &lt;a href="https://kulshekhar.github.io/ts-jest/docs/getting-started/paths-mapping/"&gt;Paths Re-Map&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;use &lt;a href="https://kulshekhar.github.io/ts-jest/"&gt;ts-jest&lt;/a&gt; and set up &lt;a href="https://kulshekhar.github.io/ts-jest/docs/getting-started/paths-mapping/"&gt;Paths Re-Map&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I've uploaded the &lt;a href="https://github.com/imjuni/typescript-lib-boilerplate"&gt;typescript-lib-boilerplate&lt;/a&gt; repo.for your reference. How do you guys work when developing library projects? If you have any good tips, please let me know, thanks!&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>productivity</category>
      <category>backend</category>
      <category>frontend</category>
    </item>
    <item>
      <title>ERDIA: TypeORM entity specification documentation tool</title>
      <dc:creator>ByungJoon Lee</dc:creator>
      <pubDate>Mon, 28 Aug 2023 17:00:00 +0000</pubDate>
      <link>https://dev.to/imjuni/erdia-typeorm-entity-specification-documentation-tool-3i50</link>
      <guid>https://dev.to/imjuni/erdia-typeorm-entity-specification-documentation-tool-3i50</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I am a developer using Node.js, TypeScript. Entity Specification documents and ER diagrams are important for backend development. GUI tools automatically generate Entity Specification documents and ER diagrams, but they are difficult to include in CI. So, I developed &lt;a href="https://imjuni.github.io/erdia/" rel="noopener noreferrer"&gt;ERDIA&lt;/a&gt;, that generates Entity Specification documents and ER diagrams using CLI interface. &lt;/p&gt;

&lt;p&gt;In this article, I will introduce how to use ERDIA and the results of using it.&lt;/p&gt;

&lt;h2&gt;
  
  
  ERDIA
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://imjuni.github.io/erdia/" rel="noopener noreferrer"&gt;ERDIA&lt;/a&gt; is a tool for generating Entity Specification documents and ER diagrams with a CLI interface. It supports formats like HTML, Markdown, PDF, SVG, PNG. and can be integrated into CI. In particular, if you set the output format to HTML documents, it till generate documents per version base on package.json version field or specific version file. I integrate it into my CI and deploy it to AWS S3. This increases productivity because it ensures each documents freshness.&lt;/p&gt;

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

&lt;p&gt;TypeORM is one of the popular ORM tools.&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%2Fvu7pc9fjy10tlzonxr6x.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%2Fvu7pc9fjy10tlzonxr6x.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The image above is a chart comparing three popular ORM tools from the &lt;a href="https://npmtrends.com/prisma-vs-sequelize-vs-typeorm" rel="noopener noreferrer"&gt;npmtrends.com&lt;/a&gt;. ERDIA only supports TypeORM for now, but the roadmap is to support &lt;a href="https://sequelize.org/" rel="noopener noreferrer"&gt;Sequelize&lt;/a&gt; and &lt;a href="https://www.prisma.io/" rel="noopener noreferrer"&gt;Prisma&lt;/a&gt; as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;If you have a project that uses TypeORM, you can apply ERDIA now.&lt;/p&gt;

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

npm i erdia &lt;span class="nt"&gt;--save-dev&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;And then, I recommend running the initialization command. &lt;/p&gt;

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

npx erdia init


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

&lt;/div&gt;

&lt;p&gt;The initialization command asks a few questions about what is needed to run ERDIA and then creates the &lt;code&gt;.erdiarc&lt;/code&gt; file. Now It's time to create your first document.&lt;/p&gt;

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

npx erdia build


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

&lt;/div&gt;

&lt;p&gt;If you are using TypeScript, please refer to the TypeScript section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Format
&lt;/h2&gt;

&lt;p&gt;ERDIA generates documents in HTML, Markdown, PDF and Image formats. Each document has the following characteristics.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;HTML&lt;/th&gt;
&lt;th&gt;Markdown&lt;/th&gt;
&lt;th&gt;PDF&lt;/th&gt;
&lt;th&gt;Image&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Entity Specification&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ER diagram&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ETA Template&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Entity Version Management&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SVG or PNG&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Markdown, PDF, Image generate document single version. But HTML document contain multiple version.&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%2Fypflgz77v4t3nejeiilg.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%2Fypflgz77v4t3nejeiilg.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Template
&lt;/h2&gt;

&lt;p&gt;ERDIA uses the &lt;a href="https://eta.js.org/" rel="noopener noreferrer"&gt;ETA template engine&lt;/a&gt; to generate documentation. The reason for using a template engine is that it allows you to customize the documentation the way you want it. If you want to customize documentation that ERDIA generates run the following command.&lt;/p&gt;

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

npx erdia eject


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

&lt;/div&gt;

&lt;p&gt;You can find the default template in template directory. Customize you want it. When run it, you'll need to pass the template path as follows to generate a modified document.&lt;/p&gt;

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

npx erdia build &lt;span class="nt"&gt;--template-path&lt;/span&gt; ./template


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  TypeScript
&lt;/h2&gt;

&lt;p&gt;If your TypeORM entity is written in TypeScript, you have to run ERDIA using &lt;a href="https://typestrong.org/ts-node/" rel="noopener noreferrer"&gt;ts-node&lt;/a&gt; or &lt;a href="https://github.com/esbuild-kit/tsx" rel="noopener noreferrer"&gt;tsx&lt;/a&gt; as follows.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;TS_NODE_PROJECT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"./tsconfig.json"&lt;/span&gt; node &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-r&lt;/span&gt; ts-node/register &lt;span class="se"&gt;\&lt;/span&gt;
  ./node_modules/erdia/dist/cli.js build &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;your dataSourcePath] &lt;span class="nt"&gt;--format&lt;/span&gt; html &lt;span class="nt"&gt;-o&lt;/span&gt; ./dist/html


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

&lt;/div&gt;

&lt;p&gt;If you've use a &lt;a href="https://www.typescriptlang.org/tsconfig#paths" rel="noopener noreferrer"&gt;re-map path&lt;/a&gt; in your project, you have to pass it up to &lt;a href="https://github.com/dividab/tsconfig-paths" rel="noopener noreferrer"&gt;tsconfig-paths&lt;/a&gt; like this,&lt;/p&gt;


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

&lt;p&gt;&lt;span class="nv"&gt;TS_NODE_PROJECT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"./tsconfig.json"&lt;/span&gt; node &lt;span class="se"&gt;&amp;lt;/span&amp;gt;&lt;br&gt;
  &lt;span class="nt"&gt;-r&lt;/span&gt; ts-node/register &lt;span class="se"&gt;&amp;lt;/span&amp;gt;&lt;br&gt;
  &lt;span class="nt"&gt;-r&lt;/span&gt; tsconfig-paths/register &lt;span class="se"&gt;&amp;lt;/span&amp;gt;&lt;br&gt;
  ./node_modules/erdia/dist/cli.js build &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;your dataSourcePath] &lt;span class="nt"&gt;--format&lt;/span&gt; html &lt;span class="nt"&gt;-o&lt;/span&gt; ./dist/html&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

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

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Conclusion&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;I generate ERDIA HTML documents during Jenkins build process and deploy them to AWS S3(CDN). This task, I always have an up-to-date Entity specification, ER diagram and can share it with my co-workers.&lt;/p&gt;

&lt;p&gt;Good documentation, well managed documentation, improves project productivity. If you're using TypeORM now, I strong recommend adopt &lt;a href="https://github.com/imjuni/erdia" rel="noopener noreferrer"&gt;ERDIA&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%2Frdyxoxpk89xcnqwqa847.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%2Frdyxoxpk89xcnqwqa847.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>database</category>
      <category>orm</category>
      <category>documentation</category>
    </item>
  </channel>
</rss>
