<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>cheehow.dev Blog</title>
        <link>https://www.cheehow.dev/blog/</link>
        <description>cheehow.dev Blog</description>
        <lastBuildDate>Mon, 19 Aug 2024 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[Placeholder function for AJAX calls]]></title>
            <link>https://www.cheehow.dev/blog/2024/08/19/placeholder-function-ajax-calls/</link>
            <guid>https://www.cheehow.dev/blog/2024/08/19/placeholder-function-ajax-calls/</guid>
            <pubDate>Mon, 19 Aug 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[A placeholder function for simluating the delay from AJAX calls.]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="tldr">TL;DR<a href="https://www.cheehow.dev/blog/2024/08/19/placeholder-function-ajax-calls/#tldr" class="hash-link" aria-label="Direct link to TL;DR" title="Direct link to TL;DR" translate="no">​</a></h2>
<p>See <a href="https://gist.github.com/rojakcoder/28d6c0d4d7c7a7d37cdcc38e25a04c95" target="_blank" rel="noopener noreferrer" class="">Github gist</a> for the code.</p>
<p>I recently had to create a user-interface (UI) without the backend endpoints in place. The focus was on making the UI as responsive as possible so that the user can tell when an action is underway.</p>
<p>This mostly means that when an AJAX call is made, the UI should indicate so, and update correspondingly when the call completes.</p>
<p>To help with the development of the UI, I created a function to simulate AJAX calls. The function is able to:</p>
<ul>
<li class="">accept a delay (in milliseconds) to simulate the delay from making an actual AJAX call</li>
<li class="">accept a probability of failing to simulate when an AJAX call fails</li>
<li class="">return a supplied payload</li>
</ul>
<p>The TypeScript code is below (see the <a href="https://gist.github.com/rojakcoder/28d6c0d4d7c7a7d37cdcc38e25a04c95" target="_blank" rel="noopener noreferrer" class="">gist</a> for the complete code sample with the docstring):</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token generic-function function" style="color:#d73a49">delay</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name constant" style="color:#36acaa">T</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  timeout</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  probability</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  result</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">Promise</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">T</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name builtin">Promise</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">T</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">resolve</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> reject</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">setTimeout</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">probability </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> probability </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> probability </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">resolve</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">result</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> hit </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> Math</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">random</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">hit </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> probability</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">resolve</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">result</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">reject</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">Placeholder rejection (</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation">Math</span><span class="token template-string interpolation punctuation" style="color:#393A34">.</span><span class="token template-string interpolation function" style="color:#d73a49">round</span><span class="token template-string interpolation punctuation" style="color:#393A34">(</span><span class="token template-string interpolation"></span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string interpolation">            hit </span><span class="token template-string interpolation operator" style="color:#393A34">*</span><span class="token template-string interpolation"> </span><span class="token template-string interpolation number" style="color:#36acaa">100</span><span class="token template-string interpolation"></span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string interpolation">          </span><span class="token template-string interpolation punctuation" style="color:#393A34">)</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string string" style="color:#e3116c">%) - this should NOT appear in production</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> timeout</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>To use this function:</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">handleButtonClick</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// Update the UI to show a loading indicator.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">try</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// Make the call take 3 seconds, with a 10% chance of failure,</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// and return an array of users.</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> result </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">delay</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">3000</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0.9</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">        email</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'user1@example.com'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">        username</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'User 1'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// Update the UI when the call completes succesfully.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">catch</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">err</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">any</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// Update the UI when the call fails.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>The JavaScript version of the same function below:</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword module" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">delay</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">timeout</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> probability</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> result</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Promise</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">resolve</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> reject</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">setTimeout</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token operator" style="color:#393A34">!</span><span class="token plain">probability </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">typeof</span><span class="token plain"> probability </span><span class="token operator" style="color:#393A34">!==</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'number'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        probability </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        probability </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">resolve</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">result</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> hit </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token known-class-name class-name">Math</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">random</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">hit</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> probability</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">hit </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> probability</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">resolve</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">result</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">reject</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">Placeholder rejection (</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation known-class-name class-name">Math</span><span class="token template-string interpolation punctuation" style="color:#393A34">.</span><span class="token template-string interpolation method function property-access" style="color:#d73a49">round</span><span class="token template-string interpolation punctuation" style="color:#393A34">(</span><span class="token template-string interpolation"></span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string interpolation">            hit </span><span class="token template-string interpolation operator" style="color:#393A34">*</span><span class="token template-string interpolation"> </span><span class="token template-string interpolation number" style="color:#36acaa">100</span><span class="token template-string interpolation"></span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string interpolation">          </span><span class="token template-string interpolation punctuation" style="color:#393A34">)</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string string" style="color:#e3116c">%) - this should NOT appear in production</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> timeout</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>]]></content:encoded>
            <category>ajax</category>
            <category>placeholder</category>
        </item>
        <item>
            <title><![CDATA[TypeScript "No overload matches this call."]]></title>
            <link>https://www.cheehow.dev/blog/2024/06/12/typescript-no-overload-matches-this-call/</link>
            <guid>https://www.cheehow.dev/blog/2024/06/12/typescript-no-overload-matches-this-call/</guid>
            <pubDate>Wed, 12 Jun 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[The developer experience of TypeScript that is difficult to resolve.]]></description>
            <content:encoded><![CDATA[<p>This is normally an easy problem to fix. However, when it isn't easily fixed, trying to find the solution is difficult because the cause is typically not obvious.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="tldr">TL;DR<a href="https://www.cheehow.dev/blog/2024/06/12/typescript-no-overload-matches-this-call/#tldr" class="hash-link" aria-label="Direct link to TL;DR" title="Direct link to TL;DR" translate="no">​</a></h2>
<p>This example here is one manifestation of such problems seen with TypeScript. Here, the problem occurs when <code>FormData</code> is used together with <code>Object.fromEntries</code>. E.g.</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> form </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> evt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">target</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">as</span><span class="token plain"> </span><span class="token maybe-class-name">HTMLFormElement</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> formData </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">FormData</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">form</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> data </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token known-class-name class-name">Object</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">fromEntries</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">formData</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>The IDE shows a wriggly line on <code>formData</code> with the following message:</p>
<blockquote>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">No overload matches this call.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Overload 1 of 2, '(entries: Iterable&lt;readonly [PropertyKey, any]&gt;): { [k: string]: any; }', gave the following error.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   Argument of type 'FormData' is not assignable to parameter of type 'Iterable&lt;readonly [PropertyKey, any]&gt;'.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     Property '[Symbol.iterator]' is missing in type 'FormData' but required in type 'Iterable&lt;readonly [PropertyKey, any]&gt;'</span><br></span></code></pre></div></div>
</blockquote>
<p><img decoding="async" loading="lazy" alt="No overload matches this call" src="https://www.cheehow.dev/assets/images/no-overload-matches-symbol-iterator-afe34c20c8c4fd88905709a9febe97a1.png" title="No overload matches this call" width="1254" height="328" class="img_ev3q"></p>
<p><strong>Two things to check:</strong></p>
<ol>
<li class="">Ensure that in <em>tsconfig.json</em>, the <code>lib</code> option contains minimally these two values in the array: <code>DOM</code> and <code>DOM.Iterable</code> (case-insensitive).</li>
<li class="">If the <em>tsconfig.json</em> file contains the <code>references</code> option, check the <code>lib</code> option in the locations specified under <code>references</code> as well.</li>
</ol>
<!-- -->
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="introduction">Introduction<a href="https://www.cheehow.dev/blog/2024/06/12/typescript-no-overload-matches-this-call/#introduction" class="hash-link" aria-label="Direct link to Introduction" title="Direct link to Introduction" translate="no">​</a></h2>
<p>TypeScript is a language that is based on JavaScript. Its website says that it is "JavaScript with syntax for types".</p>
<p>Indeed, after switching to use TypeScript, I've had the number of runtime issues reduced drastically compared to using JavaScript.</p>
<p>JavaScript has gained widespread adoption due in large part to the ease in which beginning developers can get started. The popularity also meant that different browsers have different JavaScript runtimes that support different versions of the language (though that's less of a problem nowadays since many have chosen to use the Chromium base). There are also various Web APIs that are implemented in JavaScript.</p>
<p>This wide adoption truly speaks for the flexibility of the language but because it is so open, it can be difficult to identify exactly which API and properties/functions are available.</p>
<p>This is where TypeScript benefits the developer greatly. Its typed nature means that integrated development environments (IDEs) can expose productivity enhancements such as code hints and autocompletion.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="whats-the-issue">What's the issue?<a href="https://www.cheehow.dev/blog/2024/06/12/typescript-no-overload-matches-this-call/#whats-the-issue" class="hash-link" aria-label="Direct link to What's the issue?" title="Direct link to What's the issue?" translate="no">​</a></h2>
<p>For TypeScript to support the differing levels of the specification as well as the myriad libraries that are now available in JavaScript, it requires the use of a config file that is named <em>tsconfig.json</em> which is typically found in the root of the source project folder.</p>
<p>Learning all the options in <em>tsconfig</em> is an endeavour in and of itself.</p>
<p>I'd bet that most TypeScript developers (like, the overwhelming majority), myself included, know the syntax well, but not the configuration of tsconfig. In our defence, it is rare that <em>tsconfig.json</em> ever needs to be modified in the lifetime of a project once it is set up.</p>
<p>Having the correct options set will yield huge productivity benefits for the developer. Conversely, a wrongly configured file can create unexpected headaches.</p>
<p>One common problem is the error hints shown in the IDE.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="problem-1">Problem 1<a href="https://www.cheehow.dev/blog/2024/06/12/typescript-no-overload-matches-this-call/#problem-1" class="hash-link" aria-label="Direct link to Problem 1" title="Direct link to Problem 1" translate="no">​</a></h3>
<p>I have two machines, one Linux and one MacOS (M1), that I develop on.</p>
<p>With the same codebase on one machine, everything works fine. When I check out the repository on the other machine, I see this wriggly line error in VS Code.</p>
<p><img decoding="async" loading="lazy" alt="Missing repeat function" src="https://www.cheehow.dev/assets/images/missing-repeat-a417ffe66743d891754f082853e2386b.png" title="Missing `repeat` function" width="751" height="168" class="img_ev3q"></p>
<p>The first thought that comes to mind is that there must be some issues with <em>tsconfig.json</em>. It's not a pleasant thought. Trying to fix issues with tsconfig is a trial-and-error most of the time.</p>
<p>Luckily, the cause of the error is sometimes very simple. In this case, the dependencies have not been installed. This is indicated by the wrigglies on the import statements like so:</p>
<p><img decoding="async" loading="lazy" alt="Missing imports" src="https://www.cheehow.dev/assets/images/missing-imports-eac592edd3176173d81c8489d1d4aba8.png" title="Missing imports" width="537" height="142" class="img_ev3q"></p>
<p>Errors on all the import statements of npm packages mean that the dependencies have not been installed yet. In this case, the resolution is to simply install the dependencies first.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="solution-to-problem-1">Solution to problem 1<a href="https://www.cheehow.dev/blog/2024/06/12/typescript-no-overload-matches-this-call/#solution-to-problem-1" class="hash-link" aria-label="Direct link to Solution to problem 1" title="Direct link to Solution to problem 1" translate="no">​</a></h3>
<div class="theme-tabs-container tabs-container tabList__CuJ"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_LNqP tabs__item--active">npm</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_LNqP">pnpm</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_Ymn6"><p><code>npm install </code></p></div><div role="tabpanel" class="tabItem_Ymn6" hidden=""><p><code>pnpm install </code></p></div></div></div>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_BuS1"><p>Install dependencies as the first resolution.</p></div></div>
<p>When you are stuck on some problem it can be easy to forget to install the dependencies on a freshly checked out codebase.</p>
<p>Furthermore, if there are no <code>import</code> statements in the file with the error, it is even less obvious.</p>
<p>This is why I've adopted the heuristic of always running <code>npm install</code>/<code>pnpm install</code> first.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="problem-2">Problem 2<a href="https://www.cheehow.dev/blog/2024/06/12/typescript-no-overload-matches-this-call/#problem-2" class="hash-link" aria-label="Direct link to Problem 2" title="Direct link to Problem 2" translate="no">​</a></h3>
<p>I am working on two TypeScript projects - one is a Next.js project, and the other is a codebase for a Chrome extension.</p>
<p>In both projects, I have the following code:</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> form </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> evt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">target </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> HTMLFormElement</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> formData </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">FormData</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">form</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> data </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> Object</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">fromEntries</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">formData</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>The code looks fine in the Next.js project.</p>
<p>But, in the Chrome extension project, the IDE complains:</p>
<p><img decoding="async" loading="lazy" alt="No overload matches this call" src="https://www.cheehow.dev/assets/images/no-overload-matches-symbol-iterator-afe34c20c8c4fd88905709a9febe97a1.png" title="No overload matches this call" width="1254" height="328" class="img_ev3q"></p>
<p>Now, this happens after installing the dependencies so it's no longer just an easy fix of installing the dependencies.</p>
<p>Back to basics then. So the error says that <code>Argument of type 'FormData' is not assignable to parameter of type 'Iterable&lt;readonly [PropertyKey, any]&gt;'.</code></p>
<p>This seems to suggest that the same <a href="https://developer.mozilla.org/en-US/docs/Web/API/FormData" target="_blank" rel="noopener noreferrer" class=""><code>FormData</code></a> class in the extension codebase is of a different version from that in the Next.js codebase. I'm guessing this has to do with the version of TypeScript target or library specified in <em>tsconfig.json</em></p>
<table><thead><tr><th style="text-align:left">Project</th><th style="text-align:left">Option</th><th style="text-align:left">Value</th></tr></thead><tbody><tr><td style="text-align:left">Next.js</td><td style="text-align:left"><code>target</code></td><td style="text-align:left"><code>"es5"</code></td></tr><tr><td style="text-align:left"></td><td style="text-align:left"><code>lib</code></td><td style="text-align:left"><code>["dom", "dom.iterable", "esnext"]</code></td></tr><tr><td style="text-align:left">Extension</td><td style="text-align:left"><code>target</code></td><td style="text-align:left"><code>"ES2020"</code></td></tr><tr><td style="text-align:left"></td><td style="text-align:left"><code>lib</code></td><td style="text-align:left"><code>["ES2020", "DOM", "DOM.Iterable", "WebWorker"]</code></td></tr></tbody></table>
<p>Looking at <a href="https://www.typescriptlang.org/tsconfig/#target" target="_blank" rel="noopener noreferrer" class=""><code>target</code></a>, the version stated in Next.js (<code>es5</code>) is even older than the version in the extension codebase (<code>ES2020</code>). <code>target</code> can't be the problem then.</p>
<p>How about <a href="https://www.typescriptlang.org/tsconfig/#lib" target="_blank" rel="noopener noreferrer" class=""><code>lib</code></a>? In Next.js we're seeing <code>esnext</code> whereas in the Chrome extension codebase, we're seeing <code>ES2020</code>. Could this be it?! <code>esnext</code> refers to the latest specifications so this should be the problem right?!</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="attempted-solution-1-to-problem-2">Attempted solution 1 to problem 2<a href="https://www.cheehow.dev/blog/2024/06/12/typescript-no-overload-matches-this-call/#attempted-solution-1-to-problem-2" class="hash-link" aria-label="Direct link to Attempted solution 1 to problem 2" title="Direct link to Attempted solution 1 to problem 2" translate="no">​</a></h3>
<p>So I changed <code>lib</code>. From this:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">tsconfig.js (extension codebase)</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">"target": "ES2020",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">"useDefineForClassFields": true,</span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">"lib": ["ES2020", "DOM", "DOM.Iterable", "WebWorker"],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">"module": "ESNext",</span><br></span></code></pre></div></div>
<p>to this:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">tsconfig.js (extension codebase)</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">"target": "ES2020",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">"useDefineForClassFields": true,</span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">"lib": ["ESNext", "DOM", "DOM.Iterable", "WebWorker"],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">"module": "ESNext",</span><br></span></code></pre></div></div>
<p>After saving this, the error persists.</p>
<p>"Okay," I'm thinking. "Let's just restart the TypeScript server for the change to take effect."</p>
<p><img decoding="async" loading="lazy" alt="&amp;quot;Restart TS Server&amp;quot;" src="https://www.cheehow.dev/assets/images/typescript-server-restart-732554273da0122757827ab1e70b884b.png" title="Restart TS Server" width="602" height="110" class="img_ev3q"></p>
<p><em>Nope.</em> Error still shows in the IDE.</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p>I've even tried variations like:</p><ul>
<li class="">Removing <code>DOM.Iterable</code>, restarting TS Server, then adding back in.</li>
<li class="">Place <code>DOM.Iterable</code> last in the array.</li>
<li class="">Change to lowercase and place <code>dom.iterable</code> first in the array.</li>
</ul><p>And restarting TS Server after every change.</p><p>I didn't think that these will fix the problems but I had to try them when I was running out of ideas.</p></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="attempted-solution-2-to-problem-2">Attempted solution 2 to problem 2<a href="https://www.cheehow.dev/blog/2024/06/12/typescript-no-overload-matches-this-call/#attempted-solution-2-to-problem-2" class="hash-link" aria-label="Direct link to Attempted solution 2 to problem 2" title="Direct link to Attempted solution 2 to problem 2" translate="no">​</a></h3>
<p>Alright. Let's inspect the other options in <em>tsconfig.json</em>.</p>
<table><thead><tr><th style="text-align:left">Option</th><th style="text-align:left">Next.js Value</th><th style="text-align:left">Extension Value</th></tr></thead><tbody><tr><td style="text-align:left"><code>allowJs</code></td><td style="text-align:left"><code>true</code></td><td style="text-align:left"><em>not set</em></td></tr><tr><td style="text-align:left"><code>skipLibCheck</code></td><td style="text-align:left"><code>true</code></td><td style="text-align:left"><code>true</code></td></tr><tr><td style="text-align:left"><code>strict</code></td><td style="text-align:left"><code>true</code></td><td style="text-align:left"><code>true</code></td></tr><tr><td style="text-align:left"><code>forceConsistentCasingInFileNames</code></td><td style="text-align:left"><code>true</code></td><td style="text-align:left"><em>not set</em></td></tr><tr><td style="text-align:left"><code>noEmit</code></td><td style="text-align:left"><code>true</code></td><td style="text-align:left"><code>true</code></td></tr><tr><td style="text-align:left"><code>esModuleInterop</code></td><td style="text-align:left"><code>true</code></td><td style="text-align:left"><em>not set</em></td></tr><tr><td style="text-align:left"><code>module</code></td><td style="text-align:left"><code>esnext</code></td><td style="text-align:left"><code>ESNext</code></td></tr><tr><td style="text-align:left"><code>moduleResolution</code></td><td style="text-align:left"><code>node</code></td><td style="text-align:left"><code>bundler</code></td></tr><tr><td style="text-align:left"><code>resolveJsonModule</code></td><td style="text-align:left"><code>true</code></td><td style="text-align:left"><code>true</code></td></tr><tr><td style="text-align:left"><code>isolatedModules</code></td><td style="text-align:left"><code>true</code></td><td style="text-align:left"><code>true</code></td></tr><tr><td style="text-align:left"><code>jsx</code></td><td style="text-align:left"><code>preserve</code></td><td style="text-align:left"><code>react-jsx</code></td></tr><tr><td style="text-align:left"><code>incremental</code></td><td style="text-align:left"><code>true</code></td><td style="text-align:left"><em>not set</em></td></tr><tr><td style="text-align:left"><code>paths</code></td><td style="text-align:left"><code>{ "~src/*": ["./src/*"], "~public/*": ["./public/*"] }</code></td><td style="text-align:left"><em>not set</em></td></tr></tbody></table>
<p>Nothing stands out as to what could be the cause. So I copied the values over to make the options identical in both projects. <em>No bueno</em>.</p>
<p>Okay. Since the configurations are all the same already, let's take a closer look at the problem. It says that <code>Property '[Symbol.iterator]' is missing in type 'FormData' but required in type 'Iterable&lt;readonly [PropertyKey, any]&gt;'.</code> So this means that the <code>FormData</code> class used in the extension codebase does not have the properties to be <code>Iterable</code>. Why?</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="attempted-solution-3-to-problem-2">Attempted solution 3 to problem 2<a href="https://www.cheehow.dev/blog/2024/06/12/typescript-no-overload-matches-this-call/#attempted-solution-3-to-problem-2" class="hash-link" aria-label="Direct link to Attempted solution 3 to problem 2" title="Direct link to Attempted solution 3 to problem 2" translate="no">​</a></h3>
<p>Ctrl/Cmd-clicking on the <code>FormData</code> class reveals two differences:</p>
<p><img decoding="async" loading="lazy" alt="Node.js code" src="https://www.cheehow.dev/assets/images/source-server-86acd8154e93bb1cc19402fae32cbf99.png" title="Node.js code" width="808" height="259" class="img_ev3q">
<em>Code in Node.js</em></p>
<p><img decoding="async" loading="lazy" alt="extension code" src="https://www.cheehow.dev/assets/images/source-extension-f95f55b2156e466425c7d84fbd110cd6.png" title="extension code" width="809" height="257" class="img_ev3q">
<em>Code in extension codebase</em></p>
<p>In the Node.js codebase, there is a reference to <code>lib.dom.iterable.d.ts</code> whereas in the extension codebase, this is not present.</p>
<p>This makes sense since what is missing is the iterable property of <code>FormData</code>.</p>
<p>The second difference is that the Node.js codebase references <code>@types+react@18.2.73</code> whereas the extension codebase references <code>@types+react@18.2.48</code>.</p>
<p>Could that be it?</p>
<p>Let's compare the <em>package.json</em> files of both codebases:</p>
<table><thead><tr><th style="text-align:left">Codebase</th><th style="text-align:left">Dependency</th></tr></thead><tbody><tr><td style="text-align:left">Next.js</td><td style="text-align:left"><code>"@types/react": "^18.2.12",</code></td></tr><tr><td style="text-align:left">Extension</td><td style="text-align:left"><code>"@types/react": "^18.2.43",</code></td></tr></tbody></table>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p>At this point it is worth highlighting that the codebases are using <code>pnpm</code> and not <code>npm</code>.</p></div></div>
<p>So there is a disparity between the versions. I'm not exactly sure what is going on, so I'm installing the latest version of <code>@types/react</code> for the extension codebase:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">pnpm</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">add</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-D</span><span class="token plain"> @types/react@latest</span><br></span></code></pre></div></div>
<p>After restarting the TS Server, the wriggly is still there. 😡</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="attempted-solution-4-to-problem-2---stackoverflow">Attempted solution 4 to problem 2 - StackOverflow<a href="https://www.cheehow.dev/blog/2024/06/12/typescript-no-overload-matches-this-call/#attempted-solution-4-to-problem-2---stackoverflow" class="hash-link" aria-label="Direct link to Attempted solution 4 to problem 2 - StackOverflow" title="Direct link to Attempted solution 4 to problem 2 - StackOverflow" translate="no">​</a></h3>
<p>Next, I took to StackOverflow (being sceptical that AI could solve this problem).</p>
<p><a href="https://stackoverflow.com/a/38862621/1075283" target="_blank" rel="noopener noreferrer" class="">This answer</a> that I've found is answering the question why VS Code is not honouring the options in <em>tsconfig.json</em>. I'm not entirely sure this is the same problem, but at this stage, I'm willing to try anything.</p>
<p>So I added <code>"typescript.tsdk": "node_modules/typescript/lib"</code> to <em>.vscode/settings.json</em>.</p>
<p>After restarting TS Server, the problem persists. 🤬</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="attempted-solution-5-to-problem-2---chatgpt">Attempted solution 5 to problem 2 - ChatGPT<a href="https://www.cheehow.dev/blog/2024/06/12/typescript-no-overload-matches-this-call/#attempted-solution-5-to-problem-2---chatgpt" class="hash-link" aria-label="Direct link to Attempted solution 5 to problem 2 - ChatGPT" title="Direct link to Attempted solution 5 to problem 2 - ChatGPT" translate="no">​</a></h3>
<p>Alright. Next up, AI. Let's see what this jobs-killer, revolutionary technology can do in this case.</p>
<blockquote>
<p><em>Me</em>:</p>
<p>VS Code is not reading lib.dom.iterable.d.ts for my TypeScript project. How can I solve this problem?</p>
</blockquote>
<p>ChatGPT gave a few suggestions. Let's break them down:</p>
<blockquote>
<p><em>ChatGPT</em>:</p>
<p>To resolve the issue of VS Code not reading lib.dom.iterable.d.ts for your TypeScript project, follow these steps:</p>
<p><strong>1. Check TypeScript Version:</strong></p>
<p>Ensure you are using an up-to-date version of TypeScript. Update TypeScript globally and locally in your project if necessary.</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">npm install -g typescript</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">npm install typescript --save-dev</span><br></span></code></pre></div></div>
</blockquote>
<table><thead><tr><th style="text-align:left">Codebase</th><th style="text-align:left">Dependency</th></tr></thead><tbody><tr><td style="text-align:left">Next.js</td><td style="text-align:left"><code>"typescript": "^5.1.3",</code></td></tr><tr><td style="text-align:left">Extension</td><td style="text-align:left"><code>"typescript": "^5.2.2"</code></td></tr></tbody></table>
<p>Huh. The extension is already using a newer version of TypeScript.</p>
<blockquote>
<p><em>ChatGPT</em>:</p>
<p><strong>2. Update VS Code:</strong></p>
<p>Make sure you are using the latest version of Visual Studio Code. Updates often include fixes for issues like this.</p>
</blockquote>
<table><thead><tr><th style="text-align:center"><img decoding="async" loading="lazy" alt="VS Code version for Linux" src="https://www.cheehow.dev/assets/images/vscode-version-linux-33a155b811584967fbbb934eec0e41cf.png" title="VS Code version for Linux" width="434" height="301" class="img_ev3q"></th><th style="text-align:center"><img decoding="async" loading="lazy" alt="VS Code version for MacOS" src="https://www.cheehow.dev/assets/images/vscode-version-macos-6ad67ad19b147ee5e6ec0b6b8867864e.png" title="VS Code version for MacOS" width="476" height="708" class="img_ev3q"></th></tr></thead></table>
<p>Well, I'm already on the latest version on both of my machines, and the same problem occurs on both of them.</p>
<blockquote>
<p><em>ChatGPT</em>:</p>
<p><strong>3. Check tsconfig.json:</strong></p>
<p>Ensure your <code>tsconfig.json</code> file includes the necessary library references. Your <code>tsconfig.json</code> should have a section like this:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "compilerOptions": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "lib": ["dom", "es2015", "dom.iterable"]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre></div></div>
<p>This explicitly includes dom.iterable as part of the TypeScript compilation process.</p>
</blockquote>
<p>Yes, that's the first thing I've checked. (See <a href="https://www.cheehow.dev/blog/2024/06/12/typescript-no-overload-matches-this-call/#attempted-solution-1-to-problem-2" class="">Attempted solution 1</a>)</p>
<blockquote>
<p><em>ChatGPT</em>:</p>
<p><strong>4. Ensure TypeScript is Correctly Configured in VS Code:</strong></p>
<p>Sometimes, VS Code may use a different TypeScript version than the one installed in your project. To ensure VS Code uses the correct version:</p>
<ul>
<li class="">Open the command palette (Ctrl+Shift+P or Cmd+Shift+P).</li>
<li class="">Type and select "TypeScript: Select TypeScript Version".</li>
<li class="">Choose "Use Workspace Version" to make sure it uses the TypeScript version specified in your project.</li>
</ul>
</blockquote>
<p>Non-starter. No such option.</p>
<p>Let's give it the benefit of the doubt - it might referring to a Workspace setting.</p>
<p><img decoding="async" loading="lazy" alt="TypeScript" src="https://www.cheehow.dev/assets/images/tsdk-6c78d64b17d89e30904b2d04194dc6c8.png" title="TypeScript:Tsdk" width="792" height="347" class="img_ev3q"></p>
<p>Oh! <a href="https://www.cheehow.dev/blog/2024/06/12/typescript-no-overload-matches-this-call/#attempted-solution-4-to-problem-2---stackoverflow" class="">Tried this already.</a> 😐</p>
<blockquote>
<p><em>ChatGPT</em>:</p>
<p><strong>5. Reload VS Code Window:</strong></p>
<p>After making changes to <code>tsconfig.json</code>, reload the VS Code window to ensure the new configuration is applied.</p>
<ul>
<li class="">Open the command palette and type "Reload Window", then select it.</li>
</ul>
</blockquote>
<p>Reload VS Code? I had been using Windows in my previous life. Of course I had reloaded VS Code already.</p>
<blockquote>
<p><em>ChatGPT</em>:</p>
<p><strong>6. Verify File Presence:</strong></p>
<p>Ensure the <code>lib.dom.iterable.d.ts</code> file is present in the <code>node_modules/typescript/lib</code> directory. If it's missing, reinstall TypeScript:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">npm install typescript --save-dev</span><br></span></code></pre></div></div>
</blockquote>
<p><img decoding="async" loading="lazy" alt="lib.dom.iterable.d.ts" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAdIAAAAoCAYAAABKHnv9AAAABHNCSVQICAgIfAhkiAAAABl0RVh0U29mdHdhcmUAZ25vbWUtc2NyZWVuc2hvdO8Dvz4AAAApdEVYdENyZWF0aW9uIFRpbWUAU3VuIDI2IE1heSAyMDI0IDA0OjI3OjEyIFBNHR+63wAAFCNJREFUeJztnX9sVFXaxz9dSbFlqAv9NZBAg74xhcVmqa0otGXWCo2A4q6aaXVZzFJTBaS7YoUVKyGbdSNKTdQG2G4l8vKWH6tFW4mBFFMsRRAYU5dSWqZgU+lMO8MWy9pGFnnfP0zvO9d25pyZe9tp4XySJp25P57veZ5znjNz7r3zREydOvV/ucn52bI5RGT8FxHx47m+70uuv3dU2zbmf/Khu5drqypCOrfR4xWjm8kFNVzvvYT7v+3hlqJQKIaICDWRKhQKhUIROj8LtwCFQqFQKEYzaiJVKBQKhcIAaiJVmI7dbichISHcMm5Ywu3fcNtXKEYaaiJVmEpWVhaLFy+mq6sr3FKGldjYWHJycobcTqj+NUtfuO2PVG709ikCM6QTaX5+PpWVldrf3Llzh9KcKVitViorK4mNjQ23lEEJRl84/G+z2Th69OiA9ysrK7njjjuG3H64yMnJoaCggIyMjJCOl/WPr3+Dia8/fcXFxSxbtkxaZ7jtiwjX+BXFP1z9P5B/w5EfQo3PSM8fY0Q7JCcnc/bs2ZBO/sEHH3DgwAEA/vKXv4R0DkXoDLf/J0yYwF133cUrr7wy5LZGGhUVFTQ0NNDY2DhkNn7q32Dia4a+cNsfyYzG9qn8bB7CiXTp0qVER0eza9cuvvjii6BO3t3dTXd3NwDXr1/3u99zzz1HWloa48aNw+VysXPnTo4fPy5lo7i4GK/XS0JCAsnJyVy8eJGtW7fidDq1fZ544glsNhtRUVG0tLRQVlaG2+3Wtq9evZr09HQuX77M+++/P8BGXl4e2dnZjBs3jnPnzlFWVkZ7e7uUvv5Pe7/61a94//33sdlsREZG8sc//tEUfRs2bKClpYVdu3YBkJCQwNatW1mxYgVut1vK/6L2ycZn3rx5eDwempqagB8/hL366qva9tdff137/89//jNffvkle/bs4a233qK+vl7bVlZWRnV1NVVVVRQXF+PxeIiNjWXmzJm43W62bdum+3BnVL/dbuf+++/HYrHQ2tpKeXk5bW1tACxZsoT77ruP8+fPk5mZyXfffcfevXv59NNPte2+n/jXrFnDhQsXtNeB9Mv4J5B/ZcaXSB/AmDFjKCoqIjU1lY6ODrZs2aIbPyPFvj9E4zfQ+JIZn4EI1D7Z+Abqv6L+B/DUU0+RmZlJVFQUTqdzQP/351/Z/Gwk/4E4Pv6Q9Z+R+cMshEu769ev5/DhwzzzzDO8/vrrpKammirgwQcfZNasWWzatIk//OEPHDp0iIKCgqDOkZKSwo4dO8jLy8PpdLJmzRpt28MPP8yCBQsoKytjw4YN/Oc//2Ht2rXadrvdzqxZs3jzzTcpKSkZ0L7FixczZ84cXnvtNQoLC2lra2P9+vVB6Tt69Cj/+Mc/mD9/PmvXruXatWvMnz/fFH1GEbUvmPjMmzePw4cPa6/Pnj1LYWEhf/rTnwDYvHkzhYWFFBYWaoPA4XCQlZWlHZOcnMzEiRN1E2tKSgoVFRXk5eVx+vRpnn/+edP0L1q0iIULF7J9+3bWr19PZ2cnL7/8sq5dSUlJnDlzhqVLl1JeXs6zzz7L1KlTAfjoo48oLCzkpZde8utjf/pl/BPIvzLI6Lv77rupq6tj3bp1dHV1UVRUNOh+4bY/GKLxIRpfEHh8GmmfTHxl8kug/me320lPT6e0tJS1a9fS0dGh2evHiH+N5j8j+UvGf2bMH2YgdY30ww8/5Pe//z319fWsWrWKv/71r/z85z83RcBtt92Gx+OhsbGRb775RrMVDA0NDdqnwP3795OYmMiECRMASE1NpaamhhMnTnD+/HnKy8tJSkrS7jqcOXMmNTU1OBwOLly4QHV1te7c9957L4cOHeLcuXN0dXVRXl5OQkICU6ZMkdb3r3/9C6/Xi9frBeDSpUtYLBZT9BlF1D7Z+Nx+++0kJSVRW1ure7+9vZ3m5mYA3G437e3tuk+ztbW1zJo1S6fn7NmzXLp0SXvvq6++0uJbWVlJXFwckyZNMkV/WloaNTU1HDt2jK+//prS0lKam5uJi4vT9unu7ubIkSMAnDhxgo6ODmbMmKFrY6DLH4H0i/wj8q8MIn2NjY0cO3aMtrY23n33XeLj47FarSPKvj9E40M0viDw+DTaPlF8ZfJLoP63Z88eVq5cicPhoL29nX379mG1Wpk4caJ2vBH/Gs1/RvOXyH9mzB9mIFza9eXDDz+ku7ubgoICYmNjuXz5smEB9fX1LFy4kNLSUlpbW2lubmb//v1BnaOvr0/7//vvvwdg7NixAIwfP54rV65o2z0ej/Z+V1cX0dHR/Pvf/9a2+/4PEBUVxRNPPEFubq723g8//EBkZGRQGv1hVJ9RRO2TjY/NZqOpqYnOzs6g7B8/fpze3l4WLFjAwYMHmT17NlVVVbp9fOPbvxQVHR1tiv6YmBh6enp09t544w2/9gHefvttvv32W+k2BtIvS6j+lcG3T/X3v3Hjxo0o+/4QjQ/R+Ao3MvklUP+bNm0a+fn5TJkyhYiICCIiIgB0xxvxr9H8N9T5y4z5wwykJ9J7770Xu91OZGQk27Zto7W11RQB7e3t/O53vyMjI4M77riDBx98kEWLFrFixQpTzm8G27dv55NPPgm3jCEjUPtk45ORkcHu3btDsl9fX09GRgatra3ExcXx+eefD7v+YAjm+p1ZGPHvjWD/RibY/OLb/4qKiqirq9OWW/vvkQinvuFkpMwfwqXdtLQ03nzzTZYtW0Z1dTUrV64M+jqJDEeOHOG9995j1apVWK1WkpOTTTlvT08P48eP117Hx8cDaJ9S+/r6dMs4P13S6evr05aJ+/nFL35hijYz9F25coWYmBjtdf//vjcrBUK2fYHik5aWRnR0NAcPHpSy+VNqa2uZMWMG2dnZnD59esBKh2/7+pfkent7TdHf09OjOz/ACy+8oFvaNUog/TIY9a8I3z7V325ffeG2DzB58uRBr6+JxodofMniz75RjOYXq9XKiRMntNeDfdOU8a9RfaHGR3S8LEM1f8gi/Ea6YMECPvnkE8ODyOPxkJ6ezjfffMP169fp6+vD6/WyfPlypk+fzvbt2+nu7uaXv/wlP/zwg3a9wigOh4Pf/OY32nW3xx57jLa2Nm1Zp7GxkezsbP75z3/S3d3Nww8/rDv+iy++YMmSJTQ0NNDZ2cnixYvJyMggPz9/ROg7deoU+fn5OBwOvF4vTz75JGfOnBlgx5//Re2TiY/NZtMN5sHo6+tjzpw5XL16FUB3nePcuXN0dHSQnZ3N3/72twHHTp8+ndmzZ3Px4kVyc3Pxer24XC5AHB+R/lOnTvH444/T0tJCZ2cnDz30EHfeead0/0tMTCQyMlJLYImJiVy7do2rV69qy6CB9Mv4R8a//uIroy8lJYX09HRcLhe5ubl4PB6dvnDbhx/vTo+Pj2fjxo00NDRo74vGh2h8yeLPvkz7wH98jeYXt9tNTk4OTqcTq9XKI488MmAfGf+Gmh9E/hHFR3S8yH9DPX/IIpxIfW8/NsLf//53VqxYQUlJCREREZw8eZJXX32V8vJyioqKWLduHbfeeisej4ctW7aY5ojq6mpiYmIoKCggKiqK5uZmXnvtNW37rl27iI+Pp6ioiCtXrlBZWal7qLqqqorbbruNNWvWcOutt9LS0sLGjRtN0WaGvsOHDxMXF8fTTz9NVFQUjY2NvPPOOwPs+PO/qH0y8UlLS9Pdmj4Y5eXl/Pa3v+XXv/41gPZ4Tj/19fU8+uijHDp0aMCxJ0+eJCsri9TUVNxuNyUlJdo2o/o//vhjLBYLy5cvx2Kx4HQ6g3qm7sUXX2TatGm61wBNTU3aclsg/TL+kfGvv/jK6HM4HDzwwAOkpKTgcrnYvHmz7tzhtg9w4cIFxo4dOyAviMaHaHzJ4s++TPvAf3yN5peSkhIKCgrYvXs3LpeLvXv3kpmZqdtHxr+h5geRf0TxER0v8t9Qzx+yqDJqBpg0aRKbNm0adNuBAwfYuXPnMCsafubPn09eXp7hO+VWr16NxWIZ8MGtuLiYtrY2duzYYej84cKofrP8Gyrhtq9QjAaCumtXocflcumeWfVlJNwROBzYbDbq6uoMn+eee+4ZdFkX0O5EHK0Y0W+Wf0erfYViNKAmUoPcLBOmP4L9cYrBmDt3LrfccgufffaZCYpuLMzw72i2r1CMBtTSrkKhUCgUBlBl1BQKhUKhMICaSBUKhUKhMICaSEchdrtd91uhCnMJt3/DbV+hUASHmkhHGVlZWSxevPimu8kpNjaWnJycIbcTqn/N0hdu+yOVG719itHNsE+k4apgL0sw+sJRYd5ms3H06NEB74/0CvJGycnJoaCgYNCHuWWQ9Y+vf4OJrz99xcXFunqVI92+iHCNX1H8w9X/A/k3HPkh1Pjc6PljqFGPvxhguCvMT5gwgbvuuotXXnllyG2NNCoqKmhoaKCxsXHIbPzUv8HE1wx94bY/khmN7Rvu/KAIH8KJtLi4GK/XS0JCAsnJyVy8eJGtW7fqKhAEqkAP4grpRiqwy1S4N6Jvw4YNtLS0sGvXLuD/qyv0/0SVGRXmZSu8z5s3D4/HQ1NTEyBXQX7Pnj289dZbukLZZWVlVFdXU1VVRXFxMR6Ph9jYWGbOnInb7Wbbtm26+opG9dvtdu6//34sFgutra2Ul5fT1tYGwJIlS7jvvvs4f/48mZmZfPfdd+zdu5dPP/1U2+77iX/NmjVabU8goH4Z/wTyb3d3tzC+In0AY8aMoaioiNTUVDo6OtiyZcugFWTCbd8fovEbaHzJjM9ABGqfbHwD9V9R/wN46qmnyMzMJCoqCqfTOaD/+/OvTPxE+mQQxccfsv6TzU83M1JLuykpKezYsYO8vDycTqfu13xEFehFFdKNVmCHwBXujeoziqh9wVR4nzdvnq7yjkwFeYfDQVZWlnZMcnIyEydO1E2sKSkpVFRUkJeXx+nTp3n++edN079o0SIWLlzI9u3bWb9+PZ2dnbz88su6diUlJXHmzBmWLl1KeXk5zz77LFOnTgXgo48+orCwkJdeesmvj/3pl/FPIP/KIKPv7rvvpq6ujnXr1tHV1UVRUdGg+4Xb/mCIxodofEHg8WmkfTLxlckvgfqf3W4nPT2d0tJS1q5dS0dHh2avHyP+NZr/jOQvGf8Fk59uZqQm0oaGBu1T4P79+0lMTNRK64gq0IsqpButwA6BK9wb1WcUUftkK7zffvvtJCUlUVtbq3tfVEG+traWWbNm6fT0V8Lo56uvvtLiW1lZSVxcHJMmTTJFf1paGjU1NRw7doyvv/6a0tJSmpubdWXKuru7OXLkCAAnTpygo6ODGTNm6Nro+w35pwTSL/KPyL8yiPQ1NjZy7Ngx2traePfdd4mPj8dqtY4o+/4QjQ/R+ILA49No+0Txlckvgfrfnj17WLlyJQ6Hg/b2dvbt24fVamXixIna8Ub8azT/Gc1fIv/J5qebHalrpL4V2r///nsAxo4dC4gr0IsqpButwC7CqD6jiNonW+HdZrPR1NSkK80kw/Hjx+nt7WXBggUcPHiQ2bNnU1VVpdvHN779S1HR0dGm6I+JiaGnp0dn74033vBrH+Dtt9/m22+/lW5jIP2yhOpfGXz7VH//+2ndyHDb94dofIjGV7iRyS+B+t+0adPIz89nypQpREREaL+b7Hu8Ef8azX9Dnb9k89PNzoi42WgkV2A3g0Dtk63wnpGRwe7du0OyX19fT0ZGBq2trcTFxfH5558Pu/5gCOb6nVkY8e+NYP9GJtj84tv/ioqKqKur05Zb+++RCKe+4WQoxveNiOHHX0QV6EUV0o1WiB9qfVeuXCEmJkZ73f+/781KgZBtX6AK72lpaURHR4dcXL22tpYZM2aQnZ3N6dOnuXz5sm67b/v6l+R6e3tN0d/T06M7P8ALL7ygW9o1SiD9Mhj1rwjfPtXfbl994bYPMHny5EGvr4nGh2h8yeLPvlGM5her1aoraj7YN00Z/xrVF2p8RMfLEig/KUz4RiqqQC+qkG60QvxQ6zt16hT5+fk4HA68Xi9PPvkkZ86cGWAn1ArzMhXebTabbjAPhr8K8gDnzp2jo6OD7OzsQUuVTZ8+ndmzZ3Px4kVyc3Pxer24XC5AHB+R/lOnTvH444/T0tJCZ2cnDz30EHfeead04d3ExEQiIyO1BJaYmMi1a9e4evWqtgwaSL+Mf2T86y++MvpSUlJIT0/H5XKRm5uLx+PR6Qu3ffjx7vT4+Hg2btxIQ0OD9r5ofIjGlyz+7Mu0D/zH12h+cbvd5OTk4HQ6sVqtPPLIIwP2kfFvqPlB5B9RfETHi/wnk58UJkykogr0ogrpRivED7W+w4cPExcXx9NPP01UVBSNjY288847A+yEWmFepsJ7Wlqa7tb0wfBXQb6f+vp6Hn30UQ4dOjTg2JMnT5KVlUVqaiput5uSkhJtm1H9H3/8MRaLheXLl2OxWHA6nUE9U/fiiy8ybdo03WuApqYmbbktkH4Z/8j41198ZfQ5HA4eeOABUlJScLlcbN68WXfucNsHuHDhAmPHjh2QIEXjQzS+ZPFnX6Z94D++RvNLSUkJBQUF7N69G5fLxd69e8nMzNTtI+PfUPODyD+i+IiOF/lPJj8pRngZtUmTJrFp06ZBtx04cICdO3cOs6LhZ/78+eTl5Rm+U2716tVYLBbdc2Pw43OYbW1t7Nixw9D5w4VR/Wb5N1TCbV+hUBhnRNxs5A+Xy6V7ZtWXkXBH4HBgs9moq6szfJ577rln0GVdQLsTcbRiRL9Z/h2t9hUKhXFG9EQKN8+E6Y9gf5xiMObOncstt9zCZ599ZoKiGwsz/Dua7SsUCuOM6KVdhUKhUChGOqqMmkKhUCgUBlATqUKhUCgUBvg/RV+sAdupuuUAAAAASUVORK5CYII=" title="lib.dom.iterable.d.ts" width="466" height="40" class="img_ev3q"></p>
<p>Yup it's there. And still using the setting <code>"typescript.tsdk": "node_modules/typescript/lib"</code>.</p>
<p><em>What if I remove this line?</em> Problem's still there. 😤</p>
<blockquote>
<p><em>ChatGPT</em>:</p>
<p><strong>7. Check for Extensions:</strong></p>
<p>Some extensions can interfere with TypeScript's configuration. Try disabling extensions one by one to see if any are causing the issue.</p>
</blockquote>
<p>Not useful. I'm using the same editor with the same set of extensions on two projects giving two different behaviour.</p>
<blockquote>
<p><em>ChatGPT</em>:</p>
<p><strong>8. Clear VS Code Cache:</strong></p>
<p>Sometimes, clearing the TypeScript server's cache can resolve issues. You can do this by:</p>
<ul>
<li class="">Deleting the .<code>vscode</code> directory in your project.</li>
<li class="">Restarting VS Code.</li>
</ul>
<p>By following these steps, you should be able to resolve the issue of VS Code not reading <code>lib.dom.iterable.d.ts</code> in your TypeScript project.</p>
</blockquote>
<p>Restarted already <em>lah</em>!</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="attempted-solution-6-to-problem-2---meta-ai">Attempted solution 6 to problem 2 - Meta AI<a href="https://www.cheehow.dev/blog/2024/06/12/typescript-no-overload-matches-this-call/#attempted-solution-6-to-problem-2---meta-ai" class="hash-link" aria-label="Direct link to Attempted solution 6 to problem 2 - Meta AI" title="Direct link to Attempted solution 6 to problem 2 - Meta AI" translate="no">​</a></h3>
<blockquote>
<p><em>Me</em>:</p>
<p>VS Code is not reading lib.dom.iterable.d.ts for my TypeScript project. How can I solve this problem?</p>
</blockquote>
<blockquote>
<p><em>Meta AI</em>:</p>
<p>Here are some steps you can take to troubleshoot why VS Code is not reading lib.dom.iterable.d.ts for your TypeScript project ¹ ² ³ ⁴:</p>
<ul>
<li class="">Ensure that your .d.ts file is open in your VS Code window for the changes to take effect.</li>
<li class="">Make sure your tsconfig.json file is in the root directory, as VS Code will only read files in this directory.</li>
<li class="">Try running the command "Reload Window" to see if this resolves the issue.</li>
<li class="">Check that your .d.ts file is in the correct directory and that the file path is correct in your tsconfig.json file.</li>
<li class="">Make sure that you are not skipping the library check in your tsconfig.json file by setting "skipLibCheck": false.</li>
<li class="">If you are still having trouble, try restarting the TypeScript server or VS Code to see if this resolves the issue.</li>
</ul>
</blockquote>
<p>The only things that are new as suggested by Meta AI are the "Reload Window" command and setting <code>"skipLibCheck": false</code>. Both of which didn't solve the problem.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="attempted-solution-7-to-problem-2---good-ol-google-search">Attempted solution 7 to problem 2 - good ol' Google Search<a href="https://www.cheehow.dev/blog/2024/06/12/typescript-no-overload-matches-this-call/#attempted-solution-7-to-problem-2---good-ol-google-search" class="hash-link" aria-label="Direct link to Attempted solution 7 to problem 2 - good ol' Google Search" title="Direct link to Attempted solution 7 to problem 2 - good ol' Google Search" translate="no">​</a></h3>
<blockquote>
<p><a href="https://www.google.com/search?q=lib.dom.iterable.d.ts+not+read+by+vs+code" target="_blank" rel="noopener noreferrer" class="">lib.dom.iterable.d.ts not read by vs code</a></p>
</blockquote>
<p>First result from StackOverflow had many of the attempted solutions listed.</p>
<p>Time for something more drastic. I closed the editor, removed the entire <em>node_modules</em> directory, ran <code>pnpm install</code>, then started the editor back up again.</p>
<p>No luck 🫤</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="attempted-solution-8-to-problem-2---include">Attempted solution 8 to problem 2 - <code>include</code><a href="https://www.cheehow.dev/blog/2024/06/12/typescript-no-overload-matches-this-call/#attempted-solution-8-to-problem-2---include" class="hash-link" aria-label="Direct link to attempted-solution-8-to-problem-2---include" title="Direct link to attempted-solution-8-to-problem-2---include" translate="no">​</a></h3>
<p>This is the "I'll try anything" stage.</p>
<p>The <code>include</code> field in <em>tsconfig.json</em> did not specify the <code>.ts</code> and <code>.tsx</code> files in the extension codebase. Maybe the configuration is sensitive that way?</p>
<table><thead><tr><th style="text-align:left">Option</th><th style="text-align:left">Value</th></tr></thead><tbody><tr><td style="text-align:left">Original</td><td style="text-align:left"><code>["src"]</code></td></tr><tr><td style="text-align:left">Changed</td><td style="text-align:left"><code>["**/*.ts", "**/*.tsx"]</code></td></tr></tbody></table>
<p>Result: Nope. ❌</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="attempted-solution-9-to-problem-2---exclude">Attempted solution 9 to problem 2 - <code>exclude</code><a href="https://www.cheehow.dev/blog/2024/06/12/typescript-no-overload-matches-this-call/#attempted-solution-9-to-problem-2---exclude" class="hash-link" aria-label="Direct link to attempted-solution-9-to-problem-2---exclude" title="Direct link to attempted-solution-9-to-problem-2---exclude" translate="no">​</a></h3>
<p>Another "I'll try anything" attempt.</p>
<p>I noticed that in the Next.js project, the <code>node_modules</code> directory was excluded.</p>
<table><thead><tr><th style="text-align:left">Project</th><th style="text-align:left">Option</th><th>Value</th></tr></thead><tbody><tr><td style="text-align:left">Next.js</td><td style="text-align:left">'exclude'</td><td><code>["node_modules"]</code></td></tr><tr><td style="text-align:left">Extension</td><td style="text-align:left">'exclude'</td><td><code>"exclude": ["src/**__tests__/*"]</code></td></tr></tbody></table>
<p>So in this attempt, I'm adding <code>node_modules</code> to <code>exclude</code>:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">"exclude": ["src/**__tests__/*", "node_modules"]</span><br></span></code></pre></div></div>
<p>Of course this didn't work — I don't expect it to. 🙄</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="attempted-solution-10-to-problem-2---project-references">Attempted solution 10 to problem 2 - project references<a href="https://www.cheehow.dev/blog/2024/06/12/typescript-no-overload-matches-this-call/#attempted-solution-10-to-problem-2---project-references" class="hash-link" aria-label="Direct link to Attempted solution 10 to problem 2 - project references" title="Direct link to Attempted solution 10 to problem 2 - project references" translate="no">​</a></h3>
<p>Grasping at straws now.</p>
<p>I noticed another difference between the two <em>tsconfig.json</em> files.</p>
<table><thead><tr><th style="text-align:left">Project</th><th style="text-align:left">Option</th><th style="text-align:left">Value</th></tr></thead><tbody><tr><td style="text-align:left">Next.js</td><td style="text-align:left"><code>references</code></td><td style="text-align:left"><em>not set</em></td></tr><tr><td style="text-align:left">Extension</td><td style="text-align:left"><code>references</code></td><td style="text-align:left"><code>[{ "path": "./tsconfig.node.json" }]</code></td></tr></tbody></table>
<p>The <em>tsconfig.node.json</em> file in the extension codebase looks like this:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "compilerOptions": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "composite": true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "skipLibCheck": true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "module": "ESNext",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "moduleResolution": "bundler",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "jsx": "react-jsx",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "paths": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "~src/*": ["./src/*"],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "~assets/*": ["./src/assets/*"],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "~pages/*": ["./src/pages/*"],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "~public/*": ["./src/public/*"]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "allowSyntheticDefaultImports": true</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "include": ["vite.config.ts", "src", "scripts", "plugins"]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre></div></div>
<p>Huh. There's no <code>lib</code> option here. Could that be it? What if I added <code>lib</code> to this config file?</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "compilerOptions": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "composite": true,</span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">    "lib": ["DOM", "DOM.Iterable"],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "skipLibCheck": true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "module": "ESNext",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "moduleResolution": "bundler",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "jsx": "react-jsx",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "paths": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "~src/*": ["./src/*"],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "~assets/*": ["./src/assets/*"],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "~pages/*": ["./src/pages/*"],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "~public/*": ["./src/public/*"]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "allowSyntheticDefaultImports": true</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "include": ["vite.config.ts", "src", "scripts", "plugins"]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre></div></div>
<div class="theme-admonition theme-admonition-success admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>success</div><div class="admonitionContent_BuS1"><p>😱 🎊 🎉</p></div></div>
<p>Took me four hours on a Sunday to figure it out and to write this post but I got it!</p>
<p>For whatever reason, the referenced project (<em>tsconfig.node.json</em>) is the one that VS Code is taking cue from instead of the one at the root (<em>tsconfig.json</em>).</p>
<p>No need for all the changes described in attempted solutions 1 to 8. All that's needed is just this one line <code>"lib": ["DOM", "DOM.Iterable"]</code> in the right file.</p>
<p>I had read <a href="https://www.typescriptlang.org/docs/handbook/project-references.html" target="_blank" rel="noopener noreferrer" class="">project references</a> before but never understood it well enough to internalise it. It's probably something I will procrastinate again until the next problem with tsconfig crops up. Again.</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p>On a related note, there is also <a href="https://code.visualstudio.com/docs/languages/jsconfig" target="_blank" rel="noopener noreferrer" class="">jsconfig.json</a> that is essentially <em>tsconfig.json</em> with <code>"allowJs": true</code></p></div></div>]]></content:encoded>
            <category>programming</category>
            <category>typescript</category>
            <category>tsconfig</category>
        </item>
        <item>
            <title><![CDATA[Coding conventions part 2]]></title>
            <link>https://www.cheehow.dev/blog/2024/05/25/coding-conventions-2/</link>
            <guid>https://www.cheehow.dev/blog/2024/05/25/coding-conventions-2/</guid>
            <pubDate>Sat, 25 May 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Collection of best practice coding conventions.]]></description>
            <content:encoded><![CDATA[<p><a class="" href="https://www.cheehow.dev/blog/2024/03/30/coding-conventions/">Part 1</a> documents conventions that can be enforced or guided through <abbr title="integrated development environment">IDE</abbr> settings.</p>
<p>Part 2 here describes conventions that really depend on the developers following them. In particular, the conventions here are for JavaScript/TypeScript code.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="naming">Naming<a href="https://www.cheehow.dev/blog/2024/05/25/coding-conventions-2/#naming" class="hash-link" aria-label="Direct link to Naming" title="Direct link to Naming" translate="no">​</a></h2>
<blockquote>
<p>There are two hard things in Computer Science: cache invalidation, naming things, and off-by-1 errors.</p>
<p>— <a href="https://twitter.com/secretGeek/status/7269997868" target="_blank" rel="noopener noreferrer" class="">Leon Bambrick</a></p>
</blockquote>
<p>General rule of thumb:</p>
<ul>
<li class="">Names of functions/variables should be spelled with letters only.</li>
<li class="">Numbers in names should only be used for localised variables (i.e. variables that are used within a function), and only when it makes sense (e.g. data from two similar sources).</li>
<li class="">Words can be abbreviated if the spelling is too long. E.g. <code>abbr</code> in place of <code>abbreviation</code></li>
<li class="">Never name anything with 2 or fewer letters unless the scope in which they are valid in is extremely small (e.g. in a <code>for</code> loop that doesn't require scrolling to see its entirety).</li>
<li class="">When an acronym is used, letters in the acronym after the first letter must be lowercase. E.g. <code>textXml</code>.</li>
<li class="">Casing for the first letter depends on context. Functions typically start with a lowercase (e.g. <code>checkIpAddress</code>) whereas classes typically start with an uppercase (e.g. <code>HttpRequestHandler</code>).</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="functionsmethods">Functions/Methods<a href="https://www.cheehow.dev/blog/2024/05/25/coding-conventions-2/#functionsmethods" class="hash-link" aria-label="Direct link to Functions/Methods" title="Direct link to Functions/Methods" translate="no">​</a></h3>
<ul>
<li class="">Use camelCasing.</li>
<li class="">Use imperative verbs.</li>
<li class="">Names should be no more than 4 words. E.g. <code>queryUserEmail</code>, <code>checkNewUserPresence</code></li>
<li class="">Functions that are used withn the same module (i.e. not <code>export</code>ed) as helper functions should be prefixed with an underscore. E.g. <code>_extractTitle</code>.</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="variables">Variables<a href="https://www.cheehow.dev/blog/2024/05/25/coding-conventions-2/#variables" class="hash-link" aria-label="Direct link to Variables" title="Direct link to Variables" translate="no">​</a></h3>
<ul>
<li class="">Use camelCasing.</li>
<li class="">Names should be no more than 3 words.</li>
<li class="">Private variables should be named starting with an underscore (<code>_</code>) when it makes sense to differentiate them (for example local variables that should be differentiated from class properties).</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="imports">Imports<a href="https://www.cheehow.dev/blog/2024/05/25/coding-conventions-2/#imports" class="hash-link" aria-label="Direct link to Imports" title="Direct link to Imports" translate="no">​</a></h3>
<p><code>import</code> statements should be placed at the top of the file. There needs to be a strong reason to place the <code>import</code> statements anywhere else than the top of the page.</p>
<p>If there is a docblock at the top of the file, the <code>import</code> statements should be placed after the docblock.</p>
<p>The statements should be grouped by the modules according to the following heuristics:</p>
<ul>
<li class="">Each group should be separated by an empty line.</li>
<li class="">The first group should contain the <code>import</code> statements of public npm packages.</li>
<li class="">The second group should contain the <code>import</code> statements of private npm packages, if applicable.</li>
<li class="">The third group onwards should contain local <code>import</code> statements.</li>
<li class="">They should also be further grouped by the level of traversal upwards.</li>
<li class="">Within each group, the order of the <code>import</code> statements should be based on the alphabetical order of the packages/modules/files.</li>
</ul>
<p>For example:</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">GetServerSideProps</span><span class="token imports"> </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'next'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports maybe-class-name">Link</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'next/link'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">ReactElement</span><span class="token imports"> </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'react'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">Grid</span><span class="token imports"> </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'react-bootstrap-icons'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">PAGE_SETUP</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">TOKEN_TWITTER</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'./constants'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> logger </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'../lib/logger'</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="typescript">TypeScript<a href="https://www.cheehow.dev/blog/2024/05/25/coding-conventions-2/#typescript" class="hash-link" aria-label="Direct link to TypeScript" title="Direct link to TypeScript" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="non-null-assertion-operator">Non-null assertion operator<a href="https://www.cheehow.dev/blog/2024/05/25/coding-conventions-2/#non-null-assertion-operator" class="hash-link" aria-label="Direct link to Non-null assertion operator" title="Direct link to Non-null assertion operator" translate="no">​</a></h4>
<p>The non-null assertion operator (the exclamation mark used after a variable) must be accompanied by a comment when used. E.g.</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// `where` is initialised before this line.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">args</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">where</span><span class="token operator" style="color:#393A34">!</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">year </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">in</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">2023</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>As an alternative to using this operator, consider if the following alternative works:</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">args</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">where </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> Object</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">assign</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> args</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">where</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  year</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">in</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">2023</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>OR</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">args</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">where </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">...</span><span class="token plain">args</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">where</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  year</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">in</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">2023</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="imports-1">Imports<a href="https://www.cheehow.dev/blog/2024/05/25/coding-conventions-2/#imports-1" class="hash-link" aria-label="Direct link to Imports" title="Direct link to Imports" translate="no">​</a></h3>
<p><code>import</code> statements should be placed at the top of the file. There needs to be a strong reason to place the <code>import</code> statements anywhere else than the top of the page.</p>
<p>If there is a docblock at the top of the file, the <code>import</code> statements should be placed after the docblock.</p>
<p>The statements should be grouped by the modules according to the following heuristics:</p>
<ul>
<li class="">Each group should be separated by an empty line.</li>
<li class="">The first group should contain the <code>import</code> statements of public npm packages.</li>
<li class="">The second group should contain the <code>import</code> statements of private npm packages, if applicable.</li>
<li class="">The third group onwards should contain local <code>import</code> statements.</li>
<li class="">They should also be further grouped by the level of traversal upwards.</li>
<li class="">Within each group, the order of the <code>import</code> statements should be based on the alphabetical order of the packages/modules/files.</li>
</ul>
<p>For example:</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">GetServerSideProps</span><span class="token imports"> </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'next'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports maybe-class-name">Link</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'next/link'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">ReactElement</span><span class="token imports"> </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'react'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">Grid</span><span class="token imports"> </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'react-bootstrap-icons'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">PAGE_SETUP</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">TOKEN_TWITTER</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'./constants'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> logger </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'../lib/logger'</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="typescript-1">TypeScript<a href="https://www.cheehow.dev/blog/2024/05/25/coding-conventions-2/#typescript-1" class="hash-link" aria-label="Direct link to TypeScript" title="Direct link to TypeScript" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="non-null-assertion-operator-1">Non-null assertion operator<a href="https://www.cheehow.dev/blog/2024/05/25/coding-conventions-2/#non-null-assertion-operator-1" class="hash-link" aria-label="Direct link to Non-null assertion operator" title="Direct link to Non-null assertion operator" translate="no">​</a></h4>
<p>The non-null assertion operator (the exclamation mark used after a variable) must be accompanied by a comment when used. E.g.</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// `where` is initialised before this line.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">args</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">where</span><span class="token operator" style="color:#393A34">!</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">year </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">in</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">2023</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>As an alternative to using this operator, consider if the following alternative works:</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">args</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">where </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> Object</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">assign</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> args</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">where</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  year</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">in</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">2023</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>OR</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">args</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">where </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">...</span><span class="token plain">args</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">where</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  year</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">in</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">2023</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="react">React<a href="https://www.cheehow.dev/blog/2024/05/25/coding-conventions-2/#react" class="hash-link" aria-label="Direct link to React" title="Direct link to React" translate="no">​</a></h2>
<ul>
<li class="">Components should be named using PascalCasing.</li>
<li class="">Names should be no more than 3 words. E.g. <code>UsernameInput</code>, <code>Footer</code>.</li>
<li class="">Use functional components in conjunction with hooks.</li>
<li class="">Types, constants and variables should be defined outside of the component if possible. If not, they should be placed at the top of the component code (see below).</li>
<li class="">Hooks should be placed at the start of the component definition and should be written in the following order: <code>useRouter</code>, <code>useContext</code>, <code>useState</code>, <code>useRef</code>, <code>useReducer</code>, <code>useCallback</code>, <code>useEffect</code>.</li>
<li class="">Custom hooks should be called after the other hooks.</li>
<li class="">Define functions and event handlers next.</li>
<li class="">Component code (code that is for the component and runs just once per render), if any, should then be placed before the <code>return</code> statement. Variables and constants should be defined at the start in this block.</li>
<li class="">Callback functions passed to <code>useEffect</code> should be named even though anonymous functions are accepted. This will make the purpose of the <code>useEffect</code> calls much more clearer. E.g.</li>
</ul>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">useEffect</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">loadList</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token spread operator" style="color:#393A34">...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="miscellaneous">Miscellaneous<a href="https://www.cheehow.dev/blog/2024/05/25/coding-conventions-2/#miscellaneous" class="hash-link" aria-label="Direct link to Miscellaneous" title="Direct link to Miscellaneous" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="constants">Constants<a href="https://www.cheehow.dev/blog/2024/05/25/coding-conventions-2/#constants" class="hash-link" aria-label="Direct link to Constants" title="Direct link to Constants" translate="no">​</a></h3>
<p>The concept of constant is different in JavaScript/TypeScript as compared to other languages. The <code>const</code> keyword is used to define a variable as not changeable. This can have different effects depending on whether the type is a primitive (like <code>string</code>) or a reference (pointing to an <code>object</code>).</p>
<p>Here "constant" refers to values that are fixed, <strong>primitive</strong> values. These values do not change for the life time of the scope that they are used in. These variables are named in uppercase letters. Words are separated by underscores. E.g.</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">GRAVITY_ON_MOON</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1.62</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>A constant should be named with no more than 4 words.</p>
<p>If the "constant" is not a primitive value (e.g. an array), it should <em>not</em> be named in uppercase letters as the values in the array/object can be changed either by intention or not.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="eslint-for-backend">ESLint for backend<a href="https://www.cheehow.dev/blog/2024/05/25/coding-conventions-2/#eslint-for-backend" class="hash-link" aria-label="Direct link to ESLint for backend" title="Direct link to ESLint for backend" translate="no">​</a></h3>
<p>The ESLint configuration file is as follows:</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">module</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">exports</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">env</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">browser</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">es2021</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">extends</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'standard-with-typescript'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">overrides</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">parser</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'@typescript-eslint/parser'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">parserOptions</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">ecmaVersion</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'latest'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">sourceType</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'module'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">plugins</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'@typescript-eslint'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">rules</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string-property property" style="color:#36acaa">'comma-dangle'</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'off'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string-property property" style="color:#36acaa">'@typescript-eslint/comma-dangle'</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'error'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// https://futurestud.io/tutorials/how-to-allow-trailing-commas-comma-dangle-with-typescript-eslint</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string-property property" style="color:#36acaa">'@typescript-eslint/no-unused-vars'</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'error'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'only-multiline'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>The file is generated using <code>npx eslint --init</code> (reference <a href="https://blog.logrocket.com/linting-typescript-eslint-prettier" target="_blank" rel="noopener noreferrer" class="">https://blog.logrocket.com/linting-typescript-eslint-prettier</a>) and modified afterwards.</p>
<p>Note: If the project is scaffolded using public tools such as <code>create-next-app</code>, follow the ESLint configuration from the scaffold.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="tsconfig">TSConfig<a href="https://www.cheehow.dev/blog/2024/05/25/coding-conventions-2/#tsconfig" class="hash-link" aria-label="Direct link to TSConfig" title="Direct link to TSConfig" translate="no">​</a></h3>
<p>The <em>tsconfig.json</em> file differs between that for the Web app and the server.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="backend">Backend<a href="https://www.cheehow.dev/blog/2024/05/25/coding-conventions-2/#backend" class="hash-link" aria-label="Direct link to Backend" title="Direct link to Backend" translate="no">​</a></h3>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token string-property property" style="color:#36acaa">"include"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"src"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token string-property property" style="color:#36acaa">"exclude"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"node_modules"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token string-property property" style="color:#36acaa">"extends"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"@tsconfig/node-lts/tsconfig.json"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token string-property property" style="color:#36acaa">"compilerOptions"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string-property property" style="color:#36acaa">"allowJs"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string-property property" style="color:#36acaa">"outDir"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"./dist"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string-property property" style="color:#36acaa">"noImplicitAny"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>The file is generated using <code>npx tsc --init</code>. It is complimented by the package <a href="https://github.com/tsconfig/bases#centralized-recommendations-for-tsconfig-bases" target="_blank" rel="noopener noreferrer" class="">@tsconfig/node-lts</a>.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="web-frontend">Web frontend<a href="https://www.cheehow.dev/blog/2024/05/25/coding-conventions-2/#web-frontend" class="hash-link" aria-label="Direct link to Web frontend" title="Direct link to Web frontend" translate="no">​</a></h3>
<p>The <em>tsconfig.json</em> file is created using Vite (<code>npm create vite@latest</code>).</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="typescript-5-notes">TypeScript 5 Notes<a href="https://www.cheehow.dev/blog/2024/05/25/coding-conventions-2/#typescript-5-notes" class="hash-link" aria-label="Direct link to TypeScript 5 Notes" title="Direct link to TypeScript 5 Notes" translate="no">​</a></h3>
<p>Starting from TypeScript 5.0, the option <code>--verbatimModuleSyntax</code> replaces <code>--importsNotUsedAsValues</code> and <code>--preserveValueImports</code>. This setting should be included in <em>tsconfig.json</em> with the value <code>true</code>.</p>
<p>Reference: <a href="https://www.typescriptlang.org/tsconfig#verbatimModuleSyntax" target="_blank" rel="noopener noreferrer" class="">https://www.typescriptlang.org/tsconfig#verbatimModuleSyntax</a></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="commits">Commits<a href="https://www.cheehow.dev/blog/2024/05/25/coding-conventions-2/#commits" class="hash-link" aria-label="Direct link to Commits" title="Direct link to Commits" translate="no">​</a></h2>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="check-your-git-username-and-email">Check your Git username and email<a href="https://www.cheehow.dev/blog/2024/05/25/coding-conventions-2/#check-your-git-username-and-email" class="hash-link" aria-label="Direct link to Check your Git username and email" title="Direct link to Check your Git username and email" translate="no">​</a></h4>
<p>All too often I see programmers, particularly junior ones who have been using the same computer since they learnt Git, use the same username and email address for every project because they've set it <em>globally</em>! This makes it hard to identify and track down changes in the future.</p>
<p>Just have a look at this:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">commit 551421f5251f9b6c0cb4fb5a7752ce58349b0ef8</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Author: Spartacus Grizzly &lt;cheekybear98@gmail.com&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Date:   Mon Mar 18 15:44:41 2024 +0800</span><br></span></code></pre></div></div>
<p>How the hell is any one going to know who Spartacus Grizzly is? 🙄</p>
<p>If you're going to work on a company job, use a proper name and the company email address given to you!</p>
<p>We're not asking every developer to change the name and email address globally. Just use <code>git config user.name</code> and <code>git config user.email</code> to change the values for the project.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="never-commit-with-an-empty-message">Never commit with an empty message.<a href="https://www.cheehow.dev/blog/2024/05/25/coding-conventions-2/#never-commit-with-an-empty-message" class="hash-link" aria-label="Direct link to Never commit with an empty message." title="Direct link to Never commit with an empty message." translate="no">​</a></h4>
<p>The fact that this has to be listed is frustrating. 😤</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="each-commit-should-be-targeted">Each commit should be targeted<a href="https://www.cheehow.dev/blog/2024/05/25/coding-conventions-2/#each-commit-should-be-targeted" class="hash-link" aria-label="Direct link to Each commit should be targeted" title="Direct link to Each commit should be targeted" translate="no">​</a></h4>
<p>Each commit should aim to add <em>one</em> feature, or to fix <em>one</em> thing only. Another way of saying this is to make each commit as small as possible.</p>
<p>Not only does this make it easy to review code commits, any issues can be more easily tracked down as well. Any necessary reverts can be done more easily as well.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="corrections-should-be-made-as-amendments-rather-than-new-commits">Corrections should be made as amendments rather than new commits<a href="https://www.cheehow.dev/blog/2024/05/25/coding-conventions-2/#corrections-should-be-made-as-amendments-rather-than-new-commits" class="hash-link" aria-label="Direct link to Corrections should be made as amendments rather than new commits" title="Direct link to Corrections should be made as amendments rather than new commits" translate="no">​</a></h4>
<p>Commits that are basically corrections for the previous commit should included as part of the original commit as far as possible.</p>
<p>A common occurrence for this situation is when a file is modified but not saved before the commit. Or a file that should be included in the commit but was not.</p>
<p>Rather than making a new commit for this, the file should be staged and included with the previous commit using <code>git commit --amend</code>.</p>
<p>However, this should only be done for commits that are <em>not</em> pushed to the cloud repository. If the commit has already been pushed, this will cause the remote branch to be inconsistent with your local branch, causing the commit history to be more messy than adding a new commit.</p>]]></content:encoded>
            <category>programming</category>
            <category>developer setup</category>
            <category>coding conventions</category>
        </item>
        <item>
            <title><![CDATA[Show recent posts in Docusaurus]]></title>
            <link>https://www.cheehow.dev/blog/2024/04/01/show-recent-posts-in-docusaurus/</link>
            <guid>https://www.cheehow.dev/blog/2024/04/01/show-recent-posts-in-docusaurus/</guid>
            <pubDate>Mon, 01 Apr 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[A simple way to show recent blog posts in the index page.]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="tldr">TL;DR<a href="https://www.cheehow.dev/blog/2024/04/01/show-recent-posts-in-docusaurus/#tldr" class="hash-link" aria-label="Direct link to TL;DR" title="Direct link to TL;DR" translate="no">​</a></h2>
<p>At a high level, these are the steps.</p>
<ol>
<li class="">Create a custom plugin that extends the original blog plugin (<a href="https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-blog" target="_blank" rel="noopener noreferrer" class="">plugin-content-blog</a>).</li>
<li class="">Disable the original blog plugin and use the new custom one.</li>
<li class="">Import the JSON file containing the recent articles.</li>
</ol>
<p>For details of each step, see <a class="" href="https://www.cheehow.dev/blog/2024/04/01/show-recent-posts-in-docusaurus/#option-2">Option 2</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="preamble">Preamble<a href="https://www.cheehow.dev/blog/2024/04/01/show-recent-posts-in-docusaurus/#preamble" class="hash-link" aria-label="Direct link to Preamble" title="Direct link to Preamble" translate="no">​</a></h2>
<p>I'm in the camp of static site generators when it comes to creating a blog. Hands-down <a href="https://docusaurus.io/" target="_blank" rel="noopener noreferrer" class="">Docusaurus</a> is the best that I've come across.</p>
<p>As soon as I got to understand Docusaurus, I ditched <a href="https://gohugo.io/" target="_blank" rel="noopener noreferrer" class="">Hugo</a>, my previous static site generator of choice. I knew that I will be using Docusaurus for the long term.</p>
<p>Despite my partiality towards Docusaurus, one function that I've found sorely missing is the ability to show the most recent blog posts in the home page. And <a href="https://docusaurus.io/feature-requests/p/recent-blog-posts-on-home-page" target="_blank" rel="noopener noreferrer" class="">I'm not the only one.</a></p>
<p>Ever since I moved my blog over in February 2023, I've been looking for a method to do this on and off over the past year.</p>
<p>Until recently, the best explanation that I've found <a href="https://stackoverflow.com/a/60537790" target="_blank" rel="noopener noreferrer" class="">describes in abstract terms how to do it</a> but doesn't show any concrete steps.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="option-1">Option 1<a href="https://www.cheehow.dev/blog/2024/04/01/show-recent-posts-in-docusaurus/#option-1" class="hash-link" aria-label="Direct link to Option 1" title="Direct link to Option 1" translate="no">​</a></h2>
<p>After a few months, I decided that there was no easy way. So I thought of a method where I render the posts client side using the RSS feed from the blog.</p>
<p>It's really more of a workaround rather than an "actual" solution.</p>
<p>This is achieved by using <code>useEffect</code> that fetches and parses the RSS feed. Here is how I did it.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="import-the-useeffect-function-if-not-already-done">Import the useEffect function if not already done.<a href="https://www.cheehow.dev/blog/2024/04/01/show-recent-posts-in-docusaurus/#import-the-useeffect-function-if-not-already-done" class="hash-link" aria-label="Direct link to Import the useEffect function if not already done." title="Direct link to Import the useEffect function if not already done." translate="no">​</a></h3>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> useEffect </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'react'</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="fetch-the-rss-feed-in-useeffect">Fetch the RSS feed in <code>useEffect</code>:<a href="https://www.cheehow.dev/blog/2024/04/01/show-recent-posts-in-docusaurus/#fetch-the-rss-feed-in-useeffect" class="hash-link" aria-label="Direct link to fetch-the-rss-feed-in-useeffect" title="Direct link to fetch-the-rss-feed-in-useeffect" translate="no">​</a></h3>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv codeBlockLinesWithNumbering_o6Pm" style="counter-reset:line-count 0"><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">feed</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> setFeed</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token generic-function function" style="color:#d73a49">useState</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name">Record</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name builtin">string</span><span class="token generic-function generic class-name punctuation" style="color:#393A34">,</span><span class="token generic-function generic class-name"> </span><span class="token generic-function generic class-name builtin">any</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token generic-function generic class-name punctuation" style="color:#393A34">[</span><span class="token generic-function generic class-name punctuation" style="color:#393A34">]</span><span class="token generic-function generic class-name"> </span><span class="token generic-function generic class-name operator" style="color:#393A34">|</span><span class="token generic-function generic class-name"> </span><span class="token generic-function generic class-name keyword" style="color:#00009f">null</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token function" style="color:#d73a49">useEffect</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">fetchFeed</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></span><span class="token-line theme-code-block-highlighted-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token function" style="color:#d73a49">fetch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation constant" style="color:#36acaa">WEBSITE</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string string" style="color:#e3116c">/blog/rss.xml</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">then</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">resp</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> resp</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">text</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">then</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">xmlText</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></span><span class="token-line theme-code-block-highlighted-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> xml </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">window</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">DOMParser</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">parseFromString</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">xmlText</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'text/xml'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line theme-code-block-highlighted-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> items </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> xml</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">querySelectorAll</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'item'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line theme-code-block-highlighted-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> latestArticle </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line theme-code-block-highlighted-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> endingArticle </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line theme-code-block-highlighted-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> posts </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">extractPosts</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">items</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> latestArticle</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> endingArticle</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">      </span><span class="token function" style="color:#d73a49">setFeed</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">posts</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span></span><br></span></code></pre></div></div>
<p>The <code>fetch</code> function retrieves the RSS feed from the published website (indicated by the variable <code>WEBSITE</code>). The feed is then converted into XML (line 7). The articles are contained in <code>item</code> elements (line 9). In this code segment, the latest article is selected (<code>latestArticle = 0</code>) along with the second latest one (<code>endingArticle = 2</code>), meaning that the newest 2 articles will be shown.</p>
<p>The posts are extracted using <code>extractPosts</code>.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="extract-the-posts">Extract the posts<a href="https://www.cheehow.dev/blog/2024/04/01/show-recent-posts-in-docusaurus/#extract-the-posts" class="hash-link" aria-label="Direct link to Extract the posts" title="Direct link to Extract the posts" translate="no">​</a></h3>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv codeBlockLinesWithNumbering_o6Pm" style="counter-reset:line-count 0"><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">extractPosts</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">elements</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> NodeListOf</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">Element</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> start </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> count </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> subset </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> start</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> start </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> count</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i</span><span class="token operator" style="color:#393A34">++</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">i </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> elements</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">length</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">      subset</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">        title</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> elements</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">querySelector</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'title'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">textContent</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">        link</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> elements</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">querySelector</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'link'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">innerHTML</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">        pubDate</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> elements</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">querySelector</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'pubDate'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">textContent</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">        description</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> elements</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">querySelector</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'description'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">textContent </span><span class="token operator" style="color:#393A34">??</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">''</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> subset</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span></span><br></span></code></pre></div></div>
<p>This will make the recent articles are available in the index page (<code>setFeed(posts)</code>), so they can then be rendered to your desire.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="drawbacks">Drawbacks<a href="https://www.cheehow.dev/blog/2024/04/01/show-recent-posts-in-docusaurus/#drawbacks" class="hash-link" aria-label="Direct link to Drawbacks" title="Direct link to Drawbacks" translate="no">​</a></h3>
<p>While this method is straightforward, there are some drawbacks.</p>
<ul>
<li class="">First, it depends on the RSS feed from the production website, which means that it will not reflect the articles that you just added to the site in development.</li>
<li class="">Second, since the list is rendered client-side, it will (generally) not be picked up by search engines. Granted, this may not impact the SEO performance much since it's just a short list of articles.</li>
<li class="">Third, since the code is fetching another resource after the page is loaded, there will be a delay before the list is rendered. Depending on your preference and how you layout your page, this might be a dealbreaker.</li>
<li class="">Fourth, depending on how the server hosting the site behaves, the feed may be stale i.e. the feed may not show the latest articles from the site, making the list show inaccurate data.</li>
</ul>
<p>Despite all these shortcomings, this was the only solution I had for a while.</p>
<p>But the problem about showing stale data (problem #4) was painful enough for me to keep looking for a better solution.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="option-2">Option 2<a href="https://www.cheehow.dev/blog/2024/04/01/show-recent-posts-in-docusaurus/#option-2" class="hash-link" aria-label="Direct link to Option 2" title="Direct link to Option 2" translate="no">​</a></h2>
<p>After spending the better part of Easter Friday, I finally got something working.</p>
<p>I found an <a href="https://kgajera.com/blog/display-recent-blog-posts-on-home-page-with-docusaurus/" target="_blank" rel="noopener noreferrer" class="">article</a> that actually describes step-by-step how the recent articles can be placed in the index page. However, this method requires replacing the index page with the blog listing page. This was a bit more drastic than what I was expecting - I didn't want to have to redesign the blog listing page to look like the index page.</p>
<p>Instead I opted to use the method suggested by <a href="https://github.com/slorber" target="_blank" rel="noopener noreferrer" class="">Sébastien Lorber</a> (one of Docusaurus' maintainers) in this <a href="https://github.com/facebook/docusaurus/issues/4138#issuecomment-771042127" target="_blank" rel="noopener noreferrer" class="">Github issue</a> which is to create an intermediate JSON file. Then the index page will import this JSON file and render the posts on the index page.</p>
<p>As described in the <a href="https://www.cheehow.dev/blog/2024/04/01/show-recent-posts-in-docusaurus/#tldr" class="">TL;DR</a>, the steps are:</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="create-a-custom-plugin-that-extends-the-original-blog-plugin-plugin-content-blog">Create a custom plugin that extends the original blog plugin (<a href="https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-blog" target="_blank" rel="noopener noreferrer" class="">plugin-content-blog</a>)<a href="https://www.cheehow.dev/blog/2024/04/01/show-recent-posts-in-docusaurus/#create-a-custom-plugin-that-extends-the-original-blog-plugin-plugin-content-blog" class="hash-link" aria-label="Direct link to create-a-custom-plugin-that-extends-the-original-blog-plugin-plugin-content-blog" title="Direct link to create-a-custom-plugin-that-extends-the-original-blog-plugin-plugin-content-blog" translate="no">​</a></h3>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">plugins/recent-blog-posts.js</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv codeBlockLinesWithNumbering_o6Pm" style="counter-reset:line-count 0"><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> fs </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">require</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'node:fs'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line theme-code-block-highlighted-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> blogPluginExports </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">require</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'@docusaurus/plugin-content-blog'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> defaultBlogPlugin </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> blogPluginExports</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">default</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">blogPluginEnhanced</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">...</span><span class="token plain">pluginArgs</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> blogPluginInstance </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">defaultBlogPlugin</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">...</span><span class="token plain">pluginArgs</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> dir </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'.docusaurus'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token operator" style="color:#393A34">...</span><span class="token plain">blogPluginInstance</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token function-variable function" style="color:#d73a49">contentLoaded</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">data</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> recentPosts </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token operator" style="color:#393A34">...</span><span class="token plain">data</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">content</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">blogPosts</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// Only show published posts.</span><span class="token plain"></span></span><br></span><span class="token-line theme-code-block-highlighted-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">filter</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">p</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">!</span><span class="token plain">p</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">metadata</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">unlisted</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><br></span><span class="token-line theme-code-block-highlighted-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">slice</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line theme-code-block-highlighted-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">      recentPosts </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> recentPosts</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">p</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></span><span class="token-line theme-code-block-highlighted-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></span><span class="token-line theme-code-block-highlighted-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">          id</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> p</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">id</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></span><span class="token-line theme-code-block-highlighted-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">          metadata</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> p</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">metadata</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></span><span class="token-line theme-code-block-highlighted-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line theme-code-block-highlighted-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">      fs</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">mkdirSync</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">dir</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">        recursive</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// Avoid error if directory already exists.</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line theme-code-block-highlighted-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> fd </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> fs</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">openSync</span><span class="token punctuation" style="color:#393A34">(</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation">dir</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string string" style="color:#e3116c">/recent-posts.json</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'w'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line theme-code-block-highlighted-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">      fs</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">writeSync</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">fd</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">JSON</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">stringify</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">recentPosts</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> blogPluginInstance</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">contentLoaded</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">data</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">module</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">exports </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token operator" style="color:#393A34">...</span><span class="token plain">blogPluginExports</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">default</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> blogPluginEnhanced</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span></span><br></span></code></pre></div></div>
<p>Create a <em>plugins</em> directory in root of the project (same level as <em>src</em>). Place the file <em>recent-blog-posts.js</em> into this directory as the plugin. (You can choose different names for the directory and file - they are not treated any differently.)</p>
<p>By including the plugin (line 3), the plugin is being extended.</p>
<p>Line 17 is of note. It checks to make sure that only listed posts will be included (<code>filter((p) =&gt; !p.metadata.unlisted)</code>). Remember that this value only <a href="https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-blog#unlisted" target="_blank" rel="noopener noreferrer" class="">takes effect in production</a>.</p>
<p>On line 18, we tell the plugin to return the latest 3 posts.</p>
<p>Lines 20-25 are optional. They are there to keep the intermediate JSON file small by omitting the full contents of the posts.</p>
<p>Lines 30-31 write the posts into the intermediate JSON which is named <code>recent-posts.json</code> and placed in the <em>.docusaurus</em> directory.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="disable-the-original-blog-plugin-and-use-the-new-custom-one">Disable the original blog plugin and use the new custom one<a href="https://www.cheehow.dev/blog/2024/04/01/show-recent-posts-in-docusaurus/#disable-the-original-blog-plugin-and-use-the-new-custom-one" class="hash-link" aria-label="Direct link to Disable the original blog plugin and use the new custom one" title="Direct link to Disable the original blog plugin and use the new custom one" translate="no">​</a></h3>
<p>This step requires modifying the configuration file <em>docusaurus.config.js</em>. The exact changes depend on whether the blog plugin was added manually (standalone) or as part of the theme.</p>
<p><strong>If the plugin is configured standalone</strong>, then it would be in the <code>plugins</code> array:</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> config </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">plugins</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token string" style="color:#e3116c">'@docusaurus/plugin-content-blog'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// rest of blog plugin options</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// rest of config</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>To use the new custom plugin, swap out the original one with the new one.</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> config </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">plugins</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">      </span><span class="token string" style="color:#e3116c">'./plugins/recent-blog-posts'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// rest of blog plugin options</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// rest of config</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p><strong>If the plugin is included as part of a preset</strong> (e.g. the classic preset <code>@docusaurus/preset-classic</code>), like the majority of users who follow the <a href="https://docusaurus.io/docs/installation#scaffold-project-website" target="_blank" rel="noopener noreferrer" class="">installation guide</a> do, then the configuration is placed in the <code>presets</code> array:</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> config </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">presets</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token string" style="color:#e3116c">'classic'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token doc-comment comment" style="color:#999988;font-style:italic">/** </span><span class="token doc-comment comment keyword" style="color:#00009f;font-style:italic">@type</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"> </span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">{</span><span class="token doc-comment comment class-name keyword" style="color:#00009f;font-style:italic">import</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">(</span><span class="token doc-comment comment class-name string" style="color:#e3116c;font-style:italic">'@docusaurus/preset-classic'</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">)</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">.</span><span class="token doc-comment comment class-name" style="color:#999988;font-style:italic">Options</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">}</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"> */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token literal-property property" style="color:#36acaa">blog</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token literal-property property" style="color:#36acaa">showReadingTime</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token comment" style="color:#999988;font-style:italic">// rest of blog plugin options</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// rest of preset options</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// rest of config</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>To use the new custom plugin, disable the blog plugin in the preset:</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> config </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">presets</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token string" style="color:#e3116c">'classic'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token doc-comment comment" style="color:#999988;font-style:italic">/** </span><span class="token doc-comment comment keyword" style="color:#00009f;font-style:italic">@type</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"> </span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">{</span><span class="token doc-comment comment class-name keyword" style="color:#00009f;font-style:italic">import</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">(</span><span class="token doc-comment comment class-name string" style="color:#e3116c;font-style:italic">'@docusaurus/preset-classic'</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">)</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">.</span><span class="token doc-comment comment class-name" style="color:#999988;font-style:italic">Options</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">}</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"> */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">        </span><span class="token literal-property property" style="color:#36acaa">blog</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// rest of preset options</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// rest of config</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>And add the custom plugin into the <code>plugins</code> array (you may have to create the entire <code>plugins</code> property if it is not already present):</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> config </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">plugins</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">      </span><span class="token string" style="color:#e3116c">'./plugins/recent-blog-posts'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token literal-property property" style="color:#36acaa">showReadingTime</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// rest of blog plugin options</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// rest of config</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="import-the-json-file-containing-the-recent-articles">Import the JSON file containing the recent articles<a href="https://www.cheehow.dev/blog/2024/04/01/show-recent-posts-in-docusaurus/#import-the-json-file-containing-the-recent-articles" class="hash-link" aria-label="Direct link to Import the JSON file containing the recent articles" title="Direct link to Import the JSON file containing the recent articles" translate="no">​</a></h3>
<p>Add the following import statement into your index page (or component) and you can access the recent articles.</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports">recentPosts</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'@site/.docusaurus/recent-posts.json'</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_BuS1"><p>TypeScript users, you may see an wriggly underline error in your IDE saying <code>Cannot find module '@site/.docusaurus/recent-posts.json'. Consider using '--resolveJsonModule' to import module with '.json' extension.</code></p><p>To resolve this issue, follow the instructions and add <code>"resolveJsonModule": true</code> to the <em>tsconfig.json</em> file found at the root.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://www.cheehow.dev/blog/2024/04/01/show-recent-posts-in-docusaurus/#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion" translate="no">​</a></h2>
<p>I would have preferred to be able to specify the number of recent posts to display by specifying the number as an option in <em>docusaurus.config.js</em> but I couldn't get it to work.</p>
<p>Adding an additional option for the plugin like this:</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> config </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">plugins</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token string" style="color:#e3116c">'./plugins/recent-blog-posts'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token literal-property property" style="color:#36acaa">showReadingTime</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">        </span><span class="token literal-property property" style="color:#36acaa">recentPosts</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// rest of blog plugin options</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// rest of config</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>raises this error:</p>
<blockquote>
<p>[ERROR] ValidationError: "recentPosts" is not allowed</p>
</blockquote>
<p>This is due to the validation of options by the original plugin. I do not think there is much value in modifying the original plugin (or to fork it) to achieve this minor enhancement.</p>
<p>I'm pretty happy with this outcome as it is. Nevertheless, if you have an idea of how to make the number of recent posts configurable in <em>docusaurus.config.js</em>, hit me up on <a href="https://twitter.com/chuacheehow" target="_blank" rel="noopener noreferrer" class="">Twitter</a>.</p>]]></content:encoded>
            <category>docusaurus</category>
            <category>programming</category>
        </item>
        <item>
            <title><![CDATA[Coding conventions]]></title>
            <link>https://www.cheehow.dev/blog/2024/03/30/coding-conventions/</link>
            <guid>https://www.cheehow.dev/blog/2024/03/30/coding-conventions/</guid>
            <pubDate>Sat, 30 Mar 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[This is another one of those things that every developer has an opinion of.]]></description>
            <content:encoded><![CDATA[<p>This is another one of those things that every developer has an opinion of. Can't blame <del>them</del> us really. As much as programming is science, it is also an art. And artists have their own temperaments.</p>
<p>Regardless, unlike artists, developers have to work as a team. That means that they have to follow the team's conventions regardless of their preferences.</p>
<p>Many conventions can now be easily enforced via configurations settings, thanks to the ubiquity of <a href="https://code.visualstudio.com/" target="_blank" rel="noopener noreferrer" class="">VS Code</a> and, to a lesser extent, <a href="https://prettier.io/" target="_blank" rel="noopener noreferrer" class="">Prettier</a>.</p>
<p>This article looks at the easy steps we can take to enforce coding conventions easily for a Next.js project.</p>
<p>The preference settings in VS Code, together with a formatter (such as Prettier), can handle most of the coding conventions that a team wants to establish.</p>
<p>One thing to note about the settings in VS Code is that some are conventions that <em>should</em> established for all team members, some are personal preferences, which should remain personal.</p>
<p>My understanding is that <em>workspace</em> settings (specified by the file <em>.vscode/settings.json</em>) override <em>user</em> settings. (If the setting is not specified at the workspace level, it naturally takes the value from the user level.) Therefore it is important to specify what should be set and what should not be.</p>
<p>Below are contents of <em>settings.json</em> that I set for my projects:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "editor.detectIndentation": true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "editor.insertSpaces": false,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "editor.indentSize": "tabSize",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "editor.formatOnSave": true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "editor.defaultFormatter": "esbenp.prettier-vscode",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "prettier.arrowParens": "always"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre></div></div>
<p>These settings achieve the following:</p>
<ol>
<li class="">Prefer for VS Code to determine whether to use tabs or spaces based on what is currently being used in the file being edited. (<code>"editor.detectIndentation": true</code>)</li>
<li class="">If the file is empty (or if VS Code cannot determine the pre-existing indentation convention in the file), tell VS Code to use tabs instead of spaces for indentation. (<code>"editor.insertSpaces": false</code>)</li>
<li class="">Use the indentation space specified by the <code>tabSize</code> setting whose value should be specified by the programmer at the user level. (<code>"editor.indentSize": "tabSize"</code>)</li>
<li class="">Format the file when it is saved. (<code>"editor.formatOnSave": true</code>)</li>
<li class="">Use the Prettier formatter to format the file when saving. This is required for the above setting to have any effect. (<code>"editor.defaultFormatter": "esbenp.prettier-vscode"</code>)</li>
</ol>
<p>Other settings such as the <code>tabSize</code> (<code>"editor.tabSize": 2</code>) are not specified here because they are meant to be personal preferences.</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p>Now you may be wondering what is the significance of these settings if they are meant to be overridden during saving by Prettier? Fair point.</p><p>It is true that Prettier <em>will</em> change the indentation when the files are saved. These settings here help to keep the behaviour consistent so that there are minimum changes between when the programmer is editing the files and after they are saved.</p></div></div>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>My position on using tabs versus spaces for indentation has changed. With tabs, the programmer can choose how the tabs are actually represented. If he/she so chooses, the setting <code>editor.tabSize</code> can be changed to <code>4</code> (or <code>3</code> if you are crazy!).</p></div></div>
<p>For Next.js projects that are scaffolded using <code>npx create-next-app</code> there should be a file <em>.eslintrc.json</em> which contains the contents below:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "extends": "next/core-web-vitals"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre></div></div>
<p>I leave this untouched as the defaults have worked well for me.</p>
<p>What is most important is the use of the <a href="https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode" target="_blank" rel="noopener noreferrer" title="‌" class="">Prettier plugin</a> that performs the task of formatting the files before they are saved. The plugin can be configured using the <em>.prettierrc</em> file in the project.</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "useTabs": true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "printWidth": 80,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "singleQuote": true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "trailingComma": "es5",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "semi": true</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre></div></div>
<p>These settings are applied when the files are saved in VS Code:</p>
<ol>
<li class="">Use tabs to indent the lines of code. (<code>"useTabs": true</code>)</li>
<li class="">Wrap the line if there are more than 80 characters in the line. (<code>"printWidth": 80</code>)</li>
<li class="">Use single quotes where possible. (<code>"singleQuote": true</code>)</li>
<li class="">Apply a trailing comma in the style ECMAScript 5, which means commas are added to the last line in a multi-line JSON definition. (<code>"trailingComma": "es5"</code>)</li>
<li class="">Always place a semicolon at the end of a statement. (I'm old school that way) (<code>"semi": true</code>)</li>
</ol>
<p>These configurations might seem trivial but they go a long way in ensuring that code review is not unnecessary hampered by redundant changes such as tabs being replaced with spaces. Take a look below:</p>
<p><img decoding="async" loading="lazy" alt="example of a diff of spaces and tabs" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAYUAAAD2CAYAAAA54puTAAAABHNCSVQICAgIfAhkiAAAABl0RVh0U29mdHdhcmUAZ25vbWUtc2NyZWVuc2hvdO8Dvz4AAAApdEVYdENyZWF0aW9uIFRpbWUARnJpIDI5IE1hciAyMDI0IDEwOjUxOjU4IEFNE+yrAwAAIABJREFUeJzt3Wd8FOUaBfCzm7LpvZGQQgihg6GpFAkIiFIkAgoIIgKCIkWkiYWOBeHqBUSKiDSxQIKCBlSIRFREioj0HtJ727TNzv0QMzfBbMrubHY2Of8v6mzyvk/UHyczsztHIQiCgApu3UmEn68XGqr4hBRY+tmaegwiIllSmnoAIiKSD0tTD2AKTS1cTD0CEZEs8UyBiIhEDAUiIhIxFIiISMRQICIiEUOBiIhEBr37KPa3PxF95ARWLHweAHDtVjw2bN0nvp5fUIgnBvXGgPBuhk1ZxV4AcDjmdxyJPQ2lUomRQ8MR1j7U4H2IiBozvUJBqxWwcft+JCWnQav9/2ffQoL8sHrpdABAdm4+Vr6/Hfd3amPQgLr2SkhKw5HY01g0dwLU6kKs/O9OtAoJhK2tyqD9iIgaM70uHymVCoR3D8P0SSN0fs233/+KXg90hLOTg97DVbdXXHwygoOawNZGBXc3ZzT18cDNuESD9iIiauz0vqfQOjQQCqWiytcKCovwx5+X0KdHJ70Hq2kvby933LqThILCImi1AiwslFDnF0qyHxFRY2WUTzSfPncZLUMCYG9nY4zlAQBB/j7o3q093np/BywslUhLz8aAPvcbbT8iosbAKKFw9u9reMDAewm1Mbh/dwzu3x05ufl47a1NCPL3MfqeREQNmVHeknrtxl0EB/oaY+l/SUhOx/qte9H/oa6wUVnXy55ERA2V3mcKm3bsx+VrccjNy8ecJevxwvgINA/yhbqgECUlGri6OEk2pK69Xlm0Dk4OdujdIwzh3cMk24+IqLFSNMY+haCAJqYeg4hIlviJZiIiEjEUiIhIxFAgIiIRQ4GIiEQMBSIiEjXKjmak8RlJRERV4ZkCERGJGApERCRiKBARkYihQEREIoYCSS7m5AX0fGYRwicsQVJalqnHIaI6kLSjGQCOHj+Nw0dPAgD69gpD/96G9zNT3V1PKcK7BxOxYHATNPOs34rSrZFH8fas0ejZqVW97ktEhtPrTEGrFbBhWxR++Olkpd7krKxcHDryO96c8yzefOVZfP/TH8jMzJFsWKq9q0mF2HQ0BdkFpfW+d25+IVyc7Ot9XyIynF5nCuW9yZ7uzli94XPxeH5hERQKBVTW1lAqy/6qhVDNSlRbk7fexA/nc5CQVQxLpQIfPhuE8T09sP6HZKz8JhGFxVo89YAb1j0ThNm77+CDQ0kAgLDXzwMAZj7ig35tnTBkzRWcWd4OeYWl6LX8Io6+2grhrZ2qXL9ToB2eWn8dd9KL4GBjgVmP+GDB4No9YVapqLqqlYjkTe/LR61DA5GemV3pmJ+PB5r6eWL1h7vh5OSA+9qGwN3V2eAhCfjy9ww081RhYm8/FGm06OBvh2OXczFjx228PzYQ9iolXtx2Cz1aOGJqXy94Olri9a/uYv34IAR7qhDkqcK1ZN0d1lWtn56nwcWEArzxuC+uJBVi4ZdxGPOgOwLcdZcZlZRokJCaAW93/ncnMkeS3mjWaEpRVFiMTh1bwlalwp9/X0NhUbGUW9SbQ8f/hF/fF+DX9wUcOv6nqccBAPRu5YTXH/fFsuFNERZoh4NnsyAAeGPvXczefQclpQLO3lGjVRMbdA4qu3zTvYUDBnZwRqsmNfdl37t+uQHtnfHyQB8IAnA5sUDn9xcWlaDbmNfRtrk/3F0cDf55iaj+SfqYi3MXrkFlY42He3UBAKzfug/nL9xAlzDzu+H4SI+OiD+ywdRjVEtTKkBlqcTJxW1hZVl2ucbJ1gIAUH71pmKFkvU/X1NYrK3zXiqrst8fijS6LwfaqKxwYvdy9Bq/CBnZeXBzdqjzPkRkWpKeKahUKuTk5EGjKYVGU4rsnDzYO9hKuQVVMKC9MwpLtJizJw5HL+Rgc0wqyq/kuzuU5f3GIynYcTwNh89no4W3DRQKYE10EqLPZete2ADWVpbw9XTjW1GJzJSkHc1tWwbh/MUbeOPtLdAKWnRqH4rWLQKlnJcqeKS9Mz6aEITV3yXh0Lks+LpaY0IvD7jaW6JLM3uMedAd22JT8dlv6Vg4xBcD2jljyRNNsepgIg6ezUJbP1t4OFoZZTatwDcYEJmjxtnRbFfz15H+xr26HlOf7IceYS1NPQoR1RE/0UySmxARjlc/+Az9Ji3nZSQiM8MzBSIiEvFMgYiIRAwFIiISMRSIiEjEUCAiIhFDgYiIRAwFIiISMRSIiEjEUCAiIhFDgRo8dkYT1Z7kHc2HY37HkdjTUCqVGDk0HGHtQw0eksgQ7Iwmqj29QkGrFbBx+34kJadV6mhOSErDkdjTWDR3AtTqQqz87060CgmErW39FscTVcTOaKLak7SjOS4+GcFBTWBro4KtjQpNfTxwMy4RbUKDpJqXZCA5PRvDX16DzJx82NlYY/YzgzD6sR4AgLW7o7HzQCxy8wuhUCjwzbp5CG7qhU+/Poa1u6KhUAAzxz6KsYN7VbvOf3Z8i50HYiEIAkL8ffDF6lni/lOWbkZpqRZblkyp9czsjCaqHUk7mr293HEr+mcUFBZBZW0NCwsl1Pm6e4HJPKkLiyAIAv6Oeg9xSekY+tK76NgyEG2aN8UvZ65g0Qsj8FivMGi1AhQK4ML1u1i3OxrffbQAWq2AQS++g85tgmGjsqpyneCm3li7Kxrno1bBzkaF3Hv+H7K3VVU6Q60OO6OJ6kbSG81B/j7o3q093np/B5at+QRXb9yFg6N5PpJUjh3NcuTv445BvTvh5zOXxWMOdmV90EqlAgqFArGnL+HRnvfB09UJ3u7OeLTXfYg9fUnnOjYqK/Tt1hZj5q/FgWOnYX/P5cc1c5/B+/PH1zgbO6OJ6k7SjmYAGNy/Owb3746c3Hy89tYmBPn7SL1FvTCHjma5UCgUKC2te+9zdetsWToFv5y9gm37f8LmL39E5AdzoFTW7RIQO6OJ6s4ob0lNSE7H+q170f+hrrBRWRtjCzIxdUERsvPUSM3MQfTPZ/FAhxY6v7ZXp1b47uezSMnIQVJaFr6LPYte/7wTqKp1NKVaXI9LRvf7QrH+tedwJzENd5LSxPVeWbUDs1dtr9Wc7IwmqhtJO5qbB/nilUXr4ORgh949whDePUzKWUlGctWF6DtxGYqLNZg8oi/CWgfp/No2zZti2qgBeOT5FQCA2eMHo3WwH27Gp1S5TmpmDia++RHSs/JgbW2JQb07IbCJh7heTn4BhFreUyjHzmii2mHzGtXZzfgUjF2wDsd3LJXFOjVhZzRR7fETzdTgsTOaqPZ4pkBERCKeKRARkYihQEREIoYCERGJGApERCRiKBARkYihQEREIoYCERGJGApERCRiKFCD8W3sGXQdtRBhIxfgzXVf4NvYMwgbMR/+/afhxF/X9F43PSsXC97/TMJJieRLrwfiqQsKsePLQ7h45Rasra0wckgfdA1rDQD448wl7In6AQKAUcMeFo8TGduC/+zGV2tmIzSoCdIyc+Hh6ojHeoUhYuZqg9bNyS9A7KmLEk1JJG96hYJCoUCblkGYPHYobsUl4oNNX6BrWGsUFZdgd+T3mDNtDARBwOoPP0OHtiFQWVtJPTdRJfkFRSgq1iA0qAkAwMOVpTpE+tArFGxtVOh1f0cAgK+PB0o0pRAEAZeu3kaQvw98vd0BAAF+Xrh09TY6tg2RbmKie5y6cAOTF29CrroAXZ5aCAD46j8vI8jXU+f3LPxgD6KPn4UgAM8+3hszxz4KQHc3dFxSOjo8MRcWFhZ4ZfwgjB3cy/g/GJEJGNy8dvD7X9Cja3soFApkZufCzdUZUd8eQ0mJBu6uLsjMzpViTiKdOrcJxtGtb+KBMa/jj89X1up7lk9/CitnjkJOfgEeGr8YYwb1gKOdrc5uaF9PV/yycxnuJqej36TleKJfN9jZqKrZgcg8GXSjOeb4aZy/dAMjhvYpO/DPA1dDgv0RGhIAAWXF7eaIHc0N2+a9P6L3s0vw+PRVyMkrQEpGTrXd0BYWSiiVCgQ08UATT1fEJ2eYcHoi49H7TOH8pZs4HHMS82eMFe8ZuLo44dyF62jXqhkA4OjPp8z20hE7mhsOpVKBik+Iv3gjHlsjjyL6o4VwdbLHwKlvia9X1Q19L5W1FYpKNPU2P1F90utMQRAE7PzqEKY+OwzOjvbi8VYtAnErLgkJSWmIT0zFnfgUtGoRKNmwRPrwcHXEjbgUlGq1UBcWQaMphbWVFVTWZb8TKf85na2pG1qXXQd/Rocn5iJPXVjj1xLJnV5nCumZ2UjPyMJ/t3wlHhs3fAA6tmuB0RH9sHrDHkAQMDqiH995RCb3XEQfTF26Bcs37cNHb05Cr06t0KdrG3Qb/RqsLC1haaGEnY0KmTl5VXZD30pIrXZ9F0d7ZObkIyUjBw52NvX0UxEZB5vXiAyQpy7Exi9/wJmLt7Dz7ZdMPQ6RwfiJZiIDaAUBPh4u+GTZVFOPQiQJg9+SStSYOdnb4ulBPU09BpFkeKZAREQihgIREYkYCkREJGIoEBGRiKFAREQihgIREYkYCkREJGIoEBGRiKFAdZaUloXwCUvQ85lFiDl5wdTjEJGEJO9oBoDY3/5E9JETWLHweckGJfnw8XBBzCeLcOzURWzZewThXduYeiQikoikHc1arYCN2/cjKTkNWq1Q80Jk1tycHSq1kxGR+dPr8lF5R7NSqajU0axUKhDePQzTJ42Qek6SIYW51uoRkU4G31Oo2NEMAK1DA6FQ8g+LxsDH3RmJqZko0ZSaehQikoi0Hc0NCDuaa+bu4ohWzXxx/5jXUFhUYupxiEgCknY0NyTsaK5ZWmYuLt9KxIndK2BlaWHqcYhIApJ2NFPjkpyRDR8Pl38FAjuLicyX5B3Nm3bsx+VrccjNy8ecJevxwvgINA/ylWxgko97mlxF7CwmMl96hYKHmws2r1lQ5WvPj3vcoIHIfGTnqv/1h36euhCXbsajd5c2CG7acLu+iRoq1nFSnSWlZWHsgnUo1miw+MWRlV5jZzGReVMI91wDuHUnEX6+Dfc3vPiEFATZmXoKIiJ54rOPiIhIxFAgIiIRQ4GIiEQMBSIiEjEUiIhIxFAgIiIRQ4GIiEQMBSIiEjEUzAA7kYmovkja0VxTdzPph53IRFRfJO1o1nWcpMFOZCIyNkk7mnUdJ2no6kSesnQzJi3aWM/TEFFDZPBTUu/taK7pOOmvYidyxWIbe1sVtFqGLxEZzigdzQ2hu1mOHc26OpHXzH0G788fb8LJiKihkLyjuaF0N8uxo1lXJ7IgCBAEQKnkWRkRGUbSjmZ2NxuXrk7ksa+uw9Pz15poKiJqSCTtaPbz9dTZ3UyG03XTvmWQLw7/cq6epyGihkjyjmZdx8lwVXUiX7qZgIvX4zHj6UdNNBURNSTsaDYD1XUiA8C854YirHVQ/Q9GRA0OO5qJiEjEZx8REZGIoUBERCKGAhERiRrljea7rramHoGISJZ4pkBERCKGAhERiRgKREQkYigQEZGIoUC19tuv5zFi2Hw8NXwhUlMzTT0OERmB7N99VF3v8x9nLmFP1A8QAIwa9nCjqP68nViADfviMG1EAPy9bWr+Bgl98dn3mL9wPLp2Y0c0UUMl+1DQ1ftcVFyC3ZHfY860MRAEAas//Awd2oaYdYdDbdxMKMCu6ESMe9S33vfOyy+As7NDve9LRPVH9qFQ3vsMoFLv86WrtxHk7wNfb3cAQICfFy5dvY2ObUMk23v3zkMAgDFjH5FszXvNW3sFsWczkZxRBEsLBVa8EIqRD3vj04MJWPvFbRSVaDGklxeWT22BpVuu4eOv4wEAA2eeAgBMHOqHnve5YsLS84j+oDPUhaV4Yv5ZfLGyIx5s71Ll+u2bO+DFdy8gPrUIdjYWmPS4H6aNCKjVvKxXJWrYZB8KFVXsfc7MzoWbqzOivj2GkhIN3F1dkJmda+oR6+zA8VQEeNtg9AAfFJUIaN3MHifOZ+PNjVexeHII7GwssHDDVXRt7Yyxj/rC3dka7+64iRUvtECAtw2aetvgVmJBndbPzC3B1Tg1Zo4KxI14Nd7ZfhPDenvDz1Olc52SEg2SkzLg4elijH8NRCQTZhMK5b3PC2aMKzvwz8NdQ4L9UVpaij//vgapfomN3BuDrZu/Rn5+2R+2n+08hOcmD0XE8HBpNrjHA+2cMeOpQPGfV267AQHAql23AAAajRZ/38hDRLgX2jcvu3zTuZUT2gaX/X11oVDV+r/+lQUA6B3mioe7uOGb2FTciFfrDIWiomJEDJmHtm2bwdXVUd8fk4jMgFmEQlW9z64uTjh34TratWoGADj68ynJLh1FDA9HxPDwerl8VBVNqQBrKyUOrukEK8uypHOwLftPVR58FZ93bm1Z9iayohJtnfeytqr5e1Uqa0QdeA8jIxYgKysXLi4MBqKGSvZvSdXV+9yqRSBuxSUhISkN8YmpuBOfglYtAqtZyXz0DnNFUbEWy7Zexy/nsrD7UKIYBq5OZaG467sE7D2ajGNnMtHM1xYKBbA56i6OnsowykzW1pbw9nFDakqWUdYnInmQ/ZmCrj7oju1aYHREP6zesAcQBIyO6Cf5O4/atguWdL3a6t3JDW9NC8WmyDi8evoqvN2s8WQ/Hzg7WKJDiCOG9fbCFz8mI+pYCqaPDMRDYa54ZUwQPtoXhx9PCggNsIebk3HehaWrJ5qIGoZG2bxm6cenpOrj5elr8PQzj6JL14b/eRCixkr2l49IPkaO6od3V27HmCff4CeaiRoonikQEZGIZwpERCRiKBARkYihQEREIoYCERGJGApERCRiKBARkYihQEREIoYCERGJGApkNOx0JjI/sn8gXnUdzQAQ+9ufiD5yAisWPm/CKakq7HQmMj+yDwVdHc1arYCN2/cjKTkNWi2f3ClH7HQmMj+yDwVdHc1KpQLh3cPg6e6M1Rs+N8repirZ0SUtLQtTJ72F7Kw82NqqMGnKMAwd9hAAYNvWA4jcG4P8vAIoFMDH299AQIAP9n55BNs+PgCFApgwqaw9rrp1Pt60H5H7YiAIAgKDmuDDjfPF/RfOW49SrRbvvDe91jOz05nIvMg+FCqq2NEMAK1DA5GemW3iqepPQUERtFoB38esR0JCGiaNX4bWbZqhRag/Tp28iFmvjEafvp2h1QpQKICrV+Lw6dYD+HTXImgFARPGLkX7Ds2hsrGucp2AQG9s23oAh4+ug62tSqwjLWdrZ1PrPgV2OhOZJ7O50Vze0TxiaB+j7xW5NwZDBs7Glo1R2LIxCkMGzkbk3hij71sb5YHo6+uBvv264uTvF8TX7O1sAABKpQIKhQInT/yN8L6d4ebuDA8PF4T37YzfT1zQuY5KZY0He3TAzGnv4cgPJ2Fra1Np7zcWT8SbSybVOGNRUTEeHzQHoaH+7HQmMjNmcaZQVUezMZm6o7m2FAoFtNq69zJXt867q6fj1B8X8dXnR7B75yFs2voalMq6XQJipzOR+ZL9mYKujubGqkBdiNxcNTLSs/HT0VMI69RS59d2vb8tYo6cQnpaNlJTMxFz5BS63d9G5zqlpaW4czsJnbu0xrK3piIhPhUJ8aniesuXbMWyxR/Xak52OhOZJ9mfKVTX0bxpx35cvhaH3Lx8zFmyHi+Mj0DzIF/J9jZVR3N18vILMHrkaygu1mD00wOqnbFFqD/GPTsI40a/CQCYNGUYQlr4Iy4uucp1MtKzMXf2f5GZmQtra0v07dcVfk09/793nrrO7/RipzOReWHzmhmJi0vGrJfWYO/+d2SxTk3Y6UxkfmR/+YjMFzudicwPzxSIiEjEMwUiIhIxFIiISMRQICIiEUOBiIhEDAUiIhIxFIiISMRQICIiEUOBiIhEDIVG4OiRUxj66Gw8NmAW1qzahaNHTuGx/jPxYJfncPbMFb3XzczMxTsrP5VwUiIyNdk/EE9XR3NN3c30f2+v2IYNmxcgONgPGRk5cHNzQp++nfH8xJUGrZuXpxb7GYioYZB9KOjqaNZ1nCpTqwtRXFSC4GA/AICbm5OJJyIiOZN9KOjqaNZ1XMpOYLmX7NTkr3PXsGDuOuTnF2DIwNkAgA2bF6Cpv+5nW7379g78dPQUBAEY8WRfPDdpKADd3c2JCal45OHpsLCwwOQpwxAxPNzoPxcRGY/sQ6Giezuaazre2LXvEII9X63EsMFz8E30mlp9z5x5YzFvwTjk5akxctirGBbRG/YOtjq7m7283bDv61VISkzDmCffwMDHHoStrcpYPxIRGZnZhEJ5R/OCGeNqddwQkXtjsHXz1+Iffp/tPITnJg9tFL8F79l1CFGRP0GpVCIvT420tGy4uTuL3c2jxgxAeN8u4tdbWFhAqVTA188TXt6uSEpMR7Ng6YqOiKh+mUUo6OpoNlZ3s7l0NBtKqVBUaka7djUOn+/5Adt3LYaziwOeGbNYfK2q7uZ7qVRWKCnR1MfoRGQksn9Lqq6OZnY3G87NzQl3bidBq9WioKAIGk0prK0tYa0qC1ilsuxyXE3dzbpE7YvBIw9Phzq/0Kg/BxFJR/ZnCro6mv18PXV2N0tFjh3NUnpydH8snP8h1r7/BVa+8yK63t8GD3Zvj8cfewWWVpawtFDCxtYa2Vl5VXY3372bUu36Ts4OyM7KQ1p6FgLsferppyIiQ7B5jYxCnV+IXTuj8fdfN/D+utmmHoeIakn2l4/IPGkFLTw9XbDqPzNMPQoR1YHsLx+ReXJwsMOwJ8JNPQYR1RHPFIiISMRQICIiEUOBiIhEDAUiIhIxFIiISMRQICIiEUOBiIhEDAUiIhIxFMxIamomnhq+ECOGzcdvv5439ThE1ADJ/hPNurqYNaWl2LAtCjdvJ8DS0qJRdDR7erri870r8ftvf2PP7sN44MF2ph6JiBoY2YeCri5mSwsLjBwSDm9Pd1y/FY8PP9nX4EOhnIurI/IqtJ8REUlF9qFQXRezj5c7gLKzCVdnR8n3buglO0RE95J9KFRUVRfzays3ISUtAy9NHGHCyeqXp5crUpIzoNGUwtLSwtTjEFEDYjY3msu7mEcM7VPp+IqFz2PutKexbc+3yMnNl2SvyL0xGDJwNrZsjMKWjVEYMnA2IvfGSLK2FFxdHdE8pCkeH/QKioqKTT0OETUgZnGmUFMXc2hzf/h6uyM+KQ1OElRzyr2jOSMjBzeux2P/wdU8UyAiScn+TEFXF3NxcQmys3MBAMmpGUhMyUATTzdTjVmv0lKz4Onl+q9AYCcyERlK9mcKujqavb3dsG7zPuTmq+Fob4dRw/rBxUXam83m1tHMTmQiMpTsQ8HDzQWb1yyo8rXlCycbde+O97Uw6vr6ysnJh72dTaVj6vxCXL92Fw882B4BAQwEItKP7EOB/i81NRMzp62BpkSDWXNGV3qNnchEJAWFIAhCxQO37iTCz9fLVPMYXXxCCiz9bE09BhGRLMn+RjMREdUfhgIREYkYCkREJGIoEBGRiKFAREQihgIREYkYCkREJGIoEBGRiKFgQuxcJiK5kf1jLnR1NFe0acd+qNWFmDXlKRNNqR92LhOR3Mg+FHR1NJf7MfYPpKZl/esBceaEnctEJBeyv3xU3tGsVCoqdTQDQEpaJv44ewkRg3obZe/dOw+JRTumsHDeesyfs9Zk+xNR4yP7M4WK7u1o/jzqR4yK6IfCQvOupNTVuWxrZ4N7nldIRGRUZhMK5R3NC2aMAwBcv5UAKytLBDb1weVrdyTdK3JvDLZu/hr5/1zS+WznITw3eSgihodLuk+5ip3L+75+FyqVNQDgjcUTjbIfEZEuZvHo7POXbmL33sOYP2OsWMn5dfTPOH7yL1hZWKJIUwJ1fgEe6XM/hg7sWe1adXl0dn11NGdk5GDi+GX4MvLtSmcKgiBAEAClUmHU/YmIysn+TKG8o/nFCRGVOpqHDuwpBsDla3fw3Y+/1hgIcqWrc3nW9DXQlmqxdsNcE01GRI2N7ENBV0dzx3bGr8o0dUdz8+Z+OPbTGZPOQESNi+xDobqO5nItQwLQMiRA8r3rq6O5qs7l69fu4uqVOEyYOKReZiAiAswgFBqy6jqXAWDqtOEmP1shosbFLG40S4kdzUREusn+w2tERFR/GApERCRiKBARkahR3mhuauFi6hGIiGSJZwpERCRiKBARkYihQEREIoYCERGJGAoSSkrJQHjEdPQc8iJifuEzi4jI/Oj17iNdvcma0lJs2BaFm7cTYGlpUWWfslR7AcDXh37GkdhTYv/A6y+Ph6ODnUH7GcLHyw0xkWtx7Nc/sWXXNwjvHmayWYiI9KFXKOjqTba0sMDIIeHw9nTH9Vvx+PCTfQaHQnUdzUVFJRjzxAB062TYHlJzc3VEbp7a1GMQEdWZXpePqutN9vFyh0JR9hu+q7OjwQNWt1d+fgHs7eX3HKPyutB7TZmzCpNmv1PP0xAR1Z7BH167tzcZAF5buQkpaRl4aeIIQ5evdi8BwPYvvoObiyOGDuyF1i0CJd1PXz5ebkhMTkOJphRWFYpz7O1soGXnMhHJmEFPSY05fho//XoWC2aMg8raqtJrV67HYcO2SCyZNxFOFRrT9KVrL0EAzl+6ga27D2Dp/Ek13lOIT0hBUEATg+epybMzVuDchev45eBHsPnnngcRkdzp/e6j85du4nDMScya8tS/AgEAQpv7w9fbHfFJaQYNWNNeCgXQvnUwfL3dkSDBXlJIy8jG5Wt3cCJ6c6VAEAQBWi3PFIhIvvQKhfLe5KnPDqvUm1xcXILs7FwAQHJqBhJTMtDE082gAXXtpdUKyMoq2ys1PRNJKRnwcpfHM42SUzPg4+Ve6dIRAIydtgxPv7DERFMREdVMr3sKunqTvb3dsG7zPuTmq+Fob4dRw/rBxcWwm8269goKaII1Gz9Hdk4+7GxtMGJIH7i6Ohm0l1QEHfcNWjYPwOGY3+t5GiKi2muUzWvGvqdw/Pe/8NGnUdix/g3x2KWrt7HDC6v6AAAAf0lEQVTkvU8QMeghPDm0r1H3JyLSV6N8dLaxJKVkYOyLS1FcUoLFcyf+6/V5L41BWPtQE0xGRFQ7PFMgIiIRn31EREQihgIREYkYCkREJGIoEBGRiKFAREQihgIREYkaxecUCjXAj5cVOBOvQL7aGb1zgP6tAJtG8dMTEdXe/wBZq+aXn/AgPQAAAABJRU5ErkJggg==" width="389" height="246" class="img_ev3q"></p>
<p>This diff essentially has no differences between the changes except that one is indented by spaces (new) and one is indented by tabs (old).</p>
<p>Now imagine this expanded to multiple files.</p>
<p>This is no exaggeration. I was a consultant to a project team for a while. They had hired a remote developer who was maintaining a legacy Java codebase.</p>
<p>No one ever reviews the code made by the remote developer not because no one in the team could do it but because every commit involved thousands of lines of code across multiple files. This happened because there wasn't a lead who enforced coding conventions for the team. The thousands of lines of changes were mostly a change in the indentation characters. 🤦 As a result, no one in the team knew what changes the remote developer had made.</p>
<p>This experience further consolidated my view that coding conventions are not a nice-to-have but a must-have for a team.</p>
<p>One last thing to note, the changes made by Prettier as specified in <em>.pretterrc</em> are enforced when the programmer saves the file in VS Code itself that has the Prettier formatter. I thought this was obvious, but sometimes the obvious bears repeating.</p>]]></content:encoded>
            <category>programming</category>
            <category>developer setup</category>
            <category>coding conventions</category>
        </item>
        <item>
            <title><![CDATA[Writing Git commit messages]]></title>
            <link>https://www.cheehow.dev/blog/2024/03/15/making-a-commit/</link>
            <guid>https://www.cheehow.dev/blog/2024/03/15/making-a-commit/</guid>
            <pubDate>Fri, 15 Mar 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[A highly opinionated take on the approach to writing Git commit messages.]]></description>
            <content:encoded><![CDATA[<p>In a <a class="" href="https://www.cheehow.dev/blog/2024/02/24/git-branching-strategy/">previous article</a> I wrote about my Git branching strategy for small teams. In this one, I will look at the topic of writing commit messages. This is also a highly opinionated take, just like the previous article.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="writing-a-commit-message">Writing a commit message<a href="https://www.cheehow.dev/blog/2024/03/15/making-a-commit/#writing-a-commit-message" class="hash-link" aria-label="Direct link to Writing a commit message" title="Direct link to Writing a commit message" translate="no">​</a></h2>
<p>Every commit should have one main theme - one main purpose for why the change was made.</p>
<p>This should be made clear by the first sentence in the commit message.</p>
<p>The first sentence should be separated from the rest of the message with an empty line.</p>
<p>The body of the commit message should be written in point form, denoted by a dash at the first of the line. (Remember that the purpose of the message is for sending a clear message, not for writing essays.)</p>
<p>Each point should be written as a full sentence, properly punctuated. Why? The purpose of punctuation rules is to facilitate clear written communication. What’s the use of having (punctuation) rules if nobody follows them?</p>
<p>A useful tip to remember is that the project lead should understand from the commit message what changes are included in the commit without having to look at the code. The code should only be looked at if the lead wants to review the correctness of the code, not for trying to understand the purpose and scope of the commit.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="example">Example<a href="https://www.cheehow.dev/blog/2024/03/15/making-a-commit/#example" class="hash-link" aria-label="Direct link to Example" title="Direct link to Example" translate="no">​</a></h3>
<p>Here is an example of the type of commit message that I think is good:</p>
<div class="language-markdown codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Written in the active voice 👍</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-markdown codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">Added the user avatar next to the comment.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token list punctuation" style="color:#393A34">-</span><span class="token plain"> Modified the user API payload to return the avatar URL.</span><br></span></code></pre></div></div>
<p>Since the commit message is supposed to describe what was done, it should be written in the past tense.</p>
<p>For consistency, my preference is to have the message written in the active voice. Below is an example of the same message written in the passive voice.</p>
<div class="language-markdown codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Written in the passive voice 👎</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-markdown codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">User avatar added.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token list punctuation" style="color:#393A34">-</span><span class="token plain"> User API payload modified to return the avatar URL.</span><br></span></code></pre></div></div>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p>I’m being pedantic here really. This is just a preference for consistency more than anything else.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-not-to-write">What not to write<a href="https://www.cheehow.dev/blog/2024/03/15/making-a-commit/#what-not-to-write" class="hash-link" aria-label="Direct link to What not to write" title="Direct link to What not to write" translate="no">​</a></h2>
<p>What is a definite no-no is to write something along the lines of</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">made code changes</span><br></span></code></pre></div></div>
<p>No sh*t genius!</p>
<p>This is just pure laziness and it makes my blood boil. <!-- -->😠<!-- --> A one-liner stating the obvious wastes the reviewer’s time and makes history traversal that much more difficult in the future.</p>
<p>Leaving the commit message empty is just as bad. It reflects the lack of care on the part of the programmer to think for the team or anyone else who will take over the code. (The grammar police in me is also triggered by the lack of a full-stop/period at the end of the sentence and the lowercase letter at the start.)</p>
<p>The other extreme - an extremely wordy write-up describing the commits - is also to be avoided. An overly detailed write-up defeats the purpose of the commit message, which is to summarise the key changes made in the commit.</p>
<p>If the reviewer wants more details, he/she should read the actual code changes.</p>
<p>Although this is to be avoided, it doesn't trigger me as much as an empty/redundant message because at least it shows that the programmer owns the work and puts in effort (albeit in the wrong direction).</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://www.cheehow.dev/blog/2024/03/15/making-a-commit/#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion" translate="no">​</a></h2>
<p>As mentioned, this is my highly opinionated take on the approach to writing commit messages. In the next article in the series, I’ll share a few useful, but not frequently used, Git commands.</p>]]></content:encoded>
            <category>programming</category>
            <category>git</category>
            <category>developer setup</category>
        </item>
        <item>
            <title><![CDATA[Git branching strategy]]></title>
            <link>https://www.cheehow.dev/blog/2024/02/24/git-branching-strategy/</link>
            <guid>https://www.cheehow.dev/blog/2024/02/24/git-branching-strategy/</guid>
            <pubDate>Sat, 24 Feb 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Simple Git branching strategy for small teams.]]></description>
            <content:encoded><![CDATA[<p>I'm preparing <a class="" href="https://www.cheehow.dev/blog/tags/developer-setup/">a set of materials</a> for a batch of interns whom I will be mentoring for a software development project.</p>
<p>One of the things that they will be doing is to check out an existing codebase to work on. To do that, they need to know Git.</p>
<p>I'm quite certain that the basics of checking in and out code is no problem for them if they have any Github profiles. However, every organization has its own conventions and requirements when it comes to maintenance of their codebases. This post documents my preferences in code maintenance.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="branching-strategy">Branching strategy<a href="https://www.cheehow.dev/blog/2024/02/24/git-branching-strategy/#branching-strategy" class="hash-link" aria-label="Direct link to Branching strategy" title="Direct link to Branching strategy" translate="no">​</a></h2>
<p>When taking on a new codebase, one of the first things to understand is the branching strategy used by the organization. A branching strategy isn't a Git command or function. Rather it is a set of conventions that determine the approach to handle code changes in terms of code releases, bug fixes and new feature development. The things to consider are the convention for creating and naming of new branches, and the guidelines for when and how to merge changes.</p>
<p>There are several popular ones out there:</p>
<ul>
<li class=""><a href="https://nvie.com/posts/a-successful-git-branching-model/" target="_blank" rel="noopener noreferrer" class="">GitFlow</a></li>
<li class=""><a href="https://docs.github.com/en/get-started/quickstart/github-flow" target="_blank" rel="noopener noreferrer" class="">GitHub Flow</a></li>
<li class=""><a href="https://docs.gitlab.com/ee/topics/gitlab_flow.html" target="_blank" rel="noopener noreferrer" class="">GitLab Flow</a></li>
</ul>
<p>One factor affecting the choice of strategy is the size of the team. The size of the team has a direct (but not necessarily proportional) bearing on the number of concurrent branches. It is important to be judicious about selecting the suitable strategy. Each strategy yields different benefits but also introduces additional overhead.</p>
<p>A strategy perfect for a team of hundreds is likely to be too onerous for a team of three.</p>
<p>Some of the strategies above are also outdated in the sense that they do not lend well to the modern strategies of continous integration/continuous deployment (CI/CD).</p>
<p>For a small team of less than five, here are my heuristics (Maybe I should call it <em>SimpleFlow</em> 🤔):</p>
<ul>
<li class="">A <code>production</code> branch should be branched off the <code>main</code> (or <code>master</code>) branch.</li>
<li class="">All releases are made on the <code>production</code> branch.</li>
<li class="">Each release should be accompanied by a tag.</li>
<li class="">This implies that the <code>main</code> branch contains the latest, tested changes.</li>
<li class="">Feature development should take place on branches based off the <code>main</code> branch - these are called <em>feature branches</em>.</li>
<li class="">Feature branches should rebase from the <code>main</code> branch frequently.</li>
<li class="">Feature branch should be <em>merged</em> back into the <code>main</code> branch when development is done.</li>
<li class="">Hotfixes should only be made on branches based off the <code>production</code> branch and merged back into <code>production</code> for release.</li>
</ul>
<p>By keeping all releases on the <code>production</code> branch only, any CI/CD pipeline can be honoured during deployment.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="example">Example<a href="https://www.cheehow.dev/blog/2024/02/24/git-branching-strategy/#example" class="hash-link" aria-label="Direct link to Example" title="Direct link to Example" translate="no">​</a></h3>
<p>Here is an example scenario:</p>
<p>Say Alice is tasked to create a new feature for users to select one of a few preset avatars. She checks out the codebase which defaults to the <code>main</code> branch.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> checkout git@github.com:coy-project</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token builtin class-name">cd</span><span class="token plain"> coy-project</span><br></span></code></pre></div></div>
<p>She then creates a new branch <code>preset-avatar</code>.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> checkout </span><span class="token parameter variable" style="color:#36acaa">-b</span><span class="token plain"> preset-avatar</span><br></span></code></pre></div></div>
<p>She starts work in this branch.</p>
<p>Halfway through her work, she receives instructions to investigate a reported bug in the production system. She stashes any outstanding work in her branch before switching to the <code>production</code> branch to start investigation work. She creates a new branch <code>hotfix-broken-image</code> to start her code changes. (Before creating the new branch, she should make sure to have the latest commits from <code>production</code> as well.)</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># In `preset-avatar` branch.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> stash </span><span class="token comment" style="color:#999988;font-style:italic"># Put her current work away.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> checkout production</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> pull</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> checkout </span><span class="token parameter variable" style="color:#36acaa">-b</span><span class="token plain"> hotfix-broken-image</span><br></span></code></pre></div></div>
<p>She makes the necessary code changes to fix the bug. Then she commits the code to the hotfix branch. Before she makes a pull request (PR) to the <code>production</code> branch, she pulls in the changes one last time. There should <em>not</em> be any more changes to production in this scenario, but edge cases can occur.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> commit </span><span class="token parameter variable" style="color:#36acaa">-m</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Fixed broken link to image."</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> checkout production</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> pull</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> checkout hotfix-broken-image</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> rebase production </span><span class="token comment" style="color:#999988;font-style:italic"># Only if there are new changes from `git pull`</span><br></span></code></pre></div></div>
<p>The project lead will review the changes. Notice there isn't a command for PRs. PRs are artefacts of the centralised service (i.e. the likes of Github and Gitlab) that provides the centralised Git service - they're not part of the core Git functionality.</p>
<p>After the changes are approved, she will merge the changes into the <code>production</code> branch. In some cases, changes to the <code>production</code> branch are restricted to project leads, so only the project leads can merge the pull request.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> checkout production</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> merge hotfix-broken-image</span><br></span></code></pre></div></div>
<p>Regardless of who merges the hotfix into the <code>production</code> branch, Alice goes back to continue to her work on the <code>preset-avatar</code> branch by restoring the changes that she had stashed away earlier.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> checkout preset-avatar</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> stash pop </span><span class="token comment" style="color:#999988;font-style:italic"># Restore the work she previously put away.</span><br></span></code></pre></div></div>
<p>From this point on, she continues her work.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="identity">Identity<a href="https://www.cheehow.dev/blog/2024/02/24/git-branching-strategy/#identity" class="hash-link" aria-label="Direct link to Identity" title="Direct link to Identity" translate="no">​</a></h3>
<p>One other thing that I require collborators to do is to set the name and email of the Git identity that is registered in the Git history.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> config user.name </span><span class="token string" style="color:#e3116c">"&lt;Your name here&gt;"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> config user.email </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">your@email.com</span><span class="token operator" style="color:#393A34">&gt;</span><br></span></code></pre></div></div>
<p>This is so that the Git history reflects clearly who made which commits.</p>
<p>I want to avoid entries that look like this when I run <code>git log</code>:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">commit 012bf3d06e6f707a23b1786c9bd94f59f851d576</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Author: juju &lt;ilovejuju@MacBook-Air.local&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Date:   Thu Jul 7 08:48:16 2022 +0800</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    made code changes</span><br></span></code></pre></div></div>
<p>The name and email should be the formal identity registered with the company.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://www.cheehow.dev/blog/2024/02/24/git-branching-strategy/#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion" translate="no">​</a></h2>
<p>This article covers the high-level, strategic approach that I've used for small projects.</p>
<p>The <a class="" href="https://www.cheehow.dev/blog/2024/03/15/making-a-commit/">next few articles</a> will cover the more strategic, tactical uses of Git.</p>]]></content:encoded>
            <category>programming</category>
            <category>git</category>
            <category>branching</category>
            <category>developer setup</category>
        </item>
        <item>
            <title><![CDATA[Node.js error code `ERR_OSSL_EVP_UNSUPPORTED`]]></title>
            <link>https://www.cheehow.dev/blog/2024/02/12/nodejs-error-code-err_ossl_evp_unsupported/</link>
            <guid>https://www.cheehow.dev/blog/2024/02/12/nodejs-error-code-err_ossl_evp_unsupported/</guid>
            <pubDate>Mon, 12 Feb 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[How to fix the error message in Node.js "ERR_OSSL_EVP_UNSUPPORTED"/"Error: error:0308010C:digital envelope routines::unsupported". ]]></description>
            <content:encoded><![CDATA[<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="tldr">TL;DR<a href="https://www.cheehow.dev/blog/2024/02/12/nodejs-error-code-err_ossl_evp_unsupported/#tldr" class="hash-link" aria-label="Direct link to TL;DR" title="Direct link to TL;DR" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="problem">Problem<a href="https://www.cheehow.dev/blog/2024/02/12/nodejs-error-code-err_ossl_evp_unsupported/#problem" class="hash-link" aria-label="Direct link to Problem" title="Direct link to Problem" translate="no">​</a></h4>
<p>Error in Node.js output</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">Error: error:0308010C:digital envelope routines::unsupported</span><br></span></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="easiest-solution">Easiest solution<a href="https://www.cheehow.dev/blog/2024/02/12/nodejs-error-code-err_ossl_evp_unsupported/#easiest-solution" class="hash-link" aria-label="Direct link to Easiest solution" title="Direct link to Easiest solution" translate="no">​</a></h4>
<p>Create a <em>.npmrc</em> file in the root of the project (same location as your <em>package.json</em> file) with following contents:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">node-options="--openssl-legacy-provider"</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-problem">The problem<a href="https://www.cheehow.dev/blog/2024/02/12/nodejs-error-code-err_ossl_evp_unsupported/#the-problem" class="hash-link" aria-label="Direct link to The problem" title="Direct link to The problem" translate="no">​</a></h2>
<p>This problem typically occurs in projects that were developed with Node.js version 16 and earlier, <strong>and</strong> then run in version 17 or later. It is a result of <a href="https://github.com/nodejs/node/blob/main/doc/changelogs/CHANGELOG_V17.md#17.0.0" target="_blank" rel="noopener noreferrer" class="">Node.js version 17 using OpenSSL 3.0</a>.</p>
<p>The problem has to do with deprecated SSL connection options in Node.js versions 17 or later.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-solution">The solution<a href="https://www.cheehow.dev/blog/2024/02/12/nodejs-error-code-err_ossl_evp_unsupported/#the-solution" class="hash-link" aria-label="Direct link to The solution" title="Direct link to The solution" translate="no">​</a></h2>
<p>There are several solutions to this issue.</p>
<p>Like many computer problems, there is the quick fix solution that "solves" the problem by making the error message go away (treating the symptom), and there is the "correct" solution that addresses the root cause (treating the root cause).</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-quickfix">The quickfix<a href="https://www.cheehow.dev/blog/2024/02/12/nodejs-error-code-err_ossl_evp_unsupported/#the-quickfix" class="hash-link" aria-label="Direct link to The quickfix" title="Direct link to The quickfix" translate="no">​</a></h3>
<p>This solution makes the problem go away by telling Node not to reject the weaker connection.</p>
<p>This is done by setting the environment variable like so:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token builtin class-name">export</span><span class="token plain"> </span><span class="token assign-left variable" style="color:#36acaa">NODE_OPTIONS</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">--openssl-legacy-provider</span><br></span></code></pre></div></div>
<p>As an alternative, the environment variable can be specified as a prefix to the <code>npm</code> command:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token assign-left variable" style="color:#36acaa">NODE_OPTIONS</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">--openssl-legacy-provider </span><span class="token function" style="color:#d73a49">npm</span><span class="token plain"> run dev</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-permanent-quickfix">The "permanent" quickfix<a href="https://www.cheehow.dev/blog/2024/02/12/nodejs-error-code-err_ossl_evp_unsupported/#the-permanent-quickfix" class="hash-link" aria-label="Direct link to The &quot;permanent&quot; quickfix" title="Direct link to The &quot;permanent&quot; quickfix" translate="no">​</a></h3>
<p>One nifty alternative is to create a <em>.npmrc</em> file with the following contents:</p>
<p>I like this option because this file can be committed into version control and solve the problem "permanently".</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-right-solution">The right solution<a href="https://www.cheehow.dev/blog/2024/02/12/nodejs-error-code-err_ossl_evp_unsupported/#the-right-solution" class="hash-link" aria-label="Direct link to The right solution" title="Direct link to The right solution" translate="no">​</a></h3>
<p>The "right" solution is to update the application or packages. The error occurs because the application or a module in the application is using an algorithm or key that is not supported by OpenSSL 3.0 by default.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="caveats">Caveats<a href="https://www.cheehow.dev/blog/2024/02/12/nodejs-error-code-err_ossl_evp_unsupported/#caveats" class="hash-link" aria-label="Direct link to Caveats" title="Direct link to Caveats" translate="no">​</a></h3>
<p>The main issue with the quick fix solution is that it overrides the stronger security safeguards imposed by newer versions of Node.js</p>
<p>Normally this is a bad idea. However, there is a use case where this isn't a problem. And that is to generate static websites. For this use case, Node.js is only used to generate the static web pages (i.e. HTML, CSS and client-side JS) and not used in production. Thus, it is not a concern if it uses a weaker connection since it is never used in production.</p>
<p>A practical scenario is the use of <a href="https://nuxt.com/" target="_blank" rel="noopener noreferrer" class="">Nuxt</a> to generate static websites and then host the sites using a Web server like <a href="https://www.nginx.com/" target="_blank" rel="noopener noreferrer" class="">NGINX</a> or <a href="https://caddyserver.com/" target="_blank" rel="noopener noreferrer" class="">Caddy Web Server</a>.</p>]]></content:encoded>
            <category>nodejs</category>
            <category>ssl</category>
        </item>
        <item>
            <title><![CDATA[TypeScript object types with optional and minimally required properties]]></title>
            <link>https://www.cheehow.dev/blog/2023/10/28/typescript-object-types-with-optional-and-minimally-required-properties/</link>
            <guid>https://www.cheehow.dev/blog/2023/10/28/typescript-object-types-with-optional-and-minimally-required-properties/</guid>
            <pubDate>Sat, 28 Oct 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[How to create an object type in TypeScript with optional properties that has at least one required property. ]]></description>
            <content:encoded><![CDATA[<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="tldr">TL;DR<a href="https://www.cheehow.dev/blog/2023/10/28/typescript-object-types-with-optional-and-minimally-required-properties/#tldr" class="hash-link" aria-label="Direct link to TL;DR" title="Direct link to TL;DR" translate="no">​</a></h3>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// Solution 1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">LabelEntry</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> label</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">ImageEntry</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> image</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">Entry</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> LabelEntry </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> ImageEntry</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Solution 2</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">Entry</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> Record</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token string" style="color:#e3116c">'label'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'image'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>An object type that I find myself creating very frequently is one that has one or all of several properties. For example, I can create an entry with a text label, one with an image, or one with both:</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> textEntry </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  label</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Fluffy cloud'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> imgEntry </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  image</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'cloud.jpg'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> bothEntry </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  label</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Fluffy cloud'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  image</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'cloud.jpg'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-problem">The problem<a href="https://www.cheehow.dev/blog/2023/10/28/typescript-object-types-with-optional-and-minimally-required-properties/#the-problem" class="hash-link" aria-label="Direct link to The problem" title="Direct link to The problem" translate="no">​</a></h2>
<p>Intuituively, I would declare the type for this kind of objects to be like this:</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">Entry</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  label</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  image</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>There's a problem with this type. You can see the problem in the next listing with <code>entry3</code>:</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> entry1</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Entry </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  label</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Fluffy cloud'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> entry2</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Entry </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  image</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'cloud.jpg'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> entry3</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Entry </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// We don't want to allow this to happen.</span><br></span></code></pre></div></div>
<p>With this type definition, <code>entry3</code> can be assigned an empty object. This is <em>not</em> the outcome that we want.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="solution-1">Solution 1<a href="https://www.cheehow.dev/blog/2023/10/28/typescript-object-types-with-optional-and-minimally-required-properties/#solution-1" class="hash-link" aria-label="Direct link to Solution 1" title="Direct link to Solution 1" translate="no">​</a></h2>
<p>One solution to the problem is to create two types and create an <a href="https://www.typescriptlang.org/docs/handbook/2/objects.html#intersection-types" target="_blank" rel="noopener noreferrer" class="">intersection</a> type like so:</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">LabelEntry</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  label</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">ImageEntry</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  image</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">Entry</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> LabelEntry </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> ImageEntry</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>The <code>entry3</code> variable above will show an error <code>Type '{}' is not assignable to type 'Entry'.</code> because it contains an empty object.</p>
<p>Instead it must have either one (or both) <code>label</code> or <code>image</code> as its property.</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> entry1</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Entry </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  label</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Fluffy cloud'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> entry2</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Entry </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  image</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'cloud.jpg'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> entry3</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Entry </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">  label</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Fluffy cloud'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">  image</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'cloud.jpg'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="solution-2">Solution 2<a href="https://www.cheehow.dev/blog/2023/10/28/typescript-object-types-with-optional-and-minimally-required-properties/#solution-2" class="hash-link" aria-label="Direct link to Solution 2" title="Direct link to Solution 2" translate="no">​</a></h2>
<p>If coming up with names is not your strongest forte or you want to have fewer redundant lines of code, this might be your preferred solution:</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">Entry</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> Record</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token string" style="color:#e3116c">'label'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'image'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p><code>Record</code> is an utility type that helps to define the keys and values of an object type easily.</p>
<blockquote>
<p>P.S. A mistake that I made before was using union (<code>|</code>) instead of intersection (<code>&amp;</code>) for the key values (i.e. <code>Record&lt;'label' | 'image', string&gt;</code>). This would have made <code>entry1</code> and <code>entry2</code> invalid.</p>
</blockquote>]]></content:encoded>
            <category>knowledgebase</category>
            <category>typescript</category>
            <category>union</category>
            <category>intersection</category>
            <category>typing</category>
            <category>optional properties</category>
        </item>
        <item>
            <title><![CDATA[Auto-increment field with Prisma]]></title>
            <link>https://www.cheehow.dev/blog/2023/10/17/autoincrement-field-with-prisma/</link>
            <guid>https://www.cheehow.dev/blog/2023/10/17/autoincrement-field-with-prisma/</guid>
            <pubDate>Tue, 17 Oct 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[How to fix conflict with auto-increment ID field with Prisma and PostgreSQL ]]></description>
            <content:encoded><![CDATA[<p><img decoding="async" loading="lazy" alt="SELECT setval(pg_get_serial_sequence(&amp;#39;tablename&amp;#39;, &amp;#39;id&amp;#39;), coalesce(max(id)+1, 1), false) FROM &amp;quot;tablename&amp;quot;;" src="https://www.cheehow.dev/assets/images/hero-cbc6ebfbed7739a257077c1cad14cc27.png" width="1012" height="202" class="img_ev3q"></p>
<p>This post is a knowledgebase article on <a href="https://www.prisma.io/" target="_blank" rel="noopener noreferrer" class="">Prisma</a> with <a href="https://www.postgresql.org/" target="_blank" rel="noopener noreferrer" class="">PostgreSQL</a>.</p>
<p>The typical model in a Prisma schema has an <code>id</code> field that auto-increments:</p>
<div class="language-prisma codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-prisma codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">model User {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  id Int @id @default(autoincrement())</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  name String</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre></div></div>
<p>The following is working (most of the time) code that inserts a new entry:</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">prisma</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">user</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">create</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">data</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token literal-property property" style="color:#36acaa">name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Some User'</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>However, the following error may occur:</p>
<p>Unique constraint failed on the fields: (<code>id</code>)</p>
<p>This is baffling - if the field auto-increments, how can the unique constraint be violated?</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="why">Why?<a href="https://www.cheehow.dev/blog/2023/10/17/autoincrement-field-with-prisma/#why" class="hash-link" aria-label="Direct link to Why?" title="Direct link to Why?" translate="no">​</a></h3>
<p>The answer (for PostgreSQL at least) is that this error typically happens if there is an entry created before that was <em>not</em> created using the auto-incremented ID. In other words, if there is an entry that was created where the ID was explicitly set, a conflict arises when Prisma tries to set its own auto-incremented ID.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="solution">Solution<a href="https://www.cheehow.dev/blog/2023/10/17/autoincrement-field-with-prisma/#solution" class="hash-link" aria-label="Direct link to Solution" title="Direct link to Solution" translate="no">​</a></h3>
<p>So, where possible, avoid setting the ID explicitly for tables which have the primary key field being an auto-incremented number field.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="but-what-about">But what about...<a href="https://www.cheehow.dev/blog/2023/10/17/autoincrement-field-with-prisma/#but-what-about" class="hash-link" aria-label="Direct link to But what about..." title="Direct link to But what about..." translate="no">​</a></h3>
<p>Alright, so we know what to avoid doing in the future. But is there a solution for tables that already have entries with manual IDs created?</p>
<p>As a matter of fact, there is!</p>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> setval</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">pg_get_serial_sequence</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'"User"'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'id'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">coalesce</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">max</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">+</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">FROM</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"User"</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>Notice that the table name is encapsulated within a pair of single quotes and a pair of double quotes (<code>'"User"'</code>)? This is because the name of the table begins with an uppercase character (<code>U</code>). This is a quirk of PostgreSQL. If the table name does not begin with an uppercase letter, the inner double quotes is not necessary (e.g. <code>'user'</code>).</p>
<p>See this discussion in <a href="https://github.com/prisma/prisma/discussions/5256" target="_blank" rel="noopener noreferrer" class="">Prisma's Github Discussions</a>.</p>]]></content:encoded>
            <category>knowledgebase</category>
            <category>prisma</category>
            <category>postgresql</category>
            <category>programming</category>
            <category>autoincrement</category>
        </item>
        <item>
            <title><![CDATA[Docusaurus with Google Authentication]]></title>
            <link>https://www.cheehow.dev/blog/2023/04/02/docusaurus-with-google-authentication/</link>
            <guid>https://www.cheehow.dev/blog/2023/04/02/docusaurus-with-google-authentication/</guid>
            <pubDate>Sun, 02 Apr 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[With a little bit of programming, you can restrict your site made by Docusaurus to be accessible to users signed in to Google.]]></description>
            <content:encoded><![CDATA[<p>With a little bit of programming, your site made by Docusaurus can be modified to be accessible only to users signed in to Google.</p>
<p>The source material came from this <a href="https://medium.com/@thomasdevshare/docusaurus-authentication-with-firebase-c824da24bc51" target="_blank" rel="noopener noreferrer" class="">article</a> by <a href="https://medium.com/@thomasdevshare/about" target="_blank" rel="noopener noreferrer" class="">Thomasdevshare</a>. His article describes a similar authentication scheme for Docusaurus with Firebase as the identity provider whereas this article describes the same approach using Google API directly.</p>
<!-- -->
<p>The main concepts described in this article will be largely the same as that written by Thomas. The main differences:</p>
<ul>
<li class="">instead of depending on the <a href="https://www.npmjs.com/package/firebase" target="_blank" rel="noopener noreferrer" class="">Firebase package</a>, the <a href="https://www.npmjs.com/package/@react-oauth/google" target="_blank" rel="noopener noreferrer" class=""><code>@react-oauth</code> package</a> is used, and</li>
<li class="">a new section on designating allowed users to access the page.</li>
</ul>
<p>(The example in this document is written in TypeScript but it should be easily applicable to JavaScript.)</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="pre-requisites">Pre-requisites<a href="https://www.cheehow.dev/blog/2023/04/02/docusaurus-with-google-authentication/#pre-requisites" class="hash-link" aria-label="Direct link to Pre-requisites" title="Direct link to Pre-requisites" translate="no">​</a></h2>
<p>These are the things that you need to set up:</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-google-credential">1. Google credential<a href="https://www.cheehow.dev/blog/2023/04/02/docusaurus-with-google-authentication/#1-google-credential" class="hash-link" aria-label="Direct link to 1. Google credential" title="Direct link to 1. Google credential" translate="no">​</a></h3>
<p>This step can be done at <a href="https://console.cloud.google.com/apis/credentials" target="_blank" rel="noopener noreferrer" class="">https://console.cloud.google.com/apis/credentials</a></p>
<p>Follow the <a href="https://developers.google.com/identity/protocols/oauth2/javascript-implicit-flow#enable-apis" target="_blank" rel="noopener noreferrer" class="">Google instructions</a> to configure your project and create a <em>client ID for Web application</em>.</p>
<p>For local development, add <code>http://localhost</code> and <code>http://localhost:&lt;port_number&gt;</code> to the Authorized JavaScript origins for <code>@react-oauth</code> to work. When deploying to production, specify the actual URL of your site.</p>
<p>Note the <code>Client ID</code> field for the OAuth 2.0 Client - this needs to be placed into the <em>.env</em> file (see <a href="https://www.cheehow.dev/blog/2023/04/02/docusaurus-with-google-authentication/#3-specify-google-client-id-and-allowed-users" class="">below</a>).</p>
<p><img decoding="async" loading="lazy" alt="Google OAuth 2.0 Client" src="https://www.cheehow.dev/assets/images/google-client-id-9dd28efc186c086516c3040c090a51fe.png" width="800" height="78" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-add-the-react-oauthgoogle-dependency">2. Add the <a href="https://www.npmjs.com/package/@react-oauth/google" target="_blank" rel="noopener noreferrer" class=""><code>@react-oauth/google</code></a> dependency<a href="https://www.cheehow.dev/blog/2023/04/02/docusaurus-with-google-authentication/#2-add-the-react-oauthgoogle-dependency" class="hash-link" aria-label="Direct link to 2-add-the-react-oauthgoogle-dependency" title="Direct link to 2-add-the-react-oauthgoogle-dependency" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">npm</span><span class="token plain"> i @react-oauth/google</span><br></span></code></pre></div></div>
<p>This dependency makes it easy to incorporate the Google SSO implicit-authorization flow.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-specify-google-client-id-and-allowed-users">3. Specify Google Client ID and allowed users<a href="https://www.cheehow.dev/blog/2023/04/02/docusaurus-with-google-authentication/#3-specify-google-client-id-and-allowed-users" class="hash-link" aria-label="Direct link to 3. Specify Google Client ID and allowed users" title="Direct link to 3. Specify Google Client ID and allowed users" translate="no">​</a></h3>
<p>Create a file <em>.env</em> in the root of the directory (same location as <em>docusaurus.config.js</em>) and add the following contents, replacing the text in arrow brackets with actual values:</p>
<div class="theme-tabs-container tabs-container tabList__CuJ"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_LNqP tabs__item--active">.env</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_LNqP">Example</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_Ymn6"><pre><code><p>GOOGLE_CLIENTID=&lt;google client ID&gt;</p><br><p>ALLOWED_USERS=&lt;email addresses separated by commas&gt;</p></code></pre></div><div role="tabpanel" class="tabItem_Ymn6" hidden=""><pre><code><p>GOOGLE_CLIENTID=1111111111111-djfh38dhf467as1hdgg3f2df334msd.apps.googleusercontent.com</p><br><p>ALLOWED_USERS=<a href="mailto:user1@example.com" target="_blank" rel="noopener noreferrer" class="">user1@example.com</a>, <a href="mailto:user2@example.com" target="_blank" rel="noopener noreferrer" class="">user2@example.com</a>, <a href="mailto:user3@example.com" target="_blank" rel="noopener noreferrer" class="">user3@example.com</a></p></code></pre></div></div></div>
<p>The Google credentials obtained in <a href="https://www.cheehow.dev/blog/2023/04/02/docusaurus-with-google-authentication/#1-google-credential" class="">Step 1</a> should replace <code>&lt;google client ID&gt;</code>.</p>
<p><code>&lt;email addresses separated by commas&gt;</code> should be replaced with actual email addresses e.g. <code>email1@example.com, email2@example.com</code></p>
<p>(The space after the comma will be trimmed by the plugin so it doesn't matter if the commas are followed by spaces.)</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-configure-docusaurusconfigjs-to-read-the-environment-variables">4. Configure <em>docusaurus.config.js</em> to read the environment variables<a href="https://www.cheehow.dev/blog/2023/04/02/docusaurus-with-google-authentication/#4-configure-docusaurusconfigjs-to-read-the-environment-variables" class="hash-link" aria-label="Direct link to 4-configure-docusaurusconfigjs-to-read-the-environment-variables" title="Direct link to 4-configure-docusaurusconfigjs-to-read-the-environment-variables" translate="no">​</a></h3>
<p>Docusaurus is only able to read the environment variable during pre-processing. This means that the values in the <em>.env</em> file have to be "transferred" to the configuration file.</p>
<p>This is done by first adding the following line to <em>docusaurus.config.js</em>:</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">require</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'dotenv'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">config</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>Then, somewhere in the file below, assign the process environment variables to properties under <code>customFields</code>:</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> config </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">title</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Me3 Technical Documentation'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">customFields</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">allowedUsers</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> process</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">env</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">ALLOWED_USERS</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">googleClientId</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> process</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">env</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">GOOGLE_CLIENTID</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_BuS1"><p>I had used the plugin <a href="https://npmjs.com/package/docusaurus2-dotenv" target="_blank" rel="noopener noreferrer" class="">docusaurus2-dotenv</a> before but it didn't work with <a href="https://developers.cloudflare.com/pages/framework-guides/deploy-a-docusaurus-site/" target="_blank" rel="noopener noreferrer" class="">deployment to Cloudflare Pages</a>.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="log-in-component">Log-in Component<a href="https://www.cheehow.dev/blog/2023/04/02/docusaurus-with-google-authentication/#log-in-component" class="hash-link" aria-label="Direct link to Log-in Component" title="Direct link to Log-in Component" translate="no">​</a></h2>
<p>Next create the log-in component. This component displays the Google sign-in button for the user to authenticate himself/herself.</p>
<p>Create a file <em>src/components/login-google/index.tsx</em></p>
<div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">src/components/login-google/index.tsx</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports">useDocusaurusContext</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"@docusaurus/useDocusaurusContext"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"></span><br></span><span class="token-line" style="color:#393A34"><span class="token imports">  </span><span class="token imports maybe-class-name">CredentialResponse</span><span class="token imports punctuation" style="color:#393A34">,</span><span class="token imports"></span><br></span><span class="token-line" style="color:#393A34"><span class="token imports">  </span><span class="token imports maybe-class-name">GoogleLogin</span><span class="token imports punctuation" style="color:#393A34">,</span><span class="token imports"></span><br></span><span class="token-line" style="color:#393A34"><span class="token imports">  </span><span class="token imports maybe-class-name">GoogleOAuthProvider</span><span class="token imports punctuation" style="color:#393A34">,</span><span class="token imports"></span><br></span><span class="token-line" style="color:#393A34"><span class="token imports"></span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'@react-oauth/google'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports maybe-class-name">React</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'react'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:#d73a49">LoginGoogle</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">props</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function-variable function" style="color:#d73a49">login</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  denied</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> boolean</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">siteConfig</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> customFields </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useDocusaurusContext</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> clientId </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> customFields</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">googleClientId</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">as</span><span class="token plain"> string</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">handleError</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">error</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Failed to sign in with Google.'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">handleSuccess</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter literal-property property" style="color:#36acaa">creds</span><span class="token parameter operator" style="color:#393A34">:</span><span class="token parameter"> </span><span class="token parameter maybe-class-name">CredentialResponse</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> plaintext </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">decode</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">creds</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">credential</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">plaintext</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> payload </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token known-class-name class-name">JSON</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">parse</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">plaintext</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">isAllowed</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">payload</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">email</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      props</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">login</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">payload</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">email</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      props</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">login</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// Checks if the supplied email address is allowed to see the page.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">isAllowed</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter literal-property property" style="color:#36acaa">email</span><span class="token parameter operator" style="color:#393A34">:</span><span class="token parameter"> string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> boolean </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> allowedUsers </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">typeof</span><span class="token plain"> customFields</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">allowedUsers</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"string"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      allowedUsers </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> customFields</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">allowedUsers</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">split</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">","</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">e</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> e</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">trim</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">allowedUsers</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">includes</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">email</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">GoogleOAuthProvider</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">clientId</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">clientId</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag" style="color:#00009f">        </span><span class="token tag attr-name" style="color:#00a4db">style</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag script language-javascript" style="color:#00009f">          </span><span class="token tag script language-javascript literal-property property" style="color:#36acaa">display</span><span class="token tag script language-javascript operator" style="color:#393A34">:</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript string" style="color:#e3116c">'flex'</span><span class="token tag script language-javascript punctuation" style="color:#393A34">,</span><span class="token tag script language-javascript" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag script language-javascript" style="color:#00009f">          </span><span class="token tag script language-javascript literal-property property" style="color:#36acaa">flexFlow</span><span class="token tag script language-javascript operator" style="color:#393A34">:</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript string" style="color:#e3116c">'column nowrap'</span><span class="token tag script language-javascript punctuation" style="color:#393A34">,</span><span class="token tag script language-javascript" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag script language-javascript" style="color:#00009f">          </span><span class="token tag script language-javascript literal-property property" style="color:#36acaa">alignItems</span><span class="token tag script language-javascript operator" style="color:#393A34">:</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript string" style="color:#e3116c">'center'</span><span class="token tag script language-javascript punctuation" style="color:#393A34">,</span><span class="token tag script language-javascript" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag script language-javascript" style="color:#00009f">          </span><span class="token tag script language-javascript literal-property property" style="color:#36acaa">margin</span><span class="token tag script language-javascript operator" style="color:#393A34">:</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript string" style="color:#e3116c">'5rem auto'</span><span class="token tag script language-javascript punctuation" style="color:#393A34">,</span><span class="token tag script language-javascript" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag script language-javascript" style="color:#00009f">          </span><span class="token tag script language-javascript literal-property property" style="color:#36acaa">textAlign</span><span class="token tag script language-javascript operator" style="color:#393A34">:</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript string" style="color:#e3116c">'center'</span><span class="token tag script language-javascript punctuation" style="color:#393A34">,</span><span class="token tag script language-javascript" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag script language-javascript" style="color:#00009f">        </span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag" style="color:#00009f">      </span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">        </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">h2</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">Please sign in to your Google account to get access.</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">h2</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">props</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">denied</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">em</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">Not authorised</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">em</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">GoogleLogin</span><span class="token tag" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag" style="color:#00009f">            </span><span class="token tag attr-name" style="color:#00a4db">onSuccess</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">handleSuccess</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag" style="color:#00009f">            </span><span class="token tag attr-name" style="color:#00a4db">onError</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">handleError</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag" style="color:#00009f">          </span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">GoogleLogin</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">    </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">GoogleOAuthProvider</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Function to decode the JWT from Google to get the user's email address.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">decode</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter literal-property property" style="color:#36acaa">jwt</span><span class="token parameter operator" style="color:#393A34">:</span><span class="token parameter"> string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> string </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> parts </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> jwt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">split</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'.'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">parts</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">!==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">''</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token dom variable" style="color:#36acaa">window</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">atob</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">parts</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="swizzle-the-root-component"><em>Swizzle</em> the Root Component<a href="https://www.cheehow.dev/blog/2023/04/02/docusaurus-with-google-authentication/#swizzle-the-root-component" class="hash-link" aria-label="Direct link to swizzle-the-root-component" title="Direct link to swizzle-the-root-component" translate="no">​</a></h2>
<p><a href="https://docusaurus.io/docs/swizzling" target="_blank" rel="noopener noreferrer" class=""><em>Swizzling</em></a> is a term describing the overridding of an existing component with a custom implementation of it.</p>
<p>The Root component is the component to swizzle as it covers all generated pages.</p>
<div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">src/theme/Root.tsx</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports maybe-class-name">React</span><span class="token imports punctuation" style="color:#393A34">,</span><span class="token imports"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> useState </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'react'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">LoginGoogle</span><span class="token imports"> </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'@site/src/components/login-google'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">default</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:#d73a49">Root</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter punctuation" style="color:#393A34">{</span><span class="token parameter"> children </span><span class="token parameter punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// `email` is used to determine if user is allowed.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">email</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> setEmail</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">useState </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">''</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">email</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">LoginGoogle</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">login</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">setEmail</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">denied</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">email </span><span class="token tag script language-javascript operator" style="color:#393A34">===</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript keyword null nil" style="color:#00009f">null</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">LoginGoogle</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">children</span><span class="token punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://www.cheehow.dev/blog/2023/04/02/docusaurus-with-google-authentication/#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion" translate="no">​</a></h2>
<p>One thing to note: the authentication information is only persisted in memory. What this means is that the authentiction is temporary (the correct term is <em>ephemeral</em>). The implication is that as soon as the user refreshes the page, the authenticated information (i.e. email address) is lost and the user gets "logged out".</p>]]></content:encoded>
            <category>programming</category>
            <category>docusaurus</category>
            <category>google</category>
        </item>
        <item>
            <title><![CDATA[About Domain Names]]></title>
            <link>https://www.cheehow.dev/blog/2019/08/26/about-domain-names/</link>
            <guid>https://www.cheehow.dev/blog/2019/08/26/about-domain-names/</guid>
            <pubDate>Mon, 26 Aug 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[This piece is a quick, non-technical introduction to domain names.]]></description>
            <content:encoded><![CDATA[<figure><img src="https://www.cheehow.dev/assets/images/kobu-agency-7okkFhxrxNw-unsplash-8bf991280e18f3cb46cb72b1cfe0f29b.jpg" alt="two women talking while looking at laptop computer"><figcaption>Photo by <a target="_blank" href="https://unsplash.com/@kobuagency">Kobu Agency</a> on <a target="_blank" href="https://unsplash.com/search/photos/website">Unsplash</a></figcaption></figure>
<p>This piece is a quick, non-technical introduction to domain names.</p>
<p>When I set out to write this article, I did not expect to write several drafts only to completely throw them away.</p>
<p>As I planned the outline of the article, I began to realise the depth and complexity of the topic. It was a challenge not to turn this into a technical write-up on DNS and nameservers in my attempt to elucidate the jargon and economics surrounding domain names.</p>
<p>So I decided to take on a consulting mindset for writing this article. I began with the question "What is the first thing that a small business owner would ask about his/her domain?"</p>
<p>The answer?</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="cost">Cost<a href="https://www.cheehow.dev/blog/2019/08/26/about-domain-names/#cost" class="hash-link" aria-label="Direct link to Cost" title="Direct link to Cost" translate="no">​</a></h2>
<p>The first thing that comes to mind for any small business owner is cost. It is only natural—even expected—that, as a (potential) business owner, you want to keep costs low as much as possible.</p>
<p>So let's start with that.</p>
<p>There are two types of costs you need to be concerned with: the acquisition cost and the renewal cost.</p>
<p>The acquisition cost is based on the domain name you want. For available domain names (names not yet claimed by anyone), the cost is very affordable - less than a hundred Sing dollars. You can purchase available domains on-the-spot easily with a credit card.</p>
<p>Then there are domain names that are held for sale. These domain names are kept for no other purpose than profit. This practice is known as <em>cybersquatting</em>.</p>
<p>I have not had to purchase a domain from cybersquatters before but the lowest price you are looking at is typically a four-figure sum. For comparison, a fresh .com domain costs around US$15. This huge price difference is why all my clients and friends have chosen to brainstorm for a fresh domain rather than to shelve out large sums of money to get an existing one. If cost savings is important to you, this is what I would recommend as well.</p>
<p>For a new domain, the renewal price is usually the same as what you paid for. That has changed now—there are <em>tiered price domains</em> that are sold at a higher price than what it costs to renew them.</p>
<p>So if there is a domain name that you very much want, but comes with a higher price tag, take a look again. The difference might be small enough (some might be a few hundred dollars) for you to stomach the one-time acquisition cost if the renewal cost is nominal. (See next section for examples.) Just chalk it off as a capital expenditure. 🤷🤷‍♂️</p>
<p>The renewal cost of a domain is usually based on its top-level domain (TLD). In simple terms, the TLD is the right most part of a domain name.</p>
<p><img decoding="async" loading="lazy" alt="www.example.com" src="https://www.cheehow.dev/assets/images/example-450f2af877aeb0d7d67fc6fb0324cd63.png" width="800" height="300" class="img_ev3q"></p>
<p>You should be familiar with .com - it is the most common TLD. Together with it, .net and .org are among the earliest TLDs introduced to the domain name system (DNS).</p>
<p>There are others, but I will only go through the types that are of relevance to this article in the next section on…</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="types-of-domain-names">Types of Domain Names<a href="https://www.cheehow.dev/blog/2019/08/26/about-domain-names/#types-of-domain-names" class="hash-link" aria-label="Direct link to Types of Domain Names" title="Direct link to Types of Domain Names" translate="no">​</a></h2>
<p>As mentioned in the previous section, .com, .net and .org are among the earliest domains introduced in the DNS. Coincidentally, they are also the cheapest to renew.</p>
<p>Acquiring them is not easy though. Being the earliest TLDs, they are also the most used. I think it is safe to say that any English word you can think of, the .com domain is probably taken.</p>
<p>If you can think of a new word or phrase then you will be able to get the .com easily without paying a premium.</p>
<p>To combat this shortage of names, ICANN has created other TLDs such as .app, .tech, .club, etc. For these TLDs though, some unclaimed domains already command a premium right out the gate. As mentioned previously these are tiered price domains. Below are a few examples of them:</p>
<p><img decoding="async" loading="lazy" alt="domain names" src="https://www.cheehow.dev/assets/images/names-68d007ca9294c45ac2baf1384de0a847.png" width="701" height="189" class="img_ev3q"></p>
<figure><figcaption>Notice how some renewal prices are the same as the initial acquisition cost, and some are different.</figcaption></figure>
<p>My friends and customers target primarily the Singapore market. For them, either a .com or .sg/.com.sg TLD works fine. However, I do think that a .sg/.com.sg domain removes the ambiguity altogether for your target audience. In a way, it acts as a filter for traffic coming to your website, and for your audience, an implicit assurance that you are operating in Singapore.</p>
<p>Domains that end with a country specific suffix like .sg have <em>country code top-level domains</em> (ccTLDs). A ccTLD domain is likely more expensive than a generic TLD like .com, the reason being that the ccTLD has to be administered by a country-specific intermediary called a Network Information Centre. For Singapore, this entity is called SGNIC.</p>
<p>To have an idea of the kind of price difference, a typical .com domain costs around S$18 (US$13). A typical .sg/.com.sg costs around S$45.</p>
<p>Domains ending with .com.sg can only be registered by a Singaporean company entity. Domains ending with .sg may be registered by anyone residing in Singapore. To get a Singapore ccTLD, there is an additional verification of identity implemented by the VerifiedID@SG scheme. Singaporeans can access this scheme using their SingPass accounts.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="getting-the-domain-name">Getting the Domain Name<a href="https://www.cheehow.dev/blog/2019/08/26/about-domain-names/#getting-the-domain-name" class="hash-link" aria-label="Direct link to Getting the Domain Name" title="Direct link to Getting the Domain Name" translate="no">​</a></h2>
<p>Most of you reading this would probably leave it to your appointed vendor to register the domain for you. This is totally fine, if your vendor is reliable.</p>
<p>As mentioned in the <a class="" href="https://www.cheehow.dev/blog/2019/08/15/3-things-to-watch-out-for-when-commissioning-your-website/">previous article</a>, it is important that the registrant information is registered as your own.</p>
<p>The following scenario that I am going to describe is a worst-case scenario that I have not had to deal with yet.</p>
<p>Suppose your vendor registered his/her own information for all four pieces of information (billing, tech, admin, and registrant) for the domain (probably for no other reason than for convenience). If your vendor is a solopreneur/freelancer, all formal records would show that he/she is the sole registrant. In the event that he/she is not contactable for whatever reason, imagine how would you recover your domain?</p>
<p>Now, I am not saying that having your name lodged as the registrant will guarantee that you can recover your domain. But not having your name in any of the records will definitely not help you at all.</p>
<p>Therefore, you have to emphasize to your vendor/developer to make sure to enter your information for the registrant. Incidentally, if you are getting a .sg or .com.sg domain, you are required by the VerifiedID@SG scheme to verify your identity using your SingPass account. Note that this is <strong>in addition</strong> to the registrant info, so be sure that both are in order.</p>
<p>If you are inclined, it is perfectly fine for you to register the domain name by yourself. But be aware that at some point, you will need to map the DNS records for your domain to the server where your website resides. Alternatively, rather than doing it yourself, you may also pass your credentials to your vendor to make those changes for you.</p>
<p>What I recommend though (if you registered the domain name yourself) is to have your vendor change those settings in front of you. On the day when you "go live" (i.e. putting your website online), have the vendor come to your office. Sign in to your registrar's control panel, and let him/her change the DNS settings on the spot. This way, you need not reveal your password and worry about potential security issues.</p>
<p>I will not be describing the DNS settings in this article. It is too complex to describe in a reasonable length. You should leave this part to your vendor/developer to handle.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="www-or-not">WWW or not?<a href="https://www.cheehow.dev/blog/2019/08/26/about-domain-names/#www-or-not" class="hash-link" aria-label="Direct link to WWW or not?" title="Direct link to WWW or not?" translate="no">​</a></h2>
<p>The last thing to mention is the www prefix. Unbeknownst to many, the www prefix, known as a <em>subdomain</em>, is an optional part of the domain name that is determined by your DNS settings.</p>
<p>From what I understand, this prefix also has an impact on your search rankings. Depending on configurations, it is possible to have your website served on both the www and naked domain (i.e. without the www). Google seems to frown upon this though - it considers them to be duplicate content. How it affects your website's ranking in the search results, I'm not exactly sure. All I know is that Google recommends not having the same content at different URLs. The naked domain and the www subdomain are considered different URLs.</p>
<p>My recommendation is that you ask your developer to redirect traffic from one to the other. It is usually a matter of preference whether to serve your website on the naked domain or the subdomain. My stance is that having a www subdomain makes it absolutely clear that what you are referring to is a website. This is all the more important if your chosen TLD is not a .com (e.g. <a href="http://www.example.app/" target="_blank" rel="noopener noreferrer" class="">www.example.app</a>, <a href="http://www.example.tech/" target="_blank" rel="noopener noreferrer" class="">www.example.tech</a>, etc.)</p>
<p>Note that I am recommending the www prefix for your website, not your email address. It is absolutely unnecessary to have the prefix for your email address. In fact it is cumbersome to include the prefix for your email address. (Compare <a href="mailto:charles@school.com" target="_blank" rel="noopener noreferrer" class="">charles@school.com</a> and <a href="mailto:charles@www.school.com" target="_blank" rel="noopener noreferrer" class="">charles@www.school.com</a>)</p>
<p>This article has gone on long enough already. If the opportunity arises, I will discuss domain transfer and other topics in another article.</p>
<p>(Also posted on <a href="https://medium.com/@cheehow_c/about-domain-names-5cfd9cc9af40?sk=97bc4b798071fd59ce73b4d7defb4325" target="_blank" rel="noopener noreferrer" class="">Medium</a> and <a href="https://www.linkedin.com/pulse/domain-names-chee-how-chua" target="_blank" rel="noopener noreferrer" class="">LinkedIn</a>.)</p>]]></content:encoded>
            <category>websitetips</category>
            <category>domains</category>
            <category>sme</category>
            <category>smallbusiness</category>
        </item>
        <item>
            <title><![CDATA[3 Things to Watch Out For When Commissioning Your Website]]></title>
            <link>https://www.cheehow.dev/blog/2019/08/15/3-things-to-watch-out-for-when-commissioning-your-website/</link>
            <guid>https://www.cheehow.dev/blog/2019/08/15/3-things-to-watch-out-for-when-commissioning-your-website/</guid>
            <pubDate>Thu, 15 Aug 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[I decided to write down all the advice on website building that I always give my friends and customers so that I don't ever miss anything out. This is the first of several articles.]]></description>
            <content:encoded><![CDATA[<figure><img src="https://www.cheehow.dev/assets/images/freestocks-org-I_pOqP6kCOI-unsplash-637a5927d6b6100b7d2d36bd79a84b38.jpg" alt="hands typing on a laptop with another laptop by the side"><figcaption>Photo by <a target="_blank" href="https://unsplash.com/@freestocks">freestocks.org</a> on <a target="_blank" href="https://unsplash.com/search/photos/website">Unsplash</a></figcaption></figure>
<p>I decided to write down all the advice on website building that I always give my friends and customers so that I don't ever miss anything out. This is the first of several articles.</p>
<p>I've been making webpages since the 90s. So I think I know a thing or two about building websites.</p>
<p>I really ought to since I've already built more than a handful of websites professionally and for my business owner friends.</p>
<p>Every time I do so, I find that I have to explain the same things to my clients and friends—the things to watch out for, the parts that make up the website, the available kinds of hosting options, etc.</p>
<p>The thing is, there are so many things to mention that each time I explain, I inevitably miss something out. So I decided to write it all down in the form of articles, listicles, or checklists that are easy to read and digest. My target readers are the average people and small business owners. I try to be as concise and non-technical as possible, so that they can read, understand, do it right, and get on with their lives.</p>
<p>To keep the length of this article manageable, I will discuss just the three fundamental things to look out for.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-make-sure-domain-ownership-is-clear">1. Make Sure Domain Ownership is Clear<a href="https://www.cheehow.dev/blog/2019/08/15/3-things-to-watch-out-for-when-commissioning-your-website/#1-make-sure-domain-ownership-is-clear" class="hash-link" aria-label="Direct link to 1. Make Sure Domain Ownership is Clear" title="Direct link to 1. Make Sure Domain Ownership is Clear" translate="no">​</a></h2>
<p>If there is only one thing I can share, it is this: make sure you own the domain!</p>
<p>"Why would I not own the domain? I paid for it!"</p>
<p>That's the typical response I get. The reason is that domain names are registered with <a href="https://www.icann.org/" title="Internet Corporation for Assigned Names and Numbers">ICANN</a> through registrars. When a domain name is registered, there are 4 pieces of contact information that needs to be provided—registrant, admin, tech, and billing.</p>
<p>Most important among them is the registrant information—the entity/person that has registered for the domain.</p>
<p>So why would that be a problem? The issue is actually due to human behaviour. You see, people loathe to enter data into fields. The cognitive burden when entering fields for four contacts is even higher. As a result, many vendors are often tempted to enter one set of information (his/her own) and use the same for all four contacts (this is usually made possible by the user interface).</p>
<p>Most of the time, this is not a problem, but when it does become a problem, there is generally no recourse for the site owner. The problem typically manifests itself when the working relationship between the vendor and the site owner turns sour.</p>
<p>I have not had to deal with this yet, fortunately. But imagine if the vendor became hostile and denies the domain to you, the site owner, there would be no records of ownership as far as ICANN is concerned. If the vendor is not cooperative, it would take you a king's ransom and a long time in order to reclaim the domain.</p>
<p>This is why it is so, so important for you to make sure that the selected vendor is a reliable and trustworthy one. Otherwise, it might be better to just handle the domain portion personally.</p>
<p>I will be writing a <a class="" href="https://www.cheehow.dev/blog/2019/08/26/about-domain-names/">piece on domain names separately</a> to delve into more details.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-costs-are-not-necessarily-indicative-of-quality">2. Costs Are Not Necessarily Indicative of Quality<a href="https://www.cheehow.dev/blog/2019/08/15/3-things-to-watch-out-for-when-commissioning-your-website/#2-costs-are-not-necessarily-indicative-of-quality" class="hash-link" aria-label="Direct link to 2. Costs Are Not Necessarily Indicative of Quality" title="Direct link to 2. Costs Are Not Necessarily Indicative of Quality" translate="no">​</a></h2>
<p>Creating a website is not like buying a car where there are clear boundaries that links quality with the right price tag.</p>
<p>Two vendors (developers) can quote the same price for a website but deliver wildly different results.</p>
<p>In my next piece on website fundamentals, I discuss the dirty little secrets of the industry (among other reasons) that explain why there is now such a large variation of quality.</p>
<p>So if price is not the answer, then what is?</p>
<p>There are generally two ways to make sure you hire the right developer.</p>
<p>One, check out the developer's previous work. For most of you reading this, the only criterion by which the work can be judged is through the aesthetics. That is well and good, but may not be sufficient, as I'll explain in another article.</p>
<p>Two, have the developer create the mock-up (also sometimes referred to as the prototype) of the website before starting actual programming work. This way you can have an idea of what the final product will look like much more quickly (and cheaply) than waiting for the site to be fully developed. This is the way it is because it takes a lot more work and time to create the actual website than to illustrate what the final design will look like.</p>
<p>To make it fair for both parties, I always recommend creating the mock-up first. Let's be clear, the mock-up isn't some sketch or hand-drawn representation of the site. Rather, it is an almost exact replica of the website. There are tools now that do not even cost money that the vendor can use to present the final look-and-feel without writing a single line of code.</p>
<p>I also recommend that you pay a fair sum of money for this prototype. While no code is written, it still takes time, effort and creative brain juice to think of and create the design. There is no right figure as the price of a website may differ greatly. Generally though, some 10% to 25% may be a ballpark figure to pay for this mock-up. It is a good way to hedge the risk and still be fair to both you and the vendor.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-check-the-email-service-provider">3. Check the Email Service Provider<a href="https://www.cheehow.dev/blog/2019/08/15/3-things-to-watch-out-for-when-commissioning-your-website/#3-check-the-email-service-provider" class="hash-link" aria-label="Direct link to 3. Check the Email Service Provider" title="Direct link to 3. Check the Email Service Provider" translate="no">​</a></h2>
<p>From my experience, when a business owner wants to create his or her own website, that usually means there is no decent email service as well.</p>
<p>By "decent" I mean an email address ending in the same domain as your website. That means no @singnet.com.sg, @gmail.com, or @outlook.com addresses.</p>
<p>This is another topic that warrants another article. For now just be aware that there are many email server options that may be close in price but vary greatly in terms of features and functions.</p>
<p>I think that Gmail has set the gold standard for email service. To me, an inbox capacity of less than a gigabyte is not considered usable given the propensity for people to send large attachments nowadays.</p>
<p>Yet, there are still traditional providers that provide (understandably small capacity) email accounts along with web hosting as a package on the cheap. While that might sound nice, especially for the start where you think "I can just change when my business grows", the reality is typically different.</p>
<p>Email is a critical business function in the work environment. When you start outgrowing your meagre inbox capacity, you'll start to experience all the inefficiencies and potential lost businesses due to a full inbox.</p>
<p>If you then want to switch to a bigger inbox, and you wish to move the contents from the old inbox to the new one, there is then this email migration cost that you will have to factor in. This migration cost is significantly higher than the subscription price of your email service. Unless… you are alright with putting up with the inconvenience of switching between your old inbox and the new one (and potential confusion that comes with it).</p>
<p>Bear in mind that this does not affect just yourself but the other coworkers in your company that have an inbox. So any inefficiency/lost productivity is magnified.</p>
<p>In summary, if you want to avoid this kind of headaches and potential lost productivity, be sure to get your email hosting solution right at the start.</p>
<p>(If you want to have the Gmail equivalent experience for your inbox, use <a href="https://gsuite.google.com/" target="_blank" rel="noopener noreferrer" class="">G Suite</a>! If you decide to go with that, <a href="https://twitter.com/chuacheehow" target="_blank" rel="noopener noreferrer" class="">hit me up</a>! I've got promotion codes for you that give you 20% off the first year subscription per user. Also, I get a commission 😉)</p>
<p>So that's it. These are the three things that I would advise anyone thinking of commissioning a website to establish a web presence. Reach me on Twitter (<a href="https://twitter.com/chuacheehow" target="_blank" rel="noopener noreferrer" class="">@chuacheehow</a>) if you have any questions.</p>
<p>(Also posted on <a href="https://medium.com/@cheehow_c/3-things-to-watch-out-for-when-commissioning-your-website-d93a6706c8f6?source=friends_link&amp;sk=c40b6cbc074bd9249bf6ef924852446c" target="_blank" rel="noopener noreferrer" class="">Medium</a> and <a href="https://www.linkedin.com/pulse/3-things-watch-out-when-commissioning-your-website-chee-how-chua" target="_blank" rel="noopener noreferrer" class="">LinkedIn</a>.)</p>
<p>My thanks go to <a href="https://www.facebook.com/jabmimi" target="_blank" rel="noopener noreferrer" class="">Abdul Rahman</a> for helping with proofreading.</p>]]></content:encoded>
            <category>websitetips</category>
            <category>domains</category>
            <category>emailservicetips</category>
            <category>sme</category>
            <category>smallbusiness</category>
        </item>
        <item>
            <title><![CDATA[Leaving My Company]]></title>
            <link>https://www.cheehow.dev/blog/2019/02/01/leaving-my-company/</link>
            <guid>https://www.cheehow.dev/blog/2019/02/01/leaving-my-company/</guid>
            <pubDate>Fri, 01 Feb 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[Two months ago I left the company which I co-founded 13 years back. Here are some of my takeaways after 13 years as its CTO.]]></description>
            <content:encoded><![CDATA[<figure><img src="https://www.cheehow.dev/assets/images/hero-c0b1f0a6f3c851d55aecc606bf22ba98.jpg" alt="photo of a balloon in Orchard Road, Singapore"><figcaption>Photo credit: Chua Chee How</figcaption></figure>
<p>Two months ago I left the company which I co-founded 13 years back. Here are some of my takeaways after 13 years as its CTO.</p>
<p>But first, an introduction.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="back-story">Back story<a href="https://www.cheehow.dev/blog/2019/02/01/leaving-my-company/#back-story" class="hash-link" aria-label="Direct link to Back story" title="Direct link to Back story" translate="no">​</a></h2>
<p>We are a company focused on education technologies that improve the pedagogical aspects of learning in schools.</p>
<p>Throughout our 13 years of operation, we've taken on work and projects of different scopes. We started with software training for adults. Back then Photoshop and its ilk from Adobe, and Dreamweaver and the Macromedia suite of applications were the must-knows for image manipulation and Web development.</p>
<p>Business was slow. A year or two after we started, we reached an inflection point. We had to decide to wind up or to pivot to a different business scope. Being the young and full-spirited youngsters we were, we wanted to give entrepreneurship another shot before throwing in the towel. With a stroke of luck, through the relationship that one of the founders had with people from Novell, we got on board a programme to supply training services to public schools.</p>
<p>Back then, there was a strong emphasis on graphical programs and interactive multimedia as a result of the Ministry of Education (MOE) IT Master Plan. With the fortuitous early investment (of time) I made into learning the Adobe and Macromedia suite of programs (think Photoshop, Flash, Dreamweaver and the likes), I was able to conduct the courses that we pitched to the schools.</p>
<p>Thanks to our partnership with Novell, we were able to gain some traction with school trainings. As Novell had acquired SUSE Linux not too long back, we also had the privilege of introducing Linux to schools. It was also then that I really sunk my teeth into Linux. (Since then, I've switched to using Linux on the desktop exclusively. I'm very thankful for that chance to really learn Linux well.)</p>
<p>The margins from training were already slim back then. Competition was intense, coming from one-person shops to existing incumbents. We thus had to be opportunistic, grabbing all kinds of deals that came our way. Along the way, through Novell and other channels, we also got a few deals that involved server deployment - completely unrelated to education.</p>
<p>As the sole technical founder, I had to equip myself with knowledge of Linux server deployment to perform the actual deployment while also conducting trainings in schools.</p>
<p>When it comes to the choice of projects, we were really not discerning, all in the name of survival. In 2006 (I think), we even clinched the deal for technical support for the Nokia phones distributed to the attendees of the International Monetary Fund (IMF) conference in Singapore.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="google">Google<a href="https://www.cheehow.dev/blog/2019/02/01/leaving-my-company/#google" class="hash-link" aria-label="Direct link to Google" title="Direct link to Google" translate="no">​</a></h2>
<p>Sometime between 2006 and 2008, we had our first contact with Google. At that time, they were located at Shenton Way where they took up an entire floor (or was it two?) in AXA Tower.</p>
<p>It was also then when we were introduced to what is now known as G Suite. We were early to the party. Being education focused, we were the first to introduce Google Apps, as it was then called, to schools.</p>
<p>We also became a reseller, selling Google Apps to commercial entities (the education edition is free of charge to educational institutes).</p>
<p>That went on for a while until we also became a Chrome Device Management license reseller with our own brand of Chromebooks.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="applications">Applications<a href="https://www.cheehow.dev/blog/2019/02/01/leaving-my-company/#applications" class="hash-link" aria-label="Direct link to Applications" title="Direct link to Applications" translate="no">​</a></h2>
<p>Along the journey, we also created a plethora of applications:</p>
<ul>
<li class=""><a href="http://chromeclass.com/" target="_blank" rel="noopener noreferrer" class="">Chromeclass</a> (software to manage student Chromebooks),</li>
<li class=""><a href="http://woma.jotterlab.com/" target="_blank" rel="noopener noreferrer" class="">Woma</a> (workload management tool for Google Classroom),</li>
<li class=""><a href="https://webnap-gsa.appspot.com/" target="_blank" rel="noopener noreferrer" class="">WebNap</a> (cyber safety testing tool),</li>
<li class="">Jotterlab (this name was used for different projects as we groomed and killed a few initiatives along the way),</li>
<li class="">VLS (stands for Virtual Lab for Science),</li>
<li class=""><a href="https://trustednetworkext.appspot.com/" target="_blank" rel="noopener noreferrer" class="">Trusted Network Extension</a> (an IP tracking tool),</li>
<li class=""><a href="https://g-flip.appspot.com/" target="_blank" rel="noopener noreferrer" class="">GFlip</a> (video repository for flipped learning),</li>
<li class="">Ductbooks (a book delivery and management system),</li>
<li class="">Edurious (a component of an learning management platform for low bandwidth environments), and</li>
<li class="">Locus (a shared access terminal for Chromebooks with more controls than a Chromebook in Public Terminal mode).</li>
</ul>
<p>Among these, a third of them were just proof-of-concept. One third of these is still being used by customers. The remaining are in the trash.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="unified-vision">Unified vision<a href="https://www.cheehow.dev/blog/2019/02/01/leaving-my-company/#unified-vision" class="hash-link" aria-label="Direct link to Unified vision" title="Direct link to Unified vision" translate="no">​</a></h2>
<p>So that was the story for 13 years in a nutshell. When we started, there were four shareholders. When I left, there were only two key decision makers, including myself.</p>
<p>Probably as a result of having only two decision makers, some of my realisations were more palpable than others.</p>
<p><em>In order for a company to move as a whole, there must be a clear direction to move towards. In corporate speak, this is the company vision and mission.</em></p>
<p>If there is no consensus as to what the company vision and mission are, then the baseline mission is profit maximisation. The organization then behaves like an indiscriminate eater, gobbling up every piece of morsel that comes its way, regardless if it's toxic or nutritious.</p>
<p>In some cases, a one-off project with seemingly low returns, if any at all, may be necessary as part of an overarching strategy, to augment the company's position in the market. These projects are necessary evils, medicine that the company must take to further its business interests.</p>
<p>In other cases, such one-off projects with seemingly high (potential) returns may feel like the sweet flesh of low lying fruits but they draw the company's resources away from its core focus. In the best case, they are profitable distractions. In the worst case(s), they are loss-making adventures that hold the company back.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="gauging-product-market-fit">Gauging product market fit<a href="https://www.cheehow.dev/blog/2019/02/01/leaving-my-company/#gauging-product-market-fit" class="hash-link" aria-label="Direct link to Gauging product market fit" title="Direct link to Gauging product market fit" translate="no">​</a></h2>
<p><em>Before committing to making a product, make sure that a good part of the market wants it.</em></p>
<p>We made the critical mistake of “surveying a market of one”. We didn't do enough market research to identify the market demand for the Web app we were planning to make.</p>
<p>Just because we hear the need from one or two potential customers, it does not mean there is a market demand for a solution. This statement sounds so obvious that it is almost redundant to state it. The problem is that we often fall to the trap of hearing only what we want to hear. When the person at the other end is in 100% consensus with you, it can feel like the whole world is in agreement.</p>
<p>One trick to identify this kind of conversation is when the person makes sweeping statements like “Oh, everyone will need this solution.” It is not so much the accuracy or correctness of the statement (because who knows for sure?) that is the problem but rather that such statements lull the subconscious into thinking that they are facts rather than opinions or guesses.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ease-of-use-trumps-value-proposition">Ease of use trumps value proposition<a href="https://www.cheehow.dev/blog/2019/02/01/leaving-my-company/#ease-of-use-trumps-value-proposition" class="hash-link" aria-label="Direct link to Ease of use trumps value proposition" title="Direct link to Ease of use trumps value proposition" translate="no">​</a></h2>
<p><em>The value proposition provided by an application must be a magnitude greater than the effort to achieve it.</em></p>
<p>I learnt this lesson from the same failed project that showed the importance of market demand.</p>
<p>The software was to help students become better essay writers by making incremental improvements to their essays through a methodology called “process writing”. With this methodology, students write several versions of an essay. Their peers and teachers can the review the essay and make comments on areas that need improving.</p>
<p>This all sounds good.</p>
<p>The problem is that we did not realise the amount of work required in this process, for both the students and teachers. From the perspective of students, writing just one essay is already a lot of work. To have them write the same essay more than once, in addition to their other assignments, is a tall order. Ditto for the teachers, whose workload is already too much. There is little to no incentive to use such an application.</p>
<p>Despite the premise of the program, it was simply too much additional work for the users. The project was doomed to fail at conception.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-it-takes-to-make-good-software">What it takes to make good software<a href="https://www.cheehow.dev/blog/2019/02/01/leaving-my-company/#what-it-takes-to-make-good-software" class="hash-link" aria-label="Direct link to What it takes to make good software" title="Direct link to What it takes to make good software" translate="no">​</a></h2>
<p><em>Being able to rapidly prototype an application to validate an idea does not mean it is trivial to write good software.</em></p>
<p>Very often, in the quest for rapid development, developers have to take shortcuts. Such shortcuts may meet the project's current and immediate goals but are typically detrimental to its future development. Such shortcuts are known as technical debt.</p>
<p>Like financial debt, the more you take on, the deeper you sink. Without understanding this, it is <em>so</em> easy to fall into the trap of thinking that a software project is done once all the checkboxes are ticked.</p>
<p>Feedback loop with early customers has to be proactive and regular. A software product is almost always never done. There are always features to add, and bugs to fix.</p>
<p>The people who put money with you before you have any traction is trusting you with their money. There is a moral imperative to reciprocate that trust by making the product/service the best that it can be. If, however, you need to keep getting different projects then either a) the model of creating your own software is not tenable, or b) the project is not something that the market needs i.e. the project should not exist, and should be trimmed to make space for (allocate resources to) other projects that might have a better chance of succeeding in the market.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="in-conclusion">In conclusion<a href="https://www.cheehow.dev/blog/2019/02/01/leaving-my-company/#in-conclusion" class="hash-link" aria-label="Direct link to In conclusion" title="Direct link to In conclusion" translate="no">​</a></h2>
<p>The company is now, and has been for a few years, stable and growing the Chrome business. We would not have imagined the hardware business making up the main chunk of the revenue, and yet, the company now stands as the Singapore's leading company for G Suite and Chrome technology in the education sector. With any luck, the company may still soar to greater heights in the right direction and focus. I wish for only the best to the company and my former colleagues.</p>
<p>(Also posted on <a href="https://medium.com/@cheehow_c/leaving-my-company-a2d25f5051b9" target="_blank" rel="noopener noreferrer" class="">Medium</a> and <a href="https://www.linkedin.com/pulse/leaving-my-company-chee-how-chua/" target="_blank" rel="noopener noreferrer" class="">LinkedIn</a>.)</p>]]></content:encoded>
            <category>reflection</category>
            <category>personal</category>
        </item>
        <item>
            <title><![CDATA[Effective Presentations - Part 2 of 2]]></title>
            <link>https://www.cheehow.dev/blog/2017/02/24/effective-presentations-part-2-of-2/</link>
            <guid>https://www.cheehow.dev/blog/2017/02/24/effective-presentations-part-2-of-2/</guid>
            <pubDate>Fri, 24 Feb 2017 00:00:00 GMT</pubDate>
            <description><![CDATA[In the previous article, I wrote about my attempt at improving my pitches. I left off from that piece with the promise of a formula that can improve the quality of your slide decks immediately.]]></description>
            <content:encoded><![CDATA[<figure><img src="https://www.cheehow.dev/assets/images/aaron-burden-90144-40faa49baf19b304fe76a76379dc5f26.jpg" alt=""><figcaption>Photo credit: <a href="https://unsplash.com/photos/CKlHKtCJZKk" target="_blank">Unsplash</a></figcaption></figure>
<p>In the <a class="" href="https://www.cheehow.dev/blog/2017/02/06/effective-presentations-part-1-of-2/">previous article</a>, I wrote about my attempt at improving my
pitches. I left off from that piece with the promise of a formula that can
improve the quality of your slide decks immediately.</p>
<p>The answer: <em>storytelling</em>.</p>
<p>The problem with this statement is it seems too simple, even patronizing, an
answer.</p>
<p>From another perspective, it could be that because the answer is so simple, it
is easy to dismiss.</p>
<p>But if you can take a moment to digest this answer, you will begin to realise
that it makes sense. Notice that in any TV series, every episode tries to end
with a cliffhanger. Producers do that because they know that it makes the
audience look forward to watching the next episode to find out what happens
next, that they want to “fill in the gap” in the whole story.</p>
<p>Storytelling is a process from the start to the end. Anything missing in this
process is a gap. No one likes gaps. Everyone wants closure. That’s why it is
more painful to lose a loved one suddenly because we lose the chance to say
our last words - closure.</p>
<p>Every Hollywood movie nowadays have equally stunning visual effects but what
makes one movie A-grade and another subpar is really the quality of the story,
an element that is not as much observed as it is felt.</p>
<p>“If storytelling is the answer, then what is the formula?” I can already
imagine this question surfacing in your mind as you read this.</p>
<p>The answer can be found from this <a href="https://medium.com/firm-narrative/want-a-better-pitch-watch-this-328b95c2fd0b#.wrn0fp5ad" target="_blank" rel="noopener noreferrer" class="">Medium piece</a> by <a href="https://medium.com/@raskin" target="_blank" rel="noopener noreferrer" class="">Andy Raskin</a>.</p>
<p>I replicate below the points which he made in that article:</p>
<blockquote>
<ol>
<li class="">Name the enemy</li>
<li class="">Answer “Why now?”</li>
<li class="">Show the promised land before explaining how you’ll get there</li>
<li class="">Identify obstacles—then explain how you’ll overcome them</li>
<li class="">Present evidence that you’re not just blowing hot air</li>
</ol>
</blockquote>
<p>If you are really interested in brushing up your presentations, go read that
piece. It’s only a 5-minute read.</p>
<p>I also like to share this <a href="https://www.youtube.com/watch?v=5pFI9UuC_fc&amp;t=2s" target="_blank" rel="noopener noreferrer" class="">video series</a> on YouTube featuring Ira Glass
from <a href="https://www.thisamericanlife.org/podcast" target="_blank" rel="noopener noreferrer" class="">This American Life</a> where he talks about creating compelling
storylines using anecdotes and a series of actions and questions.</p>
<p>I’m certainly no presentation expert (far from it), but by just applying what
I’ve learnt from the Raskin article and Glass videos, I do think that my works
have improved from what they were before.</p>
<p>I hope they will do the same for you. Share your thoughts with me in the
comments below or on Twitter <a href="https://twitter.com/chuacheehow" target="_blank" rel="noopener noreferrer" class="">@chuacheehow</a></p>
<p>(Also posted on
<a href="http://medium.com/@cheehow_c/effective-presentations-part-2-of-2-8f212fae17a7" target="_blank" rel="noopener noreferrer" class="">Medium</a>
and <a href="https://www.linkedin.com/pulse/effective-presentations-part-2-chee-how-chua" target="_blank" rel="noopener noreferrer" class="">LinkedIn</a>)</p>]]></content:encoded>
            <category>presentation</category>
            <category>public speaking</category>
        </item>
        <item>
            <title><![CDATA[Effective Presentations - Part 1 of 2]]></title>
            <link>https://www.cheehow.dev/blog/2017/02/06/effective-presentations-part-1-of-2/</link>
            <guid>https://www.cheehow.dev/blog/2017/02/06/effective-presentations-part-1-of-2/</guid>
            <pubDate>Mon, 06 Feb 2017 00:00:00 GMT</pubDate>
            <description><![CDATA[I’m always looking for ways to improve my presentations. Oftentimes, I only get one chance to get my point across and I want to make every such opportunity count.]]></description>
            <content:encoded><![CDATA[<figure><img src="https://www.cheehow.dev/assets/images/kx4mm3znzbc-chuttersnap-55f6b354f9dd3e9d7a8608e67014e9db.jpg" alt=""><figcaption>Photo credit: <a href="https://unsplash.com/photos/Kx4Mm3ZnZBc" target="_blank">Unsplash</a></figcaption></figure>
<p>I’m always looking for ways to improve my presentations. Oftentimes, I only
get one chance to get my point across and I want to make every such
opportunity count.</p>
<p>I had once thought that the key to well done presentations is a slick,
animated slideshow with concise key points. Now I know better. What you use
as the visual material is secondary to <em>what you are saying</em> and <em>how you say
it</em>.</p>
<p>I would attribute the “how you say it” to the command and fluency of the
language that you are presenting in. This has to do with the richness of your
vocabulary and the structure of the sentences that you articulate during the
presentation. Your language skills, like any other skills, can only be
improved through repeated practice. So there’s that.</p>
<p>“What you say” though are the contents of your presentation. Some might argue
that how you say it is more important then what you say. That argument, I
think, is probably only true for the very few speakers who seem to naturally
exude such charisma that can charm the masses. Needless to say, that is
certainly not an attribute that the large majority of us can emulate.</p>
<p>Contents, however, are highly malleable. They are the one thing in the
presentation that you can change with ease. What is not as easy is to know
<em>what</em> to change it to.</p>
<p>We all want an easy-to-apply formula that we can use on our presentation decks
right now while we polish up our language skills and vocabulary gradually.
But does such a formula exist? If so, it sounds too good to be true, isn’t
it?</p>
<p>What if there is such a thing? And that it is the same formula that
differentiates an A-grade movie from a B-grade one.</p>
<p>If you feel that all the presentations that you have ever done in your life
are, how should I say, <em>lacklustre</em>, then you can probably see a great
improvement in your slide decks simply by applying this formula. I know that
it works for me.</p>
<p>Like any good show, I am going to leave this post on a cliff-hanger and come
back with the second and final part of this article next time.</p>
<p>(Also posted on
<a href="https://medium.com/@cheehow_c/effective-presentations-part-1-of-2-962b1b421a1c#.bvuvu4nva" target="_blank" rel="noopener noreferrer" class="">Medium</a>
and <a href="https://www.linkedin.com/pulse/effective-presentations-part-1-2-chee-how-chua" target="_blank" rel="noopener noreferrer" class="">LinkedIn</a>)</p>]]></content:encoded>
            <category>presentation</category>
            <category>public speaking</category>
        </item>
        <item>
            <title><![CDATA[A Lesson from Twitter]]></title>
            <link>https://www.cheehow.dev/blog/2016/12/21/a-lesson-from-twitter/</link>
            <guid>https://www.cheehow.dev/blog/2016/12/21/a-lesson-from-twitter/</guid>
            <pubDate>Wed, 21 Dec 2016 00:00:00 GMT</pubDate>
            <description><![CDATA[<img src=]]></description>
            <content:encoded><![CDATA[<figure><img src="https://www.cheehow.dev/assets/images/haipj8pyel8-freestocks-org-a94a3297d2e615ab7a6c7d534720aedc.jpg" alt=""><figcaption>Photo credit: <a href="https://unsplash.com/photos/HAIPJ8PyeL8" target="_blank"></a><a href="https://unsplash.com/photos/HAIPJ8PyeL8" target="_blank" rel="noopener noreferrer" class="">https://unsplash.com/photos/HAIPJ8PyeL8</a></figcaption></figure>
<p>Several months back I was addicted to Twitter. Any time I can pull out my
phone, I would be checking my Twitter feed.</p>
<p>It's a time waster. Prolific YouTuber <a href="https://en.wikipedia.org/wiki/Derek_Muller">Dr Derek Muller</a>
describes it as a part of the <a href="https://www.youtube.com/watch?v=iYYuiWP0IpA">distraction economy</a>.</p>
<p>I had even gone to the extent of checking for more updates when I had finished
everything in my feed. What was the use of that? Is there anything to gain
from all that time spent reading little messages from strangers?</p>
<p>Given that each message is at most 140 characters, surely Twitter's only value
is for newsy stuff right? Well, that's mostly true but every now and then, you
can find a gem of wisdom among the stream of ramblings.</p>
<p>And found one I did. I don't remember the exact wording but the gist revolves
around these two sentences:</p>
<blockquote>
<p>"Why is this job important?"</p>
<p>"What you will learn in this job."</p>
</blockquote>
<p>This was posted by someone who was in the position of hiring (programmers I
think). He found that by including these two points in a job advertisement, it
helped to attract more quality candidates than not.</p>
<p>After parsing through the sentences, I can see why. The first point "What is
this job important?" probably does not make sense to a lot of people why it
would help. The second point "What you will learn in this job." is probably
more obvious. Clearly it speaks to people who want to learn more. Beyond that
though, if we delve a little deeper into the characteristics of the people who
place emphasis on it, we can easily see that these are people who want and
desire to acquire new knowledge.</p>
<p>Naturally, if I were to infer another characteristic that makes such a person
perpetually curious, it would be interest, or for some, passion. Only when you
have interest/passion in a job, would you be always keen to learn more. And a
person who is interested/passionate can be counted on to complete the tasks
satisfactorily, not necessarily to the supervisor but simply to herself.</p>
<p>What about the first point? What can we infer from it?</p>
<p>A disassociated worker likely doesn't give a damn about why the job is
important. I can think of two traits in an individual who <em>does</em> give a damn.</p>
<p>One is the ability to think at a higher level, "see the big picture", and
understand and appreciate the role that she is playing in the organization for
the job that she is doing.</p>
<p>The other is an innate desire for self actualization. For some people, the
knowledge that one has a significant role to play in the company provides the
extra motivation to work hard. I think that's probably the reason why some
people stay behind after office hours to complete the task at hand
whereas others adopt a "couldn't care less" attitude in the office.</p>
<p>Simply adding these two points in the job advertisement will not magically
filter out the dispassionate candidates, but you can leverage these two points
during the interview to "suss" out these hidden personality traits in the
candidates.</p>
<p>If you are in a position of hiring, try this out the next time a position is
available and see if it works for you.</p>]]></content:encoded>
            <category>twitter</category>
            <category>hiring</category>
        </item>
        <item>
            <title><![CDATA[A little lesson on binding]]></title>
            <link>https://www.cheehow.dev/blog/2016/09/28/a-little-lesson-on-binding/</link>
            <guid>https://www.cheehow.dev/blog/2016/09/28/a-little-lesson-on-binding/</guid>
            <pubDate>Wed, 28 Sep 2016 00:00:00 GMT</pubDate>
            <description><![CDATA[I've been writing JavaScript for the past 10 years for my work, and there are]]></description>
            <content:encoded><![CDATA[<p>I've been writing JavaScript for the past 10 years for my work, and there are
still things in the language that trips me up. A very good example is on binding.</p>
<p>Given the setup below, I would have been a <em>little</em> hesitant as to what the
right answer is.</p>
<div class="language-JavaScript language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:#d73a49">Alpha</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'A'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">Alpha</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">prototype</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method-variable function-variable method function property-access" style="color:#d73a49">say</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:#d73a49">Beta</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'B'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">Beta</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">prototype</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method-variable function-variable method function property-access" style="color:#d73a49">say</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'G'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">say</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">echo</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">action</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">action</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">a </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Alpha</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">b </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Beta</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">a</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">say</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// returns A</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">b</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">say</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// returns B</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">say</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// returns G</span><br></span></code></pre></div></div>
<p>Nothing fancy up to this point. But the next 2 lines will make me think a bit.</p>
<div class="language-JavaScript language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">echo</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">a</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">say</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Output: 'G'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">echo</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">a</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">say</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">bind</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">a</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Output: 'A'</span><br></span></code></pre></div></div>
<p>This next part is the kicker.</p>
<div class="language-JavaScript language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:#d73a49">Delta</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'D'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">say</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">say</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">bind</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">Delta</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">prototype</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method-variable function-variable method function property-access" style="color:#d73a49">say</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">d </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Delta</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">d</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">say</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">echo</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">d</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">say</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>What do you think the output is?</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="answer">ANSWER<a href="https://www.cheehow.dev/blog/2016/09/28/a-little-lesson-on-binding/#answer" class="hash-link" aria-label="Direct link to ANSWER" title="Direct link to ANSWER" translate="no">​</a></h3>
<p>Both lines output "D".</p>
<p>This example shows that there is a case for early binding even on prototype
methods.</p>]]></content:encoded>
            <category>basics</category>
            <category>javascript</category>
            <category>programming</category>
            <category>binding</category>
        </item>
        <item>
            <title><![CDATA[LG has won me over]]></title>
            <link>https://www.cheehow.dev/blog/2016/09/15/lg-has-won-me-over/</link>
            <guid>https://www.cheehow.dev/blog/2016/09/15/lg-has-won-me-over/</guid>
            <pubDate>Thu, 15 Sep 2016 00:00:00 GMT</pubDate>
            <description><![CDATA[About a year ago, I bought my wife and I a new phone for each of us. For her]]></description>
            <content:encoded><![CDATA[<p>About a year ago, I bought my wife and I a new phone for each of us. For her
it was a Galaxy Note 5. For me, I got a LG G4.</p>
<p>At that point in time, the G4 was considered slightly below par compared to
the Note 5, in terms of price and branding. I had aimed for a V10 but there
was completely no news about it being available in Singapore.</p>
<p>Despite being a flagship phone for Samsung, there were plenty of reasons for
not choosing the Note 5 then - the <a href="https://www.google.com.sg/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;source=web&amp;cd=6&amp;cad=rja&amp;uact=8&amp;ved=0ahUKEwjj5eXgwJHPAhVGoJQKHT-qCO8QFgg6MAU&amp;url=http%3A%2F%2Fwww.theverge.com%2F2016%2F1%2F19%2F10789208%2Fsamsung-note-5-stylus-fix&amp;usg=AFQjCNE79xIR20GNeloNmKXj8cAM7XA1ww" target="_blank" rel="noopener noreferrer" class="">stylus
problem</a>,
the non-removable battery and the lack of external storage. I had no regrets
not selecting the Note 5.</p>
<p>Notwithstanding all the shortcomings, I had a more pragmatic reason for
choosing the G4 over the Note 5 though - price. To me, it was that I did not
think that the Note 5 was worth the extra money over the G4; all the features
that the phone touted (and the Samsung branding) were not worth the premium
over the G4.</p>
<p>Now, my stance is more opinionated - I think the support for LG is simply
better than the Samsung. In the time between my wife getting her Note 5 to her
first OS upgrade from Android 5.1 to Android 6, I had already gotten three
updates. My G4 was revved up to Android M months before her Note 5 was
upgraded. My G4 also got another update recently, though I'm not sure what the
upgrade was - my assumption is that it is for some security patches.</p>
<p>Regardless of the reason for the latest update, the fact that LG has provided
more frequent updates than Samsung has (for its flagship phone no less) is
enough reason for me to not choose Samsung phones again.</p>
<p>P.S. I had <em>begun</em> writing this article before the <a href="https://www.google.com.sg/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;source=web&amp;cd=1&amp;cad=rja&amp;uact=8&amp;ved=0ahUKEwjova-VwpHPAhUFlZQKHUhOBlQQqQIIHTAA&amp;url=https%3A%2F%2Fwww.cnet.com%2Fnews%2Fwhy-is-samsung-galaxy-note-7-exploding-overheating%2F&amp;usg=AFQjCNHlQSxAuGD-5Kb_oAKwAAZECOsS2g" target="_blank" rel="noopener noreferrer" class="">Note 7 battery
problems</a>
surfaced so the battery problem wasn't the genesis for my opinion.</p>]]></content:encoded>
            <category>android</category>
            <category>lg</category>
            <category>samsung</category>
            <category>g4</category>
            <category>note5</category>
        </item>
        <item>
            <title><![CDATA[Installing Disqus]]></title>
            <link>https://www.cheehow.dev/blog/2016/07/19/installing-disqus/</link>
            <guid>https://www.cheehow.dev/blog/2016/07/19/installing-disqus/</guid>
            <pubDate>Tue, 19 Jul 2016 00:00:00 GMT</pubDate>
            <description><![CDATA[So I've gotten around to installing Disqus for this blog. This post is just a]]></description>
            <content:encoded><![CDATA[<p>So I've gotten around to installing Disqus for this blog. This post is just a
test post for testing the commenting system.</p>
<p>(2023 February note: Disqus was not enabled after the switch to <a href="https://docusaurus.io/" target="_blank" rel="noopener noreferrer" class="">Docusaurus</a>)</p>]]></content:encoded>
            <category>disqus</category>
        </item>
    </channel>
</rss>