<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Olivia Coumans&#39; Blog</title>
  <subtitle>Olivia Coumans&#39; site</subtitle>
  <link href="https://oliviac.dev/feed.xml" rel="self" />
  <link href="https://oliviac.dev" />
  <description>Recent content on Olivia Coumans&#39; blog</description>
  <updated>2026-02-27T00:00:00Z</updated>
  <id>https://oliviac.dev</id>
  <author>
    <name>Olivia Coumans</name>
    <email>livie7c@gmail.com</email>
  </author> 
  <entry>
    <title>Using Vim with VSCode</title>
    <link href="
  https://oliviac.dev/blog/vim-with-vscode/
  " />
    <updated>2022-01-03T00:00:00Z</updated>
    <id>
  https://oliviac.dev/blog/vim-with-vscode/
  </id>
    <content
      type="html"
      >&lt;p&gt;In this post, I’ll share tips on using the Vim plugin in VSCode. It’s an excellent way to explore a different editing style and get a feel for Vim without leaving your current setup. The plugin provides access to Vim’s modes and motions with minimal configuration.&lt;/p&gt;
&lt;p&gt;I originally started using Vim to rely less on my mouse, and it’s made a huge difference. These days, I regularly switch between VSCode (with the Vim plugin) and Neovim, and having Vim baked into my daily workflow makes that back-and-forth feel seamless. Plus, editing with Vim is fun! If you&#39;re considering trying it, let’s dive in.&lt;/p&gt;
&lt;h2 id=&quot;installation&quot; tabindex=&quot;-1&quot;&gt;Installation&lt;/h2&gt;
&lt;p&gt;First, install the plugin &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=vscodevim.vim&quot;&gt;Vim&lt;/a&gt;. Once you relaunch your code editor and open a file, you’ll see &lt;code&gt;NORMAL&lt;/code&gt; in the bottom bar - one of Vim’s modes. Your cursor will also look a bit different.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://oliviac.dev/img/vscode_status_bar_vim_mode.png&quot; alt=&quot;Zoomed-in view of a VSCode status bar with the Vim plugin activated. The current Git branch is displayed, along with a cross icon and a warning triangle icon, showing a zero count. The &amp;quot;NORMAL&amp;quot; Vim mode is highlighted with a marker, making it clear where it appears in the status bar.&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;remember-vim-and-its-modes&quot; tabindex=&quot;-1&quot;&gt;Remember Vim and its modes&lt;/h2&gt;
&lt;p&gt;Vim has several modes, each with its keyboard shortcuts and motions. The four most common are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Normal mode&lt;/strong&gt; (also called &amp;quot;Command mode&amp;quot;): This is the mode you&#39;ll use most of the time. In Normal mode, you can navigate your file with commands like &lt;code&gt;g&lt;/code&gt; and &lt;code&gt;gg&lt;/code&gt;, search for text (e.g., &lt;code&gt;/Gary&lt;/code&gt; to search for that name), and more.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Insert mode&lt;/strong&gt;: This is where you write text. To enter Insert mode, press &lt;code&gt;i&lt;/code&gt;. You’ll use this mode whenever you want to add or modify code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Visual mode&lt;/strong&gt;: This mode is the equivalent of selecting text with your mouse. To enter Visual mode, press &lt;code&gt;v&lt;/code&gt;. You can select an entire line by pressing &lt;code&gt;V&lt;/code&gt; while in Visual mode.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Last line mode&lt;/strong&gt;: Access this mode by pressing &lt;code&gt;:&lt;/code&gt;. It allows you to run commands like opening a file (&lt;code&gt;:e&lt;/code&gt; filename), saving a file (&lt;code&gt;:w&lt;/code&gt;), and exiting Vim (&lt;code&gt;:q&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;learning-vim&quot; tabindex=&quot;-1&quot;&gt;Learning vim&lt;/h2&gt;
&lt;p&gt;If you&#39;re new to Vim, &lt;code&gt;vimtutor&lt;/code&gt; is an excellent resource to get started. It’s an interactive tutorial that covers the basics and helps you become comfortable with the editor. Once Vim is installed on your computer, you can access the tutorial anytime by typing &lt;code&gt;vimtutor&lt;/code&gt; in your terminal.&lt;/p&gt;
&lt;p&gt;Additionally, I highly recommend this &lt;a href=&quot;https://www.youtube.com/playlist?list=PLm323Lc7iSW_wuxqmKx_xxNtJC_hJbQ7R&quot;&gt;Youtube playlist&lt;/a&gt; by the Primeagen. This series of videos provides practical insights and tips to help you get comfortable with Vim more quickly.&lt;/p&gt;
&lt;h2 id=&quot;basic-settings&quot; tabindex=&quot;-1&quot;&gt;Basic settings&lt;/h2&gt;
&lt;p&gt;Now that you have Vim installed and running, let’s configure it to fit your workflow. To improve your Vim experience, you can customize a range of settings, like the leader key or enabling relative line numbers.&lt;/p&gt;
&lt;p&gt;In traditional Vim, you configure Vim settings in a &lt;code&gt;vimrc&lt;/code&gt; file, where you define key mappings, plugins, and various preferences. In VSCode, you can enable a similar setup using the &lt;code&gt;vim.vimrc.enable&lt;/code&gt; setting, which allows you to use a vimrc file to configure your Vim plugin. However, I prefer configuring Vim settings directly within VSCode’s settings.json, as it feels more integrated with the VSCode environment.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;leader key&lt;/strong&gt; in Vim is combined with other keys to create custom keyboard shortcuts, especially in normal mode. As you get more comfortable, you’ll likely create &amp;quot;remaps”, shortcuts for common actions like toggling the sidebar or quickly switching between files.&lt;/p&gt;
&lt;p&gt;In VSCode, you can define your shortcuts and pick a leader key, with &lt;code&gt;,&lt;/code&gt; and &lt;code&gt;space&lt;/code&gt; being popular choices. Feel free to experiment and see what works best for you.&lt;/p&gt;
&lt;p&gt;Here’s how I configure my Vim settings in &lt;code&gt;settings.json&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// settings.json&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;vim.leader&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot; &quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;vim.hlsearch&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;vim.useSystemClipboard&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;vim.smartRelativeLine&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;quot;vim.leader&amp;quot;: &amp;quot; &amp;quot;,&lt;/code&gt;: Sets the spacebar as my leader key, which triggers custom keyboard shortcuts.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vim.hlsearch&lt;/code&gt;: Highlights search results when you search with &lt;code&gt;/&lt;/code&gt; in normal mode, making it easier to spot matches.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vim.useSystemClipboard&lt;/code&gt; Ensures you can copy and paste between Vim and your system clipboard (no need to use extra commands like &lt;code&gt;*y&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vim.smartRelativeLine&lt;/code&gt;: Displays the current line number and other line numbers relative to your position. This speeds up navigation and makes it easier to jump between lines. For example, &lt;code&gt;2k&lt;/code&gt; will take you two lines up from where you are. This one was a life-changer for me!&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;creating-custom-shortcuts&quot; tabindex=&quot;-1&quot;&gt;Creating custom shortcuts&lt;/h2&gt;
&lt;p&gt;Remaps are the secret sauce when using Vim as your primary code editor. They allow you to associate the actions you often perform with keyboard shortcuts. In VSCode, you can add custom shortcuts in your &lt;code&gt;settings.json&lt;/code&gt;. The Vim plugin allows you to add custom keybindings per mode:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;vim.normalModeKeyBindingsNonRecursive&lt;/strong&gt;: Custom keybindings for Normal mode.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;vim.visualModeKeyBindingsNonRecursive&lt;/strong&gt;: Custom keybindings for Visual mode.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;vim.insertModeKeyBindingsNonRecursive&lt;/strong&gt;: Custom keybindings for Insert mode (I don’t use this, but it&#39;s available).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here are some of my shortcuts:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;vim.normalModeKeyBindingsNonRecursive&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;before&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&amp;lt;leader&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;commands&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;workbench.action.toggleSidebarVisibility&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;before&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&amp;lt;leader&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;r&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;r&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;commands&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;editor.action.rename&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;before&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;K&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;commands&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;editor.action.showHover&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;before&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&amp;lt;leader&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;r&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;f&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;commands&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;fileutils.renameFile&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;before&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&amp;lt;leader&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;p&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;s&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;commands&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;fuzzySearch.activeTextEditor&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;breaking-down-the-commands&quot; tabindex=&quot;-1&quot;&gt;Breaking down the commands&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;before&lt;/code&gt;: This is the key combination you press to trigger the action. Each key combination is an array of keys you press in sequence. For example, &lt;code&gt;&amp;lt;leader&amp;gt; + n&lt;/code&gt; means pressing the leader key followed by the letter n.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;commands&lt;/code&gt;: These are predefined VSCode actions or commands triggered by your custom keybinding. You can assign these to do anything from toggling visibility to renaming files.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For example, I use the &lt;code&gt;rename&lt;/code&gt; action quite a lot. It is usually triggered by &lt;code&gt;F2&lt;/code&gt;, but I found that shortcut awkward. So, I created a custom shortcut with &lt;code&gt;&amp;lt;leader&amp;gt; + r + r&lt;/code&gt; that feels more comfortable and matches a keymap I have in Neovim.&lt;/p&gt;
&lt;h3 id=&quot;a-few-favorite-custom-keymaps&quot; tabindex=&quot;-1&quot;&gt;A few favorite custom keymaps&lt;/h3&gt;
&lt;p&gt;In my &lt;code&gt;settings.json&lt;/code&gt;, I have a few favorite keymaps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Toggle Sidebar visibility&lt;/strong&gt;: &lt;code&gt;&amp;lt;leader&amp;gt; + n&lt;/code&gt; toggles the sidebar visibility. I use this one quite often.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rename&lt;/strong&gt;: &lt;code&gt;&amp;lt;leader&amp;gt; + r + r&lt;/code&gt; saves me some time since I don&#39;t often use the function key.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Show Hover information&lt;/strong&gt;: &lt;code&gt;K&lt;/code&gt; shows detailed hover information for a function or variable. This is the keyboard equivalent of hovering over a function or variable with your mouse.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;keymaps-using-extension-capabilities&quot; tabindex=&quot;-1&quot;&gt;Keymaps using extension capabilities&lt;/h3&gt;
&lt;p&gt;You can get quite creative when defining your keymaps. You can leverage some extensions you&#39;ve added. For instance, I have custom keymaps for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Renaming a file&lt;/strong&gt;: &lt;code&gt;&amp;lt;leader&amp;gt;+r+f&lt;/code&gt; renames the current file using the &lt;a href=&quot;https://marketplace.visualstudio.com/items/?itemName=sleistner.vscode-fileutils&quot;&gt;file util extension&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fuzzy search&lt;/strong&gt;: &lt;code&gt;&amp;lt;leader&amp;gt; + p + s&lt;/code&gt; triggers a fuzzy search in the active text editor using the &lt;a href=&quot;https://marketplace.visualstudio.com/items/?itemName=jacobdufault.fuzzy-search&quot;&gt;fuzzy search extension&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;explore-and-customize&quot; tabindex=&quot;-1&quot;&gt;Explore and customize&lt;/h3&gt;
&lt;p&gt;It can quickly become a rabbit hole, but that&#39;s part of the beauty of using Vim. There is &lt;a href=&quot;https://code.visualstudio.com/docs/getstarted/keybindings&quot;&gt;complete documentation&lt;/a&gt; of all the existing keybindings in VSCode. A good exercise is to review the default keybindings and see if there are any you commonly use that could be further customized or improved.&lt;/p&gt;
&lt;h2 id=&quot;extending-vim-power-with-some-plugins&quot; tabindex=&quot;-1&quot;&gt;Extending Vim power with some plugins&lt;/h2&gt;
&lt;p&gt;Vim in VSCode supports several built-in Vim plugins that enhance what Vim can do.&lt;/p&gt;
&lt;p&gt;One plugin I highly recommend enabling is &lt;code&gt;vim-surround&lt;/code&gt;. It makes working with brackets, quotes, and tags much faster. You can quickly change or delete surrounding characters with just a few keystrokes.&lt;/p&gt;
&lt;p&gt;To enable it, go to your settings and search for &lt;code&gt;Vim: Surround&lt;/code&gt;. You&#39;ll see a checkbox to turn it on.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://oliviac.dev/img/vim-surround-plugin-vscode.png&quot; alt=&quot;Settings menu open in VSCode. &amp;quot;vim surround&amp;quot; is entered in the search input. There are three settings found. The first is a checkbox to enable the Surround plugin for Vim. The second result is an option to customize the Status Bar color in surround input mode. The third setting is to include surrounded spaces. Both the first and the third checkbox are checked.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Once enabled, here are a few examples of what you can do while in normal mode:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Change single quotes to double quotes: &lt;code&gt;cs&#39;&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Rename an HTML tag: &lt;code&gt;cst&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&#39;s a small plugin, but once you get used to it, it&#39;ll feel like a must-have! You can check out more examples in the &lt;a href=&quot;https://github.com/tpope/vim-surround&quot;&gt;official documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;some-of-my-favorite-vim-motions&quot; tabindex=&quot;-1&quot;&gt;Some of my favorite Vim motions&lt;/h2&gt;
&lt;p&gt;One of the first big challenges when getting started with Vim is to try to stay in Normal mode as much as possible. This is the key to becoming fast and efficient with Vim.&lt;/p&gt;
&lt;p&gt;Here are some of my go-to motions in Normal mode:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;gg&lt;/code&gt;: Jump to the top of the file&lt;/li&gt;
&lt;li&gt;&lt;code&gt;G&lt;/code&gt;: Jump to the bottom of the file&lt;/li&gt;
&lt;li&gt;&lt;code&gt;f&lt;/code&gt; and &lt;code&gt;F&lt;/code&gt;: Move to a specific character on the current line (f searches forward, F searches backward). For instance, in the line Hello there, typing &lt;code&gt;ft&lt;/code&gt; from the start of the line moves your cursor to the &lt;code&gt;t&lt;/code&gt; in there.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;zz&lt;/code&gt;: Center the current line in the viewport&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0w&lt;/code&gt;: If you&#39;re mid-line or at the end, this brings you back to the start of the line, then moves to the first word&lt;/li&gt;
&lt;li&gt;&lt;code&gt;D&lt;/code&gt;: Delete everything from your cursor to the end of the line&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dd&lt;/code&gt;: Delete the entire line&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cc&lt;/code&gt;: Delete the line and immediately enter Insert mode on the same line&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;number&amp;gt;k&lt;/code&gt; or &lt;code&gt;&amp;lt;number&amp;gt;j&lt;/code&gt;: Move up or down multiple lines&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cit&lt;/code&gt;: When editing HTML, this puts you into Insert mode inside a tag and deletes the existing content (Small warning: this is very powerful but will remove any current content inside the tag!)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;u&lt;/code&gt;: Undo your last action (a lifesaver when things don&#39;t go as expected...)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Getting used to these motions can be a mental workout at first. However, with practice, they quickly become second nature!&lt;/p&gt;
&lt;p&gt;Vim also supports text objects, which makes it easy to edit things like words, quotes, or parentheses, no matter where your cursor is inside them. For example, &lt;code&gt;ci&amp;quot;&lt;/code&gt; changes everything inside quotes, and &lt;code&gt;da(&lt;/code&gt; deletes everything around a set of parentheses. It takes some time to get the hang of it, but once you do, the benefits of using Vim become clear!&lt;/p&gt;
&lt;h2 id=&quot;bonus%3A-moving-a-code-block-up-or-down-in-visual-mode&quot; tabindex=&quot;-1&quot;&gt;Bonus: moving a code block up or down in visual mode&lt;/h2&gt;
&lt;p&gt;I remember watching a React presentation by Ryan Florence, where I first saw this trick. During the talk, he highlighted a code block in visual mode and moved it up and down without cutting and pasting. If you want to do the same in VSCode with Vim, add these to your &lt;code&gt;settings.json&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;vim.visualModeKeyBindings&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;before&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;J&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;commands&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;editor.action.moveLinesDownAction&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;before&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;K&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;commands&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;editor.action.moveLinesUpAction&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, you can select a block of code in visual mode and move it up with &lt;code&gt;K&lt;/code&gt; or down with &lt;code&gt;J&lt;/code&gt;. Awesome stuff!&lt;/p&gt;
&lt;h2 id=&quot;conclusion-and-further-resources&quot; tabindex=&quot;-1&quot;&gt;Conclusion and further resources&lt;/h2&gt;
&lt;p&gt;If you&#39;re interested in testing out Vim, the plugin in VSCode is a great place to start. Once you&#39;re more comfortable with the basics, there are many resources to help you dive deeper into the Vim world:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://vimtricks.com/&quot;&gt;VimTricks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/c/ThePrimeagen&quot;&gt;ThePrimeagen YouTube channel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://changelog.com/podcast&quot;&gt;Changelog&lt;/a&gt; has some great podcast episodes about vim&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My current VSCode settings and keymaps are in my &lt;a href=&quot;https://github.com/liv7c/dotfiles/blob/main/vscode/settings.json&quot;&gt;dotfiles&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And if you&#39;re curious about trying out Neovim, I have a &lt;a href=&quot;https://github.com/liv7c/nvim-config&quot;&gt;repo with my current Neovim config&lt;/a&gt;, which will continue to evolve.&lt;/p&gt;
&lt;p&gt;I hope you find this blog post helpful. If you have any questions or want to chat about Vim, feel free to reach out on &lt;a href=&quot;https://bsky.app/profile/oliviac.dev&quot;&gt;Bluesky&lt;/a&gt; 😀&lt;/p&gt;
</content
    >
  </entry> 
  <entry>
    <title>Search for a string in your git history with git log</title>
    <link href="
  https://oliviac.dev/blog/search-for-string-with-git-log/
  " />
    <updated>2022-01-07T00:00:00Z</updated>
    <id>
  https://oliviac.dev/blog/search-for-string-with-git-log/
  </id>
    <content
      type="html"
      >&lt;p&gt;Recently, I discovered a useful functionality of &lt;code&gt;git log&lt;/code&gt; while cleaning up some code. You can pass an option to &lt;code&gt;git log&lt;/code&gt; to get back a list of all the commits that changed a particular string. Let&#39;s explore that feature!&lt;/p&gt;
&lt;h2 id=&quot;using-git-log--s&quot; tabindex=&quot;-1&quot;&gt;Using &lt;code&gt;git log -S&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;If you want to find all the occurrences of a specific string in your git history, &lt;code&gt;git log -S&lt;/code&gt; is perfect for the job.&lt;/p&gt;
&lt;p&gt;For example, if you look for a particular component in a React app, you can type:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; log &lt;span class=&quot;token parameter variable&quot;&gt;-S&lt;/span&gt; ContentWrapper&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It will return a list of all the commits where that string appears:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;commit ab68707f03a5636c399213194a32c29d631e7c2b
Author: Olivia Coumans &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;my_email@email.com&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
Date:   Tue Jan &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;11&lt;/span&gt;:03:34 &lt;span class=&quot;token number&quot;&gt;2022&lt;/span&gt; +0100
  feat&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;styles&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;: create PageContentWrapper comp

commit 5e79c7fa417c5a58b7b6c6bfb71de318686a6210
Author: Olivia Coumans &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;my_email@email.com&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
Date:   Thu Dec &lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;:57:15 &lt;span class=&quot;token number&quot;&gt;2021&lt;/span&gt; +0100
  feat&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;footer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;: &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; site footer&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can then use &lt;code&gt;git show [COMMIT_HASH]&lt;/code&gt; to display the content of a commit with all the diffs.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; show ab68707&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;bonus%3A-list-all-the-commits-that-modified-a-file&quot; tabindex=&quot;-1&quot;&gt;Bonus: list all the commits that modified a file&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;git log -p FILE_PATH&lt;/code&gt; is a quick way to list all the commits that modified a specific file.&lt;/p&gt;
&lt;p&gt;Don&#39;t hesitate to pass flags to customize the output of &lt;code&gt;git log&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; log --name-only &lt;span class=&quot;token parameter variable&quot;&gt;--oneline&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; ./components/SiteHeader/SiteHeader.tsx&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above example will only display the hash and the name of each commit that modified the file.&lt;/p&gt;
&lt;h2 id=&quot;conclusion-and-further-resources&quot; tabindex=&quot;-1&quot;&gt;Conclusion and further resources&lt;/h2&gt;
&lt;p&gt;With &lt;code&gt;git log&lt;/code&gt; and some of its options, you can quickly find out when some piece of code was removed or added while staying in your terminal. I hope it will be helpful for you too!&lt;/p&gt;
&lt;p&gt;Some further resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://git-scm.com/docs/git-log#Documentation/git-log.txt--Sltstringgt&quot;&gt;Git documentation on git log -S&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.git-scm.com/docs/git-log&quot;&gt;Git documentation on git-log&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content
    >
  </entry> 
  <entry>
    <title>Exploring generics and generic constraints in TypeScript</title>
    <link href="
  https://oliviac.dev/blog/exploring-generics-and-generic-constraints/
  " />
    <updated>2022-01-14T00:00:00Z</updated>
    <id>
  https://oliviac.dev/blog/exploring-generics-and-generic-constraints/
  </id>
    <content
      type="html"
      >&lt;p&gt;Generics can be hard to grasp when first learning TypeScript. This post will review what generics are and why we use them. We&#39;ll then move on to explore generic constraints. They are a handy trick to keep in mind to build more type-safe code.&lt;/p&gt;
&lt;h2 id=&quot;generics-as-a-superpower-to-build-reusable-code&quot; tabindex=&quot;-1&quot;&gt;Generics as a superpower to build reusable code&lt;/h2&gt;
&lt;p&gt;The whole idea behind generics is to write functions or data structures that can work with many different types depending on the context.&lt;/p&gt;
&lt;p&gt;The most common example to introduce generics is the &lt;code&gt;identity&lt;/code&gt; function. The sole goal of this function is to return the argument it receives.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;identify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you have &lt;code&gt;strict&lt;/code&gt; enabled in your &lt;code&gt;tsconfig&lt;/code&gt;,  the code above will cause a type error. It will tell you that &lt;code&gt;value&lt;/code&gt; has the implicit type of &lt;code&gt;any&lt;/code&gt;. The first approach to fixing this issue is to make &lt;code&gt;value&lt;/code&gt; an &lt;code&gt;any&lt;/code&gt; type explicitly.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;identity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;arg&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; arg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One problem with this approach is that you lose all type safety. By making &lt;code&gt;value&lt;/code&gt; a type of &lt;code&gt;any&lt;/code&gt;, the return value of &lt;code&gt;identity&lt;/code&gt; will also be of type &lt;code&gt;any&lt;/code&gt;. If you store it in a variable, this variable will also be of type &lt;code&gt;any&lt;/code&gt;, which could cause some type errors.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;identify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Lisa&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// name will be of type `any`&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; total&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// would not throw a type error&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We want TypeScript to infer the type of the argument. That&#39;s when generics come to the rescue.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;identity&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;arg&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; arg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;identity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Lisa&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// will infer that T = string&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// identity&amp;lt;string&gt;(&quot;Lisa&quot;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can think of a generic as a placeholder or a variable that TypeScript will fill with the correct type information later. In this example, when you invoke &lt;code&gt;identity&lt;/code&gt;, TypeScript will fill the blanks and replace the generic &lt;code&gt;T&lt;/code&gt; with a concrete type (&lt;code&gt;string&lt;/code&gt; in the case of the example).&lt;/p&gt;
&lt;h2 id=&quot;a-real-life-example-of-generics&quot; tabindex=&quot;-1&quot;&gt;A real-life example of generics&lt;/h2&gt;
&lt;p&gt;Let&#39;s imagine we want to build a helper function to get the difference between two arrays. Some criteria for our helper function:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We want this function to be reusable with all arrays, no matter what elements they contain.&lt;/li&gt;
&lt;li&gt;We want to make sure that both arrays contain the same type of elements.&lt;/li&gt;
&lt;li&gt;We want to pass a function &lt;code&gt;filterFn&lt;/code&gt; that we can use to filter the lists.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;getArrayDifference&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  prevList&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  currList&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;filterFn&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;el&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; list&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;boolean&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; removedElements &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; prevList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;el &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;filterFn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;el&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; currList&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; addedElements &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; currList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;el &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;filterFn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;el&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; prevList&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;removedElements&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;addedElements&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&#39;s try this function. Let&#39;s imagine we want to use it to get the difference between two lists of tags.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Tag&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; prevTags &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;TypeScript&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Svelte&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; currTags &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;TypeScript&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;tagFilterFn&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tag&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Tag&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; listOfTags&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Tag&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; listOfTags&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findIndex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;el &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; el&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; tag&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; diff &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getArrayDifference&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;prevTags&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; currTags&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; tagFilterFn&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// TypeScript replaces T with Tag&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// getArrayDifference&amp;lt;Tag&gt;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// we get back [{id: 2,  name: &quot;Svelte&quot;}]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;If you inspect the &lt;code&gt;getArrayDifference&lt;/code&gt; in this example, you will see that TypeScript considers &lt;code&gt;T&lt;/code&gt; to be &lt;code&gt;Tag&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It returns a list of Tag. &lt;code&gt;diff&lt;/code&gt; will be of type &lt;code&gt;Tag[]&lt;/code&gt;. If we had used &lt;code&gt;any&lt;/code&gt; in our helper function definition, &lt;code&gt;diff&lt;/code&gt; would have been of type &lt;code&gt;any&lt;/code&gt; as well, and we would have lost all the advantages of using TypeScript.&lt;/li&gt;
&lt;li&gt;Thanks to generics, we also have some type safety for our &lt;code&gt;filterFn&lt;/code&gt;. In the above example, its first argument must be of type &lt;code&gt;Tag&lt;/code&gt;, and its second argument must be a list of tags.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Generics make our function type-safe and reusable with other types. We could use our helper with arrays of numbers.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; otherDiff &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getArrayDifference&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;curr&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; list&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;list&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;curr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// T = number&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// returns [1]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that we are well immersed in generics, let&#39;s explore generic constraints!&lt;/p&gt;
&lt;h2 id=&quot;generic-constraints-or-generics-with-limitations&quot; tabindex=&quot;-1&quot;&gt;Generic constraints or generics with limitations&lt;/h2&gt;
&lt;p&gt;The whole idea behind generic constraints is to limit the possibilities of the types a generic can represent.  Generics are like wildcards. However, we could already know that we want the type to have specific properties from the get-go. You can create a generic constraint with the &lt;code&gt;extends&lt;/code&gt; keyword. Let&#39;s have a look at some typical use-cases for generic constraints.&lt;/p&gt;
&lt;h3 id=&quot;usecase-%231%3A-you-want-to-use-a-specific-property-on-a-generic-type&quot; tabindex=&quot;-1&quot;&gt;Usecase #1: you want to use a specific property on a generic type&lt;/h3&gt;
&lt;p&gt;Let&#39;s say we want to write a function that filters a list by id and pretty-prints the result. This function should be generic because we want it to be reusable with many different types.&lt;/p&gt;
&lt;p&gt;At first, we might write something like:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;findByIdAndPrint&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;list&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token comment&quot;&gt;// The line below will cause a type error&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; itemToPrint &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; list&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;item &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;itemToPrint&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;itemToPrint&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;No item found&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This won&#39;t work. TypeScript will throw a type error &lt;code&gt;Property &amp;quot;id&amp;quot; does not exist on type &amp;quot;T&amp;quot;&lt;/code&gt;. We have to tell TypeScript that &lt;code&gt;T&lt;/code&gt; will have an &lt;code&gt;id&lt;/code&gt; property no matter what.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HasId&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// we could also inline the constraint with T extends {id: string}&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; findByIdAndPrint&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HasId&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; itemToPrint &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; list&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;item &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;itemToPrint&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;itemToPrint&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;No item found&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What does &lt;code&gt;extends&lt;/code&gt; do?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It tells TypeScript that &lt;code&gt;T&lt;/code&gt; must have a property &lt;code&gt;id&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;extends&lt;/code&gt; also means that our type &lt;code&gt;T&lt;/code&gt; is not limited to having only a property &lt;code&gt;id&lt;/code&gt; and can have many more.&lt;/li&gt;
&lt;li&gt;We constraint our generic so that this function won&#39;t work with any type without an &lt;code&gt;id&lt;/code&gt; property.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;usecase-%232%3A-create-a-relationship-between-two-generics&quot; tabindex=&quot;-1&quot;&gt;Usecase #2: Create a relationship between two generics&lt;/h3&gt;
&lt;p&gt;You might have come across the keyword &lt;code&gt;keyof&lt;/code&gt;. &lt;code&gt;keyof&lt;/code&gt; is an operator that returns a union of all the keys of an interface or type.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Person&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	age&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;PersonKeys&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;keyof&lt;/span&gt; Person &lt;span class=&quot;token comment&quot;&gt;// &#39;name&#39; | &#39;age&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;How does it relate to our generic constraint? Let&#39;s say we have a function that acts as a getter for a property on an object.&lt;/p&gt;
&lt;p&gt;Our first approach might be to just write it without any generics:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getPropertyValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;obj&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Record&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;unknown&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; obj&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Record&lt;/code&gt; is a utility type that creates an object type. The problem with this approach is that we can pass just any string as a second argument. And we might want only to allow the user to give a key that exists on the object.&lt;/p&gt;
&lt;p&gt;Generics and generic constraints to the rescue!&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;getPropertyValue&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; Record&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;unknown&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;K&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;keyof&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;obj&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;K&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; obj&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;We first constraint &lt;code&gt;T&lt;/code&gt; to tell TypeScript that this will be an object. &lt;code&gt;unknown&lt;/code&gt; is an excellent alternative to using &lt;code&gt;any&lt;/code&gt;  as it is more restrictive.&lt;/li&gt;
&lt;li&gt;We then pass a second generic &lt;code&gt;K&lt;/code&gt;. We directly limit what &lt;code&gt;K&lt;/code&gt; can represent with &lt;code&gt;extends&lt;/code&gt;. We use &lt;code&gt;keyof&lt;/code&gt; to tell TypeScript that &lt;code&gt;K&lt;/code&gt; will be a key of &lt;code&gt;T&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;getPropertyValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Ryan&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; age&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;26&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;name&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &#39;Ryan&#39;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// this code will throw a type error&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;getPropertyValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Lisa&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;country&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this case, we use generic constraints to create a relationship between two generics that, otherwise, could stand for any type and be entirely independent of one another.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this post, we explored generics and generic constraints.  We saw a few examples of how much power generics give us as typescript developers to make our code more flexible, reusable, and type-safe.&lt;/p&gt;
&lt;p&gt;Some useful resources to go deeper:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/2/generics.html&quot;&gt;TypeScript: Documentation - Generics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://exploringjs.com/tackling-ts/ch_computing-with-types-overview.html#generic-types-factories-for-types&quot;&gt;An overview of computing with types by Axel Rauschmayer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content
    >
  </entry> 
  <entry>
    <title>An overview of the unknown type in Typescript</title>
    <link href="
  https://oliviac.dev/blog/an-overview-of-unknown-typescript/
  " />
    <updated>2022-01-21T00:00:00Z</updated>
    <id>
  https://oliviac.dev/blog/an-overview-of-unknown-typescript/
  </id>
    <content
      type="html"
      >&lt;p&gt;Typescript&#39;s version 3.0 introduced a new type, &lt;code&gt;unknown&lt;/code&gt;.  Contrary to &lt;code&gt;any&lt;/code&gt;, we do not opt out entirely from the type system by assigning a type &lt;code&gt;unknown&lt;/code&gt; to a value. This blog post will explore the purpose of &lt;code&gt;unknown&lt;/code&gt; and some key differences between &lt;code&gt;unknown&lt;/code&gt; and &lt;code&gt;any&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;purpose-of-unknown&quot; tabindex=&quot;-1&quot;&gt;Purpose of unknown&lt;/h2&gt;
&lt;p&gt;The purpose of &lt;code&gt;unknown&lt;/code&gt; is similar to &lt;code&gt;any&lt;/code&gt;. It is used to represent any possible value. We might want to write a helper function that takes any possible type as an argument. Or we might not know when writing our program what type of value a particular variable will hold at runtime.&lt;/p&gt;
&lt;p&gt;It is an excellent alternative to using the infamous &lt;code&gt;any&lt;/code&gt; type. Even though it might do something similar to &lt;code&gt;any&lt;/code&gt;, they are critical differences between both. To understand those, let&#39;s first review some of the pitfalls of using &lt;code&gt;any&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-multiple-risks-of-using-any&quot; tabindex=&quot;-1&quot;&gt;The multiple risks of using &lt;code&gt;any&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;If we explicitly give an &lt;code&gt;any&lt;/code&gt; type to a value, we can then assign it to any variable, no matter their type.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ourValue&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;hello&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// we can assign it a variable supposed to contain a number&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; importantNumberVal&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ourValue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// we can assign it to a variable supposed to&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// contain an array of strings&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; listOfNames&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ourValue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This code is perfectly valid Typescript code. However, we know it will cause all sorts of errors down the line. We can also use our value typed &lt;code&gt;any&lt;/code&gt; with a function that requires a specific type of argument to work correctly.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Person&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// we could use it with a function that has a specific type signature&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;greetPerson&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;person&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Person&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Hello &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; problematicValue&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// will not throw any errors or warnings&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;greetPerson&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;problematicValue&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These two examples are only reminders that while &lt;code&gt;any&lt;/code&gt; can be very convenient, we must remember its tradeoffs too. While we gain flexibility, we give up most of the benefits of using Typescript.&lt;/p&gt;
&lt;h2 id=&quot;unknown%2C-a-type-safe-alternative-to-any&quot; tabindex=&quot;-1&quot;&gt;&lt;code&gt;unknown&lt;/code&gt;, a type-safe alternative to &lt;code&gt;any&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;unknown&lt;/code&gt; is much more restrictive than the type &lt;code&gt;any&lt;/code&gt;. Let&#39;s revisit an earlier code example, replacing &lt;code&gt;any&lt;/code&gt; with &lt;code&gt;unknown&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ourValue&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;unknown&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;hello&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// type error here&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Type &#39;unknown&#39; is not assignable to type &#39;number&#39;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; importantNumberVal&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ourValue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// another type error :)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Type &#39;unknown&#39; is not assignable to type &#39;string[]&#39;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; listOfNames&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ourValue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can no longer use &lt;code&gt;ourValue&lt;/code&gt;  in all situations. The general rule is that you can only assign a value of type &lt;code&gt;unknown&lt;/code&gt; to a variable that is &lt;code&gt;any&lt;/code&gt; or &lt;code&gt;unknown&lt;/code&gt;.
But how do we use it then?&lt;/p&gt;
&lt;h2 id=&quot;type-narrowing-to-use-a-type-unknown-value&quot; tabindex=&quot;-1&quot;&gt;Type narrowing to use a type  &lt;code&gt;unknown&lt;/code&gt; value&lt;/h2&gt;
&lt;p&gt;You can only assign a value of type &lt;code&gt;unknown&lt;/code&gt; to a variable that has the type &lt;code&gt;unknown&lt;/code&gt; or &lt;code&gt;any&lt;/code&gt;. But, in our example, our variable &lt;code&gt;importantNumberVal&lt;/code&gt; holds a &lt;code&gt;number&lt;/code&gt; type. In that case, the only solution is type narrowing. We need to do some runtime checks to use our value.&lt;/p&gt;
&lt;p&gt;If we wanted to use it to assign it to a constant that holds a number, we would need first to check that it is of type number.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ourValue&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;unknown&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;hello&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; ourValue &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;number&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;Number&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isNaN&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ourValue&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token comment&quot;&gt;// it works!&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; importantNumberVal&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ourValue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using &lt;code&gt;unknown&lt;/code&gt; means doing this extra check. It is virtually unusable until we narrow what type it is. However, in the above example, we keep our code type-safe. But, like most good things, it requires some extra work.&lt;/p&gt;
&lt;h2 id=&quot;using-unknown-to-regain-some-type-safety&quot; tabindex=&quot;-1&quot;&gt;Using &lt;code&gt;unknown&lt;/code&gt; to regain some type safety&lt;/h2&gt;
&lt;p&gt;One interesting technique is to assign a value of type &lt;code&gt;any&lt;/code&gt; to a variable of type &lt;code&gt;unknown&lt;/code&gt;. We can restrict what we can do with this value in our program this way.&lt;/p&gt;
&lt;p&gt;Let&#39;s imagine we want to use a function from an external package. The function has a return type of &lt;code&gt;any&lt;/code&gt; for the specific helper we wish to use.  If we are ok with eventual type errors and have a degree of certainty about the return value, we might assign it to a variable of type &lt;code&gt;any&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; getValueFromPackage &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;some-awesome-npm-package&#39;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;printNameInfoToTheUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; data&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getValueFromPackage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;token comment&quot;&gt;// name will have the any type&lt;/span&gt;
	&lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; count &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data
	&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; humanReadableCount &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; count &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token comment&quot;&gt;// some more code...&lt;/span&gt;
	&lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Total count:&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; humanReadableCount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The problem with using &lt;code&gt;any&lt;/code&gt; is that it spreads. In the example, we can destructure  &lt;code&gt;data&lt;/code&gt; without any warnings from Typescript, even though those properties might not exist. Moreover,  &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;count&lt;/code&gt; will also have the &lt;code&gt;any&lt;/code&gt; type. Even if this example is a little contrived, this will often cause some issues in a more realistic scenario. The package we use might change its schema and return an object that no longer has a &lt;code&gt;name&lt;/code&gt; property. Or we could make a typo and spell one of the properties wrong.&lt;/p&gt;
&lt;p&gt;Using a variable of type &lt;code&gt;unknown&lt;/code&gt; to store the return value of the third-package function is an excellent way to gain some type safety.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;printNameInfoToTheUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; data&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;unknown&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getValueFromPackage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;token comment&quot;&gt;// Warning: This will throw some type errors&lt;/span&gt;
	&lt;span class=&quot;token comment&quot;&gt;// Property &#39;name&#39; does not exist on type &#39;unknown&#39;&lt;/span&gt;
	&lt;span class=&quot;token comment&quot;&gt;// Property &#39;count&#39; does not exist on type &#39;unknown&#39;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; count &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data
	&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; humanReadableCount &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; count &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token comment&quot;&gt;// some more code...&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Total count:&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; humanReadableCount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By replacing &lt;code&gt;any&lt;/code&gt; with &lt;code&gt;unknown&lt;/code&gt;, we no longer can destructure &lt;code&gt;data&lt;/code&gt;. Typescript yells a little at us by throwing two type errors: &lt;code&gt;Property &#39;name&#39; does not exist on type &#39;unknown&#39;&lt;/code&gt; and &lt;code&gt;Property &#39;count&#39; does not exist on type &#39;unknown&#39;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To use the return value, we need to be more specific about what value it holds. We can solve this issue using type guards and a little generic helper.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// helper to check that a key exists or not on an object&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;hasProperty&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; object&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;K&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  obj&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  propertyName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;K&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; obj &lt;span class=&quot;token keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; Record&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;unknown&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; propertyName &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; obj&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;printNameInfoToTheUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; data&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;unknown&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getValueFromPackage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// type safety has a price...&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;object&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    data &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;hasProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;name&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;hasProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;count&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// both will be of type `unknown`&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; count &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// type-checking count to avoid calculation errors&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; humanReadableCount &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; count &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;number&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; Number&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isNaN&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;count&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      humanReadableCount &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; count &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Total count:&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; humanReadableCount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; name &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;string&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// throw or show other message&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In our example, &lt;code&gt;getValueFromPackage&lt;/code&gt; is supposed to return an object. By assigning it to &lt;code&gt;unknown&lt;/code&gt;, we make it unusable in the rest of the code, unless we restrict what type of value it contains.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;hasProperty&lt;/code&gt; is a &lt;code&gt;type predicate&lt;/code&gt;.  A type predicate is a function that returns a boolean whose value will determine the types inferred by Typescript. For example, &lt;code&gt;typeof&lt;/code&gt; is a built-in type predicate. When you use it inside an if statement (e.g. &lt;code&gt;typeof val === &#39;number&#39;&lt;/code&gt;), Typescript will infer that &lt;code&gt;val&lt;/code&gt; is a &lt;code&gt;number&lt;/code&gt; in the entirety of the if block.
In our case, when &lt;code&gt;hasProperty&lt;/code&gt; returns true, Typescript will infer that the key we were looking up on our object is of &lt;code&gt;unknown&lt;/code&gt; type.&lt;/p&gt;
&lt;p&gt;Let&#39;s dissect the multiple conditions in the if statement:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;typeof data === &#39;object&#39;&lt;/code&gt;  enables us to already tell Typescript that this value is an object.&lt;/li&gt;
&lt;li&gt;Because &lt;code&gt;null&lt;/code&gt; happens to be an object in JavaScript, we need to tell Typescript that &lt;code&gt;data&lt;/code&gt; is an object and not null.&lt;/li&gt;
&lt;li&gt;We then use a type predicate &lt;code&gt;hasProperty&lt;/code&gt; to confirm that both &lt;code&gt;count&lt;/code&gt; and &lt;code&gt;name&lt;/code&gt; are present on our object.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Inside of our if block, we still need to restrict further the &lt;code&gt;count&lt;/code&gt; and &lt;code&gt;name&lt;/code&gt; values to use them because they are both &lt;code&gt;unknown&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This example shows how we can regain some type of safety if we use an external package with many &lt;code&gt;any&lt;/code&gt; types. However, it is really up to you to evaluate whether going through those steps is worth it.&lt;/p&gt;
&lt;h2 id=&quot;conclusion-and-further-resources&quot; tabindex=&quot;-1&quot;&gt;Conclusion and further resources&lt;/h2&gt;
&lt;p&gt;In the wild, you will see many packages use &lt;code&gt;any&lt;/code&gt; in their type definitions. Because &lt;code&gt;unknown&lt;/code&gt; was introduced only in the v3 of Typescript, they are many codebases that do not use it heavily. However, it can serve us well to use it instead of &lt;code&gt;any&lt;/code&gt;. It enables us to avoid some of the pitfalls of using &lt;code&gt;any&lt;/code&gt;. However, as seen in our last example, it can also bring many extra steps and type checks. My rule of thumb is always to use  &lt;code&gt;unknown&lt;/code&gt; first before using &lt;code&gt;any&lt;/code&gt;. When writing helper functions, for instance, it can help avoid accidentally using the argument value without doing any type checks first. I hope this post was a little helpful to you!&lt;/p&gt;
&lt;p&gt;Here are some valuable resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://exploringjs.com/tackling-ts/ch_any-unknown.html#typescripts-two-top-types&quot;&gt;Typescript&#39;s two top types by Axel Rauschmayer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-0.html#new-unknown-top-type&quot;&gt;Release note Typescript 3.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates&quot;&gt;TypeScript: Documentation - Narrowing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/70028907/narrowing-an-object-of-type-unknown&quot;&gt;Stack overflow post on narrowing an object type&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content
    >
  </entry> 
  <entry>
    <title>Getting started with tmux</title>
    <link href="
  https://oliviac.dev/blog/getting-started-with-tmux/
  " />
    <updated>2022-02-05T00:00:00Z</updated>
    <id>
  https://oliviac.dev/blog/getting-started-with-tmux/
  </id>
    <content
      type="html"
      >&lt;p&gt;Apart from its cool name, tmux is also a great tool to make your developer life easier. In this post, we&#39;ll look at the purpose of tmux and some basic terminology. We&#39;ll write a tmux configuration that is enough to start using it and look at the most common commands.&lt;/p&gt;
&lt;h2 id=&quot;why-use-tmux%3F&quot; tabindex=&quot;-1&quot;&gt;Why use tmux?&lt;/h2&gt;
&lt;p&gt;Have you ever gotten lost switching between a tab in iterms where you run your tests while another tab runs your application (and a third one runs the backend)? Or do you have to work with a couple of repositories at once and have multiple terminals opened at the same time? tmux is a terminal multiplexer. The whole purpose of tmux is to make your life easier running and switching between different programs in one terminal.&lt;/p&gt;
&lt;h2 id=&quot;some-basic-terminology&quot; tabindex=&quot;-1&quot;&gt;Some basic terminology&lt;/h2&gt;
&lt;p&gt;Let&#39;s look at different critical terms before diving deeper into using and configuring tmux.&lt;/p&gt;
&lt;p&gt;A session in tmux gets created when you start tmux in your terminal. You can run multiple sessions at once (though only one is visible at a time, the others will be detached). Each session contains its own set of windows and panes.&lt;/p&gt;
&lt;p&gt;A window is your entire terminal window. A pane is what you create when you split your terminal window vertically or horizontally. Tmux enables you to make those splits and windows with whatever keymap you choose. You can also script it all (see the last section at the end).&lt;/p&gt;
&lt;p&gt;A tmux window:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://oliviac.dev/img/tmux-window.png&quot; alt=&quot;A tmux window takes up your entire terminal window&quot; /&gt;&lt;/p&gt;
&lt;p&gt;A tmux pane:
&lt;img src=&quot;https://oliviac.dev/img/tmux-pane.png&quot; alt=&quot;Example of a tmux pane in tmux, splitting the tmux window in half vertically&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;installing-tmux-and-running-it&quot; tabindex=&quot;-1&quot;&gt;Installing tmux and running it&lt;/h2&gt;
&lt;p&gt;First, make sure you have tmux installed on your system. Check out &lt;a href=&quot;https://github.com/tmux/tmux/wiki/Installing&quot;&gt;the tmux official wiki&lt;/a&gt; for all the information you need to install it properly. Once installed, you can check that everything is working by running the command &lt;code&gt;tmux&lt;/code&gt; in your terminal. You should be in a tmux session. To exit it, type &lt;code&gt;exit&lt;/code&gt; and enter.&lt;/p&gt;
&lt;h2 id=&quot;configuring-and-using-tmux&quot; tabindex=&quot;-1&quot;&gt;Configuring and using tmux&lt;/h2&gt;
&lt;p&gt;Now it is time to configure tmux (just a little bit) and explore some cool things we can do with it. First, let&#39;s create a &lt;code&gt;.tmux.conf&lt;/code&gt; file in your &lt;strong&gt;root directory&lt;/strong&gt;. This is the configuration file tmux will load when you launch it.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;touch&lt;/span&gt; ~/.tmux.conf&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;testing-your-config&quot; tabindex=&quot;-1&quot;&gt;Testing your config&lt;/h3&gt;
&lt;p&gt;The goal of configuring it is to find what works for you. I&#39;d recommend writing the tmux config while being in tmux so that you can test it out as we add new things to it. If you are inside tmux, just like a bashrc, you need to source your tmux config as you make changes for it to take effect.&lt;/p&gt;
&lt;p&gt;If you&#39;re inside tmux, you can source your updated config in command mode. Run &lt;code&gt;&amp;lt;ctrl-b&amp;gt;:&lt;/code&gt; (ctrl b followed by a colon). You should see the bottom bar changing. Enter &lt;code&gt;source-file ~/.tmux.conf&lt;/code&gt; and your configuration should be loaded. Let&#39;s add a custom keymap to our configuration to do this quicker:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;bind&lt;/span&gt; r source-file ~/.tmux.conf&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; display &lt;span class=&quot;token string&quot;&gt;&quot;config reloaded&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;bind&lt;/code&gt; is our way to tell tmux that &lt;code&gt;r&lt;/code&gt; preceded by the prefix key should source the tmux config. By pressing &lt;code&gt;&amp;lt;ctrl-b&amp;gt;&lt;/code&gt; followed by &lt;code&gt;r&lt;/code&gt;, this will reload your config without leaving tmux. Don&#39;t forget to source your config one last time in command mode before trying out this command. This key combination might feel very awkward. So let&#39;s move on to choose a better prefix.&lt;/p&gt;
&lt;h3 id=&quot;choose-a-prefix-you&#39;re-comfortable-with&quot; tabindex=&quot;-1&quot;&gt;Choose a prefix you&#39;re comfortable with&lt;/h3&gt;
&lt;p&gt;The whole point of tmux is to have keyboard shortcuts that work for you. tmux has a set of default keymaps to create windows, new panes, switch between sessions, etc. Each keymap uses a &lt;code&gt;prefix&lt;/code&gt;. You can think of it as the &lt;code&gt;leader&lt;/code&gt; key in vim. You combine the prefix with another key to interact with tmux and ask it to do something. By default, the prefix is &lt;code&gt;C-b&lt;/code&gt; (ctrl-b). If you like this prefix, you can move on to the next section. A popular alternative is to use &lt;code&gt;C-a&lt;/code&gt; as the prefix.&lt;/p&gt;
&lt;p&gt;Add this to your tmux config:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# in your ~/.tmux.conf&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Setting the prefix from C-b to C-a&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-g&lt;/span&gt; prefix C-a
&lt;span class=&quot;token comment&quot;&gt;# free original prefix keybinding&lt;/span&gt;
unbind C-b
&lt;span class=&quot;token comment&quot;&gt;# make sure we can send C-a to other apps&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;bind&lt;/span&gt; C-a send-prefix&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;set -g prefix C-a&lt;/code&gt; will tell tmux every time it runs &lt;code&gt;control+a&lt;/code&gt; as its prefix.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;unbind&lt;/code&gt; is to free &lt;code&gt;C-b&lt;/code&gt; and keep only one combination as our prefix.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bind C-a send-prefix&lt;/code&gt; is to make sure you can use this keymap in programs running inside of tmux. For instance, if you use vim and do not include this line, any of your vim keymaps using &lt;code&gt;C-a&lt;/code&gt; would no longer work inside tmux.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;a-small-note-before-going-further&quot; tabindex=&quot;-1&quot;&gt;A small note before going further&lt;/h3&gt;
&lt;p&gt;In the rest of the article, I&#39;ll be writing &lt;code&gt;&amp;lt;PREFIX&amp;gt;&lt;/code&gt; often followed by a letter to explain the different commands you can use in tmux. &lt;code&gt;&amp;lt;PREFIX&amp;gt;&lt;/code&gt; is whatever prefix you choose to use (for instance, &lt;code&gt;Ctrl-a&lt;/code&gt;).&lt;/p&gt;
&lt;h3 id=&quot;creating-windows-and-panes-in-tmux&quot; tabindex=&quot;-1&quot;&gt;Creating windows and panes in tmux&lt;/h3&gt;
&lt;p&gt;Generally, after setting up the &lt;code&gt;prefix&lt;/code&gt; in the tmux configuration, it is very common also to customize the keymap to create new panes (vertical or horizontal splits in a window) and navigate between those panes. In your &lt;code&gt;.tmux.conf&lt;/code&gt;, add:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# below your prefix config&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;bind&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; split-window &lt;span class=&quot;token parameter variable&quot;&gt;-h&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;bind&lt;/span&gt; - split-window &lt;span class=&quot;token parameter variable&quot;&gt;-v&lt;/span&gt;
unbind &lt;span class=&quot;token string&quot;&gt;&#39;&quot;&#39;&lt;/span&gt;
unbind %&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&#39;s dissect these few lines.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;By default, to create a horizontal split, you would use &lt;code&gt;&amp;lt;PREFIX&amp;gt;&amp;quot;&lt;/code&gt; (&lt;code&gt;C-a&lt;/code&gt; followed by a double quote &lt;code&gt;&amp;quot;&lt;/code&gt;). Instead, we bind &lt;code&gt;-&lt;/code&gt; to create a horizontal split. You can create a new pane in your window using your prefix followed by &lt;code&gt;-&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;For a vertical split, the keymap is by default &lt;code&gt;&amp;lt;PREFIX&amp;gt;%&lt;/code&gt;. A popular replacement is to use &lt;code&gt;|&lt;/code&gt; instead. It might also be easier to remember. You can now type &lt;code&gt;&amp;lt;PREFIX&amp;gt;|&lt;/code&gt; to create a vertical split.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The default keymap is &lt;code&gt;&amp;lt;PREFIX&amp;gt;c&lt;/code&gt; to create a new window.&lt;/p&gt;
&lt;p&gt;If you want to test these keymaps, reload your config (&lt;code&gt;&amp;lt;PREFIX&amp;gt;r&lt;/code&gt;).&lt;/p&gt;
&lt;h3 id=&quot;navigating-between-panes-and-windows-in-a-tmux-session&quot; tabindex=&quot;-1&quot;&gt;Navigating between panes and windows in a tmux session&lt;/h3&gt;
&lt;p&gt;To navigate between your windows, there are three main ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;PREFIX&amp;gt; n&lt;/code&gt; to go to the next window&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;PREFIX&amp;gt; 1&lt;/code&gt; to go to a particular window. Every window has a number. It starts at 0.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;PREFIX&amp;gt; w&lt;/code&gt; to have an interactive list of all your windows with a preview of what contains each window.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A popular option to navigate between your panes is to use the same keys as in vim (&lt;code&gt;k&lt;/code&gt; to go up, &lt;code&gt;j&lt;/code&gt; to go down, &lt;code&gt;h&lt;/code&gt; to go to the left pane, &lt;code&gt;l&lt;/code&gt; to go to the right pane). Let&#39;s add this to our &lt;code&gt;tmux.conf&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# in your ~/.tmux.conf&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# map direction keys for vim like experience&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;bind&lt;/span&gt; h select-pane &lt;span class=&quot;token parameter variable&quot;&gt;-L&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;bind&lt;/span&gt; j select-pane &lt;span class=&quot;token parameter variable&quot;&gt;-D&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;bind&lt;/span&gt; k select-pane &lt;span class=&quot;token parameter variable&quot;&gt;-U&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;bind&lt;/span&gt; l select-pane &lt;span class=&quot;token parameter variable&quot;&gt;-R&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I also use the vim keys to resize the panes.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# in your ~/.tmux.conf&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# resize panes with repeated key&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;bind&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-r&lt;/span&gt; H resize-pane &lt;span class=&quot;token parameter variable&quot;&gt;-L&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;bind&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-r&lt;/span&gt; J resize-pane &lt;span class=&quot;token parameter variable&quot;&gt;-D&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;bind&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-r&lt;/span&gt; K resize-pane &lt;span class=&quot;token parameter variable&quot;&gt;-U&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;bind&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-r&lt;/span&gt; L resize-pane &lt;span class=&quot;token parameter variable&quot;&gt;-R&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But if you do not care about vim, you can use &lt;code&gt;&amp;lt;PREFIX&amp;gt;&lt;/code&gt; followed by the arrow key to move your cursor to a particular split.&lt;/p&gt;
&lt;h3 id=&quot;creating-sessions-and-naming-sessions&quot; tabindex=&quot;-1&quot;&gt;Creating sessions and naming sessions&lt;/h3&gt;
&lt;p&gt;Earlier, I mentioned that you could have multiple sessions with their own set of windows and panes (and processes running). When you start tmux, you create a session at the same time. My go-to commands to manipulate sessions in tmux:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;tmux new-session -s coding&lt;/code&gt; to start tmux and create a &amp;quot;coding&amp;quot; session.&lt;/li&gt;
&lt;li&gt;If you are already in a tmux session and wish to create a new one, you can run &lt;code&gt;tmux new-session -s processes -d&lt;/code&gt;. The &lt;code&gt;-d&lt;/code&gt; is essential here. It will make that session in detached mode.&lt;/li&gt;
&lt;li&gt;To switch between sessions, you can use &lt;code&gt;&amp;lt;PREFIX&amp;gt;(&lt;/code&gt; to go to the next session or &lt;code&gt;&amp;lt;PREFIX&amp;gt;)&lt;/code&gt; to go to the previous session.&lt;/li&gt;
&lt;li&gt;You can also use an interactive list (like for the windows) by pressing &lt;code&gt;&amp;lt;PREFIX&amp;gt;s&lt;/code&gt;. Press &lt;code&gt;q&lt;/code&gt; to leave the interactive list.&lt;/li&gt;
&lt;li&gt;To rename your current session, use &lt;code&gt;&amp;lt;PREFIX&amp;gt;$&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;detached-mode&quot; tabindex=&quot;-1&quot;&gt;Detached mode&lt;/h3&gt;
&lt;p&gt;One great functionality is to run processes in the background using tmux detached mode. You can always re-attach to a session later on.&lt;/p&gt;
&lt;p&gt;If you are always in tmux, you can essentially leave tmux momentarily while not killing any processes by pressing &lt;code&gt;&amp;lt;PREFIX&amp;gt;d&lt;/code&gt;. It will send whatever tmux session you&#39;re on in the background. You can reattach this same session to run &lt;code&gt;tmux attach-session&lt;/code&gt; (or &lt;code&gt;tmux a&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;If you have several tmux sessions running in detached mode, you can also attach to a particular session directly. Use &lt;code&gt;tmux a -t NAME_OF_YOUR_SESSION&lt;/code&gt;. &lt;code&gt;NAME_OF_YOUR_SESSION&lt;/code&gt; will be your session name.&lt;/p&gt;
&lt;h3 id=&quot;closing-a-tmux-window-and-stopping-all-tmux-processes&quot; tabindex=&quot;-1&quot;&gt;Closing a tmux window and stopping all tmux processes&lt;/h3&gt;
&lt;p&gt;One significant point of attention is to make sure you do not forget a tmux session that runs in the background. &lt;code&gt;tmux ls&lt;/code&gt; is an excellent command to remember. It will list all your tmux sessions and show you when they were created.&lt;/p&gt;
&lt;p&gt;When it comes to quitting a window or pane, here&#39;s my list of essential commands:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;To kill a window or pane, &lt;code&gt;&amp;lt;PREFIX&amp;gt;x&lt;/code&gt; (&lt;code&gt;ctr-a x&lt;/code&gt; in my case).&lt;/li&gt;
&lt;li&gt;You can also use &lt;code&gt;&amp;lt;PREFIX&amp;gt;&amp;amp;&lt;/code&gt; to kill a window.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When it comes to killing a session in tmux, I generally kill all sessions simultaneously. I first leave tmux by pressing &lt;code&gt;&amp;lt;PREFIX&amp;gt;d&lt;/code&gt;. It will send all sessions in detached mode. tmux still runs but in the background. If you do a &lt;code&gt;tmux ls&lt;/code&gt;, you&#39;ll still see all of your sessions. I then do &lt;code&gt;tmux kill-server&lt;/code&gt; (be careful because it will essentially kill all sessions and processes running in tmux).
If you want to kill one specific session, leave &lt;code&gt;tmux&lt;/code&gt; (&lt;code&gt;&amp;lt;PREFIX&amp;gt;d&lt;/code&gt;) and then type &lt;code&gt;tmux kill-session -t NAME_OF_SESSION_TO_KILL&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;scrolling-in-your-tmux-buffer&quot; tabindex=&quot;-1&quot;&gt;Scrolling in your tmux buffer&lt;/h3&gt;
&lt;p&gt;There is a mode called &lt;code&gt;copy mode&lt;/code&gt; in tmux. You enter it by pressing &lt;code&gt;&amp;lt;PREFIX&amp;gt;[&lt;/code&gt; (and quit it by pressing &lt;code&gt;ENTER&lt;/code&gt;). After pressing &lt;code&gt;&amp;lt;PREFIX&amp;gt;[&lt;/code&gt;, you can then move in your buffer with your arrow keys. You can also use vim keys in copy mode (like &lt;code&gt;b&lt;/code&gt; and &lt;code&gt;w&lt;/code&gt; to move from one word to another, &lt;code&gt;gg&lt;/code&gt; ) if you enable vim keys in your config.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# in your ~/.tmux.conf&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# enable vi key bindings&lt;/span&gt;
setw &lt;span class=&quot;token parameter variable&quot;&gt;-g&lt;/span&gt; mode-keys &lt;span class=&quot;token function&quot;&gt;vi&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;searching-in-a-tmux-buffer&quot; tabindex=&quot;-1&quot;&gt;Searching in a tmux buffer&lt;/h3&gt;
&lt;p&gt;Here are the steps if you are searching for something in your current buffer:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Enter copy mode &lt;code&gt;&amp;lt;PREFIX&amp;gt;[&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;?&lt;/code&gt; if you want to search for an element above your current position in your buffer. Or you can press &lt;code&gt;/&lt;/code&gt; to search down.&lt;/li&gt;
&lt;li&gt;Type the element you are searching for.&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;n&lt;/code&gt; to move between the found occurrences.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;help-in-tmux&quot; tabindex=&quot;-1&quot;&gt;Help in tmux&lt;/h3&gt;
&lt;p&gt;If you forget how to do something in tmux, tmux has a help menu with a list of the keymaps. Type &lt;code&gt;&amp;lt;PREFIX&amp;gt;?&lt;/code&gt; to enter it (and &lt;code&gt;q&lt;/code&gt; to exit it).&lt;/p&gt;
&lt;h3 id=&quot;colors-in-tmux&quot; tabindex=&quot;-1&quot;&gt;Colors in tmux&lt;/h3&gt;
&lt;p&gt;To have your colors work properly in tmux in programs like vim or emac, add this to your config:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Configure color for terminal&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-g&lt;/span&gt; default-terminal &lt;span class=&quot;token string&quot;&gt;&quot;screen-256color&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;extending-tmux-with-plugins&quot; tabindex=&quot;-1&quot;&gt;Extending tmux with plugins&lt;/h3&gt;
&lt;p&gt;There is a plugin system to extend tmux. If you feel like adding some plugins, you need to install &lt;code&gt;tpm&lt;/code&gt; (tmux plugin manager). You can find all the installation information &lt;a href=&quot;https://github.com/tmux-plugins/tpm&quot;&gt;in the Github repository&lt;/a&gt;. Once you&#39;ve installed it, you can add some plugins to your tmux config. You should add all the plugin related stuff &lt;strong&gt;at the very end of your config.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here&#39;s what I have in my config:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# at the very end of ~/.tmux.conf&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-g&lt;/span&gt; @themepack &lt;span class=&quot;token string&quot;&gt;&#39;powerline/default/cyan&#39;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# set up plugins&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-g&lt;/span&gt; @plugin &lt;span class=&quot;token string&quot;&gt;&#39;tmux-plugins/tpm&#39;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# theme&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-g&lt;/span&gt; @plugin &lt;span class=&quot;token string&quot;&gt;&#39;jimeh/tmux-themepack&#39;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Initialize TMUX plugin manager&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# keep this line at the very bottom of tmux.conf&lt;/span&gt;
run &lt;span class=&quot;token string&quot;&gt;&#39;~/.tmux/plugins/tpm/tpm&#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instead of configuring it by hand, I added &lt;code&gt;tmux-themepack&lt;/code&gt; to style the bottom bar.&lt;/p&gt;
&lt;h2 id=&quot;scripting-tmux-with-tmuxinator&quot; tabindex=&quot;-1&quot;&gt;Scripting tmux with tmuxinator&lt;/h2&gt;
&lt;p&gt;At this point, we have a working tmux config and a set of keymaps we are comfortable with to create windows, sessions, and move in our terminal. What gives tmux an extra edge over using built-in tabs in your terminal (if you have those) is automating things. If you open your terminal every morning to launch the same programs and create the same tmux sessions, you can create a script and launch everything in half a second.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tmuxinator/tmuxinator&quot;&gt;tmuxinator&lt;/a&gt; is a great tool to create scripts quickly. Let&#39;s create an example script together to get the ball rolling for you. Let&#39;s start a project called &amp;quot;work&amp;quot;.&lt;/p&gt;
&lt;p&gt;First, we launch tmuxinator by typing &lt;code&gt;tmuxinator new work&lt;/code&gt;. Let&#39;s modify the newly created config:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# /Users/yourusername/.config/tmuxinator/work.yml&lt;/span&gt;

&lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; work
&lt;span class=&quot;token comment&quot;&gt;# the path you want to launch tmux in&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ~/projects/devblog

&lt;span class=&quot;token comment&quot;&gt;# Controls whether the tmux session should be attached to&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# automatically. Defaults to true.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# attach: false&lt;/span&gt;

&lt;span class=&quot;token key atrule&quot;&gt;windows&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;editor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; nvim
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; npm run dev&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;name&lt;/code&gt; will be the name of your script. Once created, when you open your terminal, you can type &lt;code&gt;tmuxinator work&lt;/code&gt; and it will launch tmux, creating all the windows you mentioned in the script.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;windows&lt;/code&gt; property contains a list of the different windows we want to create. It will create two windows: &amp;quot;editor&amp;quot; and the other named &amp;quot;process&amp;quot;.&lt;/li&gt;
&lt;li&gt;We then launch &lt;code&gt;nvim&lt;/code&gt; in the editor window while starting npm in the other window.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you&#39;re into aliases, you can create a quick one for &lt;code&gt;tmuxinator&lt;/code&gt; (it is a great name, but it can be a long one to write).&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# in your ~/.bashrc&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;tx&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;tmuxinator&quot;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# I also have an alias for tmux cos I&#39;m lazy :)&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;tm&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;tmux&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;conclusion-and-great-resources&quot; tabindex=&quot;-1&quot;&gt;Conclusion and great resources&lt;/h2&gt;
&lt;p&gt;We&#39;ve explored tmux and how to configure it and use it. We finished the article by writing a small script that is only a glimpse of all the cool things we can do with tmux. Here&#39;s my list of all the cheatsheets, documentation, and books to get extra comfortable with tmux:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tmux/tmux/wiki/Getting-Started&quot;&gt;Getting Started with tmux/tmux Wiki&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tmuxcheatsheet.com/&quot;&gt;Tmux Cheat Sheet &amp;amp; Quick Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;One of the best books on tmux: &lt;a href=&quot;https://pragprog.com/titles/bhtmux2/tmux-2/&quot;&gt;tmux 2: Productive Mouse-Free Development by Brian P. Hogan&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tmuxinator/tmuxinator&quot;&gt;Tmuxinator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=NZO8KjNbwJk&quot;&gt;Video on tmux by ThePrimeagen&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/liv7c/dotfiles&quot;&gt;GitHub - liv7c/dotfiles: Personal config for bash, tmux, git, and neovim&lt;/a&gt;: my custom config if you feel like taking a look (definitely a work in progress)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I hope this guide will be helpful to you. If you have any questions, you can reach me on &lt;a href=&quot;https://bsky.app/profile/oliviac.dev&quot;&gt;Bluesky&lt;/a&gt;.&lt;/p&gt;
</content
    >
  </entry> 
  <entry>
    <title>Testing HTML in React Components with Vitest</title>
    <link href="
  https://oliviac.dev/blog/validating-html-in-react-components-vitest/
  " />
    <updated>2024-09-08T00:00:00Z</updated>
    <id>
  https://oliviac.dev/blog/validating-html-in-react-components-vitest/
  </id>
    <content
      type="html"
      >&lt;p&gt;In this guide, we&#39;ll walk through the steps to set up HTML validation for React components using Vitest. You&#39;ll learn how to ensure your components adhere to proper HTML structure, improving code quality and catching errors early in the development process.&lt;/p&gt;
&lt;h2 id=&quot;what-is-html-validation%2C-and-why-does-it-matter%3F&quot; tabindex=&quot;-1&quot;&gt;What is HTML validation, and why does it matter?&lt;/h2&gt;
&lt;p&gt;You may have already used a service like &lt;a href=&quot;https://validator.w3.org/&quot;&gt;W3C validation service&lt;/a&gt; for your web pages. This type of validator scans your HTML and checks for essential elements, such as that the document has a language attribute (&lt;code&gt;&amp;lt;hmtl lang=&amp;quot;en&amp;quot;&amp;gt;&lt;/code&gt;), but also that your HTML markup is valid. Having valid HTML is crucial to creating a more accessible experience for your users.&lt;/p&gt;
&lt;p&gt;There are so many ways to check whether your HTML is valid. With React, we tend to create a lot of small components and often lack the vision of what the HTML of the page as a whole looks like. So, a service like the W3C validation service is still necessary. However, having quicker feedback while writing our reusable components during development is extremely helpful. It can significantly decrease the number of errors we encounter when we validate the HTML of a whole page. Moreover, when creating component libraries, it is essential to ensure the component has a valid HTML markup. Thus, in this post, we&#39;ll set up &lt;code&gt;html-validate&lt;/code&gt; in vitest to add those HTML checks at the component level and improve the feedback loop overall.&lt;/p&gt;
&lt;h2 id=&quot;setting-up-html-validation-in-vitest&quot; tabindex=&quot;-1&quot;&gt;Setting up html validation in vitest&lt;/h2&gt;
&lt;p&gt;I assume you already have a react project with vitest. If not, you can check out the &lt;a href=&quot;https://oliviac.dev/blog/validating-html-in-react-components-vitest/#the-whole-demo-code&quot;&gt;entire demo code&lt;/a&gt; in the final section of the post.&lt;/p&gt;
&lt;p&gt;The first step is to install &lt;a href=&quot;https://www.npmjs.com/package/html-validate&quot;&gt;&lt;code&gt;html-validate&lt;/code&gt;&lt;/a&gt;. If you use &lt;code&gt;npm&lt;/code&gt; or &lt;code&gt;pnpm&lt;/code&gt; along with vitest v2, you might need to use the flag &lt;code&gt;--legacy-peer-deps&lt;/code&gt;. This flag turns off the peer dependency checking during installation.&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# npm i -D html-validate&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# pnpm i -D html-validate&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;yarn&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--dev&lt;/span&gt; html-validate&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we need to modify the test setup file. You probably already have a setup file defined in your Vite or Vitest config. The setup file is run before each test file and reduces the boilerplate.&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/// &amp;lt;reference types=&quot;vitest&quot; /&gt;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;defineConfig&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;vite&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; react &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;@vitejs/plugin-react&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// https://vitejs.dev/config/&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;defineConfig&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  plugins&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;react&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  test&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    globals&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// your test setup files&lt;/span&gt;
    setupFiles&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;./src/setup-tests.ts&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    environment&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;happy-dom&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In my Vite config, I have defined one setup file &lt;code&gt;./src/setup-tests/ts&lt;/code&gt;. In your setup file, add this line:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// adding this to my `src/setup-tests.ts`&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;html-validate/vitest&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This line extends the &lt;code&gt;expect&lt;/code&gt; capabilities by adding some handy matcher functions such as &lt;code&gt;toBeValid&lt;/code&gt; and &lt;code&gt;toHTMLValidate&lt;/code&gt;. For the exhaustive list of the available matcher functions, check out the &lt;a href=&quot;https://gitlab.com/html-validate/html-validate/-/blob/master/src/vitest/vitest.ts?ref_type=heads&quot;&gt;html-validate source code for vitest&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Once we have added the new dependency and the line in our test setup file, we&#39;re generally good to go!&lt;/p&gt;
&lt;h2 id=&quot;validate-your-react-component-html-in-your-tests&quot; tabindex=&quot;-1&quot;&gt;Validate your React component HTML in your tests&lt;/h2&gt;
&lt;p&gt;I created a small Button component for this demo with some &lt;em&gt;problematic&lt;/em&gt; HTML markup.&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;PropsWithChildren&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;children&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; PropsWithChildren&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;children&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;button&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we look at the &lt;a href=&quot;https://html.spec.whatwg.org/multipage/form-elements.html#the-button-element&quot;&gt;HTML specifications for the button element&lt;/a&gt;, we see that a button can only contain &lt;strong&gt;phrasing content&lt;/strong&gt;. &lt;a href=&quot;https://html.spec.whatwg.org/multipage/dom.html#phrasing-content-2&quot;&gt;The HTML spec&lt;/a&gt; defines phrasing content as the text of the document. You can only include elements concerning the text&#39;s appearance (e.g., &lt;code&gt;strong&lt;/code&gt;, &lt;code&gt;span&lt;/code&gt;). It is an easy error to make. Now, let&#39;s write a test that helps us catch that issue (and others).&lt;/p&gt;
&lt;p&gt;Let&#39;s create a test file for our button and add a test case to validate the HTML:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;Button&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;./Button&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;render&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; screen&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;@testing-library/react&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Button&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;has valid HTML&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;container&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Button&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Hello&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Button&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; htmlString &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; container&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;innerHTML&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;htmlString&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toHTMLValidate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this test, we use the &lt;code&gt;.toHTMLValidate()&lt;/code&gt; helper from &lt;code&gt;html-validate&lt;/code&gt;.
We also use the &lt;code&gt;container.innerHTML&lt;/code&gt; to pass to &lt;code&gt;toHTMLValidate&lt;/code&gt; the actual HTML markup of our component.
When we run the test, we see that the test fails.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://oliviac.dev/img/html-vitest-error.png&quot; alt=&quot;Console output of the test file for the button. The test  fails, showing the error text &amp;quot;Error: Expected HTML to be valid but had the following errors:&amp;quot;. It shows two errors. One is that &amp;lt;button&amp;gt; is missing the recommended &amp;quot;type&amp;quot; attribute [no-implicit-button-type]. The other is that &amp;lt;div&amp;gt; element is not permitted as content under &amp;lt;button&amp;gt; [element-permitted-content]&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The test output shows us that our simple Button component has two issues:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;it is missing the recommended &lt;code&gt;type&lt;/code&gt; attribute.&lt;/li&gt;
&lt;li&gt;And it captures the error we discussed - the invalid &lt;code&gt;div&lt;/code&gt; element inside of a &lt;code&gt;button&lt;/code&gt; element.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-whole-demo-code&quot; tabindex=&quot;-1&quot;&gt;The whole demo code&lt;/h2&gt;
&lt;p&gt;You can check out the entire demo code on &lt;a href=&quot;https://stackblitz.com/edit/vitejs-vite-ceadnv?file=src%2Fcomponents%2FButton%2Findex.test.tsx&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;StackBlitz&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this guide, we set up &lt;code&gt;html-validate&lt;/code&gt; to validate the HTML of our React components in vitest. It greatly improves the feedback loop and helps catch all kinds of HTML errors quicker during development. I hope the guide was helpful. If you have any extra questions, don&#39;t hesitate to reach out!&lt;/p&gt;
</content
    >
  </entry> 
  <entry>
    <title>A practical introduction to code splitting in React</title>
    <link href="
  https://oliviac.dev/blog/a-practical-introduction-to-code-splitting-in-react/
  " />
    <updated>2025-03-26T00:00:00Z</updated>
    <id>
  https://oliviac.dev/blog/a-practical-introduction-to-code-splitting-in-react/
  </id>
    <content
      type="html"
      >&lt;p&gt;In this blog post, we&#39;ll explore various techniques for code splitting in React applications. We&#39;ll cover methods like lazy loading components, dynamic imports, and route-based code splitting. Throughout the article, we&#39;ll use a demo app to illustrate each technique so you can follow along and implement these concepts in your React projects. If you’d like to code along, feel free to clone the &lt;a href=&quot;https://github.com/liv7c/demo-code-splitting-react-vite&quot;&gt;Github repository&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Before exploring the different techniques, let’s first understand code splitting and how it can improve the user experience.&lt;/p&gt;
&lt;h2 id=&quot;what-is-code-splitting%3F&quot; tabindex=&quot;-1&quot;&gt;What is code splitting?&lt;/h2&gt;
&lt;p&gt;At its core, code splitting is a technique for dividing your code into different chunks or pieces. A chunk is a separate file that your bundler (or build tool) loads at specific moments — for example, a JavaScript file that loads when your user navigates to the About page.&lt;/p&gt;
&lt;p&gt;Code splitting works alongside your build tool. Build tools like Vite bundle and optimize your CSS, JavaScript, images, and other assets for production. The build tool determines which code should load initially (when the app first starts) and which can be loaded on demand (as the user interacts with the app). While the techniques for code splitting can vary depending on the build tool, the underlying concept remains the same.&lt;/p&gt;
&lt;h2 id=&quot;setting-up-the-demo-app&quot; tabindex=&quot;-1&quot;&gt;Setting up the demo app&lt;/h2&gt;
&lt;p&gt;To follow along with this post, clone the repository from GitHub and check out the &lt;code&gt;start-route-code-splitting&lt;/code&gt; branch:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; clone https://github.com/liv7c/demo-code-splitting-react-vite
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; demo-code-splitting-react-vite
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; checkout start-route-code-splitting
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; run dev&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/liv7c/demo-code-splitting-react-vite/tree/start-route-code-splitting&quot;&gt;&lt;code&gt;start-route-code-splitting&lt;/code&gt; branch&lt;/a&gt; contains the initial setup, but no code-splitting techniques have been applied yet.&lt;/p&gt;
&lt;h3 id=&quot;app-overview&quot; tabindex=&quot;-1&quot;&gt;App overview&lt;/h3&gt;
&lt;p&gt;After running the app, you should see the following pages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Home Page&lt;/strong&gt;: The main landing page of the app.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Movies Page&lt;/strong&gt;: Displays a list of movies fetched from a free API.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Movie Detail Page&lt;/strong&gt;: Shows detailed information about a specific movie.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;About Page&lt;/strong&gt;: Includes an informational modal for additional details.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;technical-stack&quot; tabindex=&quot;-1&quot;&gt;Technical stack&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;The app was created with &lt;a href=&quot;https://vite.dev/&quot;&gt;Vite&lt;/a&gt; using the &lt;code&gt;npm create vite@latest&lt;/code&gt; command.&lt;/li&gt;
&lt;li&gt;React Query is used for data fetching, and Radix UI is used for the modal component.&lt;/li&gt;
&lt;li&gt;The app uses React Router v7 but is not in framework mode (it’s not a Remix-style app). It uses createBrowserRouter to manage routes. You can view the router configuration in the &lt;a href=&quot;https://github.com/liv7c/demo-code-splitting-react-vite/blob/start-route-code-splitting/src/router/index.tsx&quot;&gt;Github repo&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;implementing-code-splitting-at-the-route-level&quot; tabindex=&quot;-1&quot;&gt;Implementing code-splitting at the route level&lt;/h2&gt;
&lt;p&gt;If you use a framework (Next or Remix), route-level code splitting is handled automatically. However, this is an easy win for many single-page applications built without a framework that can significantly improve performance.&lt;/p&gt;
&lt;p&gt;After running &lt;code&gt;npm run build,&lt;/code&gt; you’ll notice that Vite currently generates one JS file (over 100KB). As you add more content to each page, this file will only get bigger. This means that users must download the entire app’s JavaScript code, even if they visit only a specific part of the app.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://oliviac.dev/img/build_output_without_code_splitting.png&quot; alt=&quot;Output of running npm run build. Vite currently generates only one HTML file, one CSS file, and one JavaScript file. The JavaScript file size is already 108.74KB (gzipped)&quot; /&gt;&lt;/p&gt;
&lt;p&gt;We can help Vite split our code at the route level. This ensures JavaScript for a specific page loads only when needed.&lt;/p&gt;
&lt;h3 id=&quot;step-1%3A-using-react.lazy-for-route-level-code-splitting&quot; tabindex=&quot;-1&quot;&gt;Step 1: Using &lt;code&gt;React.lazy&lt;/code&gt; for route-level code splitting&lt;/h3&gt;
&lt;p&gt;In our &lt;code&gt;router/index.tsx&lt;/code&gt;, instead of importing every page component directly, we can use &lt;code&gt;React.lazy&lt;/code&gt; to import every page. We’ll skip lazy loading for the Home page, as it’s likely the most common entry point to the app.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;React.lazy&lt;/code&gt; ensures a component is imported only when it gets rendered. This is the behavior we want for most of the routes.&lt;/p&gt;
&lt;p&gt;Let’s wrap every page component with &lt;code&gt;React.lazy&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// in src/router/index.tsx&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;createBrowserRouter&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react-router&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Home &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;../pages/Home&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;AppLayout&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;../layouts/AppLayout&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;lazy&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// We wrap each page previously imported with React.lazy.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// React.lazy takes a function that returns a promise resolving to a React component.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; About &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lazy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;../pages/About&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; NotFound &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lazy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;../pages/NotFound&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; MovieDetails &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lazy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;../pages/MovieDetails&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Movies &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lazy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;../pages/Movies&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-2%3A-adding-suspense-for-loading-states&quot; tabindex=&quot;-1&quot;&gt;Step 2: Adding Suspense for loading states&lt;/h3&gt;
&lt;p&gt;Next, we need to add a Suspense boundary to handle loading states while the code is being fetched. We could add one to the &lt;code&gt;AppLayout&lt;/code&gt; to have a generic loader.&lt;/p&gt;
&lt;p&gt;Let’s create a quick loader component:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/components/Loader/index.tsx&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LoaderProps&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  message&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Loader&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;message &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Loading content...&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; LoaderProps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;span className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;sr-only&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;message&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;span&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;my-4 flex h-12 w-12 animate-spin justify-self-center rounded-full border-8 border-gray-300 border-t-teal-600&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we can wrap the &lt;code&gt;Outlet&lt;/code&gt; in the &lt;code&gt;AppLayout&lt;/code&gt; with a &lt;code&gt;Suspense&lt;/code&gt; component and use our new fancy loader as a fallback:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// components/AppLayout/index.tsx&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;Suspense&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;NavLink&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Outlet&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react-router&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;Loader&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;../../components/Loader&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;AppLayout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;header className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;bg-teal-800 text-white&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* rest of header content */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;header&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;main&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;max-width-wrapper py-6&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* let&#39;s wrap up our Outlet with a Suspense component */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Suspense fallback&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Loader &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Outlet &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Suspense&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;main&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-3%3A-testing-our-changes&quot; tabindex=&quot;-1&quot;&gt;Step 3: Testing our changes&lt;/h3&gt;
&lt;p&gt;This simple change greatly improves our build output. After running &lt;code&gt;npm run build&lt;/code&gt;, we see that Vite creates a JS file for each page. Additionally, there’s a JS file for the date utility used on the movies and movie detail pages. In larger projects, where pages may become complex and large, this approach ensures the build doesn’t generate one massive JavaScript file for the entire application.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://oliviac.dev/img/build_output_after_route_splitting.png&quot; alt=&quot;Output of running npm run build. Vite now generates multiple JavaScript files for each route. We now have a MovieDetails.js, a NotFound.js, an About.js, and other files.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;If you&#39;d like to see the completed code for the route-level code-splitting, you can check out the &lt;code&gt;end-route-code-splitting&lt;/code&gt; branch:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; checkout end-route-code-splitting&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;fixing-the-multiple-loaders&quot; tabindex=&quot;-1&quot;&gt;Fixing the multiple loaders&lt;/h2&gt;
&lt;p&gt;Now that we’ve split our routes using &lt;code&gt;React.lazy&lt;/code&gt;, we’ve reduced our initial JavaScript load. However, we now have a subtle UX issue: multiple loaders.&lt;/p&gt;
&lt;p&gt;When users land on the Movies page, they first see the Loader from &lt;code&gt;AppLayout&lt;/code&gt;. Then, after the component mounts, React Query starts fetching movie data, triggering another loading state. This creates a flickering effect where two loaders appear back-to-back.&lt;/p&gt;
&lt;p&gt;To fix this, we have a few approaches.&lt;/p&gt;
&lt;h3 id=&quot;solution-1%3A-use-another-suspense-boundary&quot; tabindex=&quot;-1&quot;&gt;Solution 1: use another Suspense boundary&lt;/h3&gt;
&lt;p&gt;We could wrap each movie and movie detail page with a Suspense boundary that uses &lt;code&gt;fallback={null}&lt;/code&gt;, meaning no loading indicator will be displayed. However, this is not ideal since users will see an empty space while the route component loads.&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// in router/index.tsx&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; router &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createBrowserRouter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;movies&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    path&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;/movies&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    element&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Suspense fallback&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Movies &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Suspense&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This might be a perfectly acceptable solution if:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The component loads quickly.&lt;/li&gt;
&lt;li&gt;A brief blank state does not negatively impact the user experience.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;solution-2%3A-leverage-usesuspensequery-from-%40tanstack-query&quot; tabindex=&quot;-1&quot;&gt;Solution 2: leverage useSuspenseQuery from @tanstack-query&lt;/h3&gt;
&lt;p&gt;A more robust approach is to use &lt;code&gt;useSuspenseQuery&lt;/code&gt; from &lt;code&gt;react-query&lt;/code&gt; (it is no longer experimental since v5). Here are some key differences between &lt;code&gt;useSuspenseQuery&lt;/code&gt; and &lt;code&gt;useQuery&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Simplified Loading State&lt;/strong&gt;: &lt;code&gt;useSuspenseQuery&lt;/code&gt; eliminates the need to handle loading states manually, as it guarantees the data property will be defined once the query resolves. React will suspend the component until the data is available. This means you don’t need to handle the loading state manually, letting Suspense take care of it automatically.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Error Handling&lt;/strong&gt;: Since &lt;code&gt;useSuspenseQuery&lt;/code&gt; no longer returns an error state, it&#39;s essential to use an &lt;code&gt;ErrorBoundary&lt;/code&gt; to handle potential errors during the data fetching. Without it, unhandled errors would cause your UI to break&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In our &lt;code&gt;hooks/useMovies.ts&lt;/code&gt;, let’s add a new hook:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// hooks/useMovies.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;useQuery&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; useSuspenseQuery&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;@tanstack/react-query&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;fetchMovie&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; fetchMovies&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;../api/movies&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;useMoviesWithSuspense&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useSuspenseQuery&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    queryKey&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;movies&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    queryFn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; fetchMovies&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;results&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, in our &lt;code&gt;Movies.tsx&lt;/code&gt;, we can replace the &lt;code&gt;useMovies&lt;/code&gt; hook with &lt;code&gt;useMoviesWithSuspense&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// pages/Movies.tsx&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;Link&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react-router&#39;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;useMoviesWithSuspense&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;../hooks/useMovies&#39;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;formatDate&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;../utils/date&#39;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Movies&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token comment&quot;&gt;// let&#39;s use our new hook.&lt;/span&gt;
	&lt;span class=&quot;token comment&quot;&gt;// It no longer returns a `status`&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;data&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; movies&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useMoviesWithSuspense&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;h1 className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;mb-4 text-xl&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Our most popular movies&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;h1&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ul className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;grid grid-cols-2 gap-x-5 gap-y-10&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;movies&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;movie&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
          &lt;span class=&quot;token comment&quot;&gt;//Nothing changes here&lt;/span&gt;
         &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;ul&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; Movies&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s install &lt;code&gt;react-error-boundary&lt;/code&gt; to handle errors and add a React boundary to our &lt;code&gt;AppLayout&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; react-error-boundary&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the &lt;code&gt;AppLayout&lt;/code&gt;, we can add an ErrorBoundary around the Suspense boundary to catch any potential errors in the data-fetching process and prevent the entire app from crashing.&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;Suspense&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;NavLink&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Outlet&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react-router&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;Loader&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;../../components/Loader&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;ErrorBoundary&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react-error-boundary&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;AppLayout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;header className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;bg-teal-800 text-white&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* some content */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;header&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;main&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;max-width-wrapper py-6&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ErrorBoundary fallback&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;⚠️Something went wrong&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Suspense fallback&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Loader &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
              &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Outlet &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Suspense&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;ErrorBoundary&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;main&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This acts as a catch-all ErrorBoundary. Alternatively, we could integrate an ErrorBoundary directly into the router configuration for a specific route. You can find more information about this approach in the &lt;a href=&quot;https://reactrouter.com/start/data/route-object&quot;&gt;React Router documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;solution-3%3A-combining-the-power-of-loader-functions-from-react-router-with-react-query&quot; tabindex=&quot;-1&quot;&gt;Solution 3: Combining the power of loader functions from react-router with react-query&lt;/h3&gt;
&lt;p&gt;The third approach (and my personal favorite) combines React Router&#39;s loader functions (&lt;a href=&quot;https://reactrouter.com/6.4.0/start/overview&quot;&gt;introduced in react-router v6.4&lt;/a&gt;) with React Query.&lt;/p&gt;
&lt;p&gt;For our MovieDetails, we face a similar challenge as we did on the Movies page: we need to fetch movie data once the component renders. By combining react-query with react-router loaders, we fetch data during the routing process rather than after component mounting, while still leveraging react-query&#39;s caching capabilities.&lt;/p&gt;
&lt;p&gt;Since we’re using react-router v7 and &lt;code&gt;createBrowserRouter&lt;/code&gt;, loaders allow us to fetch data before the component mounts. The result is passed directly to the component, and we can continue using react-query for caching.&lt;/p&gt;
&lt;h4 id=&quot;setting-up-the-loader-function&quot; tabindex=&quot;-1&quot;&gt;Setting up the loader function&lt;/h4&gt;
&lt;p&gt;First, let’s create a new file &lt;code&gt;loader.ts&lt;/code&gt; in our MovieDetails folder (feel free to name it differently). This file will contain our loader function:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/pages/MovieDetails/loader.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;LoaderFunctionArgs&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react-router&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;QueryClient&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;@tanstack/react-query&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;getMovieDetailsQuery&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;../../api/movies&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;Movie&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;../../types/movie&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;movieDetailsLoader&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;queryClient&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; QueryClient&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;params&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; LoaderFunctionArgs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; query &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getMovieDetailsQuery&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;params&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; queryClient&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ensureQueryData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;query&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Movie&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I created a &lt;code&gt;getMovieDetailsQuery&lt;/code&gt; that returns the query options we were using in our &lt;code&gt;useMovie&lt;/code&gt; hook:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// in src/api/movies.ts&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getMovieDetailsQuery&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;movieId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    queryKey&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;movies&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; movieId&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;queryFn&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetchMovie&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;movieId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    enabled&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Boolean&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;movieId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Some key points about the loader function:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;QueryClient&lt;/strong&gt;: The loader function receives a &lt;code&gt;queryClient&lt;/code&gt; that we will pass from the router. Since loaders are not hooks, we cannot use &lt;code&gt;useQueryClient&lt;/code&gt; to access the react-query store directly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;getMovieDetailsQuery&lt;/strong&gt;: This function returns the query options we usually use with &lt;code&gt;useQuery&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;What &lt;code&gt;movieDetailsLoader&lt;/code&gt; returns&lt;/strong&gt;: It returns a function with the loader signature. The returned function receives arguments like the &lt;code&gt;params&lt;/code&gt; that react-router automatically passes to all the loader functions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ensureQueryData&lt;/strong&gt;: The ensureQueryData method ensures that if the data isn&#39;t already cached, the query will be executed to fetch the data. Check out the &lt;a href=&quot;https://tanstack.com/query/latest/docs/reference/QueryClient#queryclientensurequerydata&quot;&gt;react query document&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;moving-the-query-client-to-its-own-file&quot; tabindex=&quot;-1&quot;&gt;Moving the query client to its own file&lt;/h4&gt;
&lt;p&gt;Before we can use this loader, we need to make the queryClient available in our app. Let’s extract the queryClient into a separate file so we can import it wherever needed.&lt;/p&gt;
&lt;p&gt;Let&#39;s create a &lt;code&gt;src/queryClient/index.ts&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;QueryClient&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;@tanstack/react-query&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; queryClient &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;QueryClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In &lt;code&gt;main.tsx&lt;/code&gt;, let’s import and use it.&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/main.tsx&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;queryClient&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;./queryClient&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;createRoot&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;root&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;StrictMode&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;QueryClientProvider client&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;queryClient&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;RouterProvider router&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;router&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;QueryClientProvider&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;StrictMode&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;modifying-our-router&quot; tabindex=&quot;-1&quot;&gt;Modifying our router&lt;/h4&gt;
&lt;p&gt;Now, in &lt;code&gt;router/index.tsx&lt;/code&gt;, we can import the loader function and the queryClient:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// router/index.tsx&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// ... other imports&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;queryClient&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;../queryClient&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;movieDetailsLoader&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;../pages/MovieDetails/loader&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; router &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createBrowserRouter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;root&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    element&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;AppLayout &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    children&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;movieDetail&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        path&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;/movies/:id&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// we use the loader property and call the movieDetailsLoader which returns a&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// function with the correct signature.&lt;/span&gt;
        loader&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;movieDetailsLoader&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;queryClient&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        element&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;MovieDetails &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;accessing-loaded-data-in-the-moviedetails-page&quot; tabindex=&quot;-1&quot;&gt;Accessing loaded data in the &lt;code&gt;MovieDetails&lt;/code&gt; page&lt;/h4&gt;
&lt;p&gt;Finally, we can replace the &lt;code&gt;useMovie&lt;/code&gt; hook in the MovieDetails component with the &lt;code&gt;useLoaderData&lt;/code&gt; hook, which gives us access to the data returned by the loader function. The Typescript part comes from this &lt;a href=&quot;https://tkdodo.eu/blog/react-query-meets-react-router#a-typescript-tip&quot;&gt;fantastic article&lt;/a&gt;, which digs deeper into the technique we are currently implementing.&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// in pages/MovieDetails/index.tsx&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;MovieDetails&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;//We replace our useMovie with useLoaderData&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// notice we no longer have any isLoading or isError 👀&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; movie &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useLoaderData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; Awaited&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;
    ReturnType&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ReturnType&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; movieDetailsLoader&lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Link to&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/movies&quot;&lt;/span&gt; className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;mb-3 inline-block py-2 underline&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;larr&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; Back to all movies
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Link&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;h1 className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;text-3xl&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;movie&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;title&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;h1&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;p className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;mt-3&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;by &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;movie&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;director&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;p className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;mt-3&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Release date&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;formatDate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;movie&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;release_date&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;my-4 border border-dotted border-amber-500 p-3&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;h2 className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;mb-3 font-bold&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Summary&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;h2&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;movie&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;opening_crawl&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;benefits-of-all-this-work&quot; tabindex=&quot;-1&quot;&gt;Benefits of all this work&lt;/h4&gt;
&lt;p&gt;We’ve written quite a bit of code for this third solution. Some key benefits of this approach are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We no longer have to manage any &lt;code&gt;isLoading&lt;/code&gt; or &lt;code&gt;isError&lt;/code&gt; booleans in our MovieDetails page since the loader fetches the data before the component mounts.&lt;/li&gt;
&lt;li&gt;We still benefit from React Query’s caching, to avoid unnecessary refetching.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;which-approach-to-choose%3F&quot; tabindex=&quot;-1&quot;&gt;Which approach to choose?&lt;/h3&gt;
&lt;p&gt;Each solution offers different trade-offs between simplicity, performance, and developer experience. There isn&#39;t a one-size-fits-all solution.&lt;/p&gt;
&lt;p&gt;Solution 1 is straightforward but may lack robustness and lead to layout shifts. Solution 2 offers a more efficient approach by leveraging the route&#39;s closest Suspense boundary and &lt;code&gt;ErrorBoundary&lt;/code&gt;, with minimal code changes. Solution 3, on the other hand, embraces newer capabilities from React Router, introducing a shift in how we load data on the client side.&lt;/p&gt;
&lt;p&gt;By adopting Solution 2 or Solution 3, we eliminated the problem of multiple loaders on the Movie and MovieDetails pages! Additionally, our build output remains unchanged after these refactorings.&lt;/p&gt;
&lt;p&gt;To see the implementations of these approaches, you can checkout the &lt;code&gt;end-multiple-loaders&lt;/code&gt; branch:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; checkout end-multiple-loaders&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;beyond-code-splitting-at-the-route-level&quot; tabindex=&quot;-1&quot;&gt;Beyond code splitting at the route level&lt;/h2&gt;
&lt;p&gt;While route-level code splitting provides significant benefits, it may not be sufficient for complex applications where individual pages contain numerous components or require large libraries. In such cases, code-splitting at the route level might not reduce load times, as you could end up with large JavaScript chunks that need to be downloaded. This section will explore how to apply more granular techniques for code-splitting to optimize loading performance.&lt;/p&gt;
&lt;h3 id=&quot;scenario%3A-we-have-added-a-fancy-animation-that-is-quite-heavy&quot; tabindex=&quot;-1&quot;&gt;Scenario: we have added a fancy animation that is quite heavy&lt;/h3&gt;
&lt;p&gt;I’ve created a new branch where I added a fancy loading animation.&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; checkout starter-lazy-loading-component&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The animation is a Lottie animation, a JSON file you can use with the &lt;a href=&quot;https://www.npmjs.com/package/lottie-react&quot;&gt;react-lottie library&lt;/a&gt;. If you’re curious, you can check out the animation on the About page by clicking on the button 🐰.&lt;/p&gt;
&lt;p&gt;After running &lt;code&gt;npm run build&lt;/code&gt;, we have a JS file for the About page of over 100KB. The file size is due mainly to the react-lottie library used to play the animation.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://oliviac.dev/img/build_output_lottie_before_code_splitting.png&quot; alt=&quot;When running npm run build in the terminal, Vite now produces several JavaScript files. There is an About.js file that is, once compressed, 117.14KB in size.&quot; /&gt;&lt;/p&gt;
&lt;h3 id=&quot;what-problem-are-we-trying-to-fix%3F&quot; tabindex=&quot;-1&quot;&gt;What problem are we trying to fix?&lt;/h3&gt;
&lt;p&gt;In our case, many users might not even interact with the modal that triggers the animation. This means the react-lottie library is unnecessarily included in the initial JavaScript bundle, even though it isn’t used immediately.&lt;/p&gt;
&lt;p&gt;To optimize this, we can use code-splitting to ensure that the &lt;code&gt;react-lottie&lt;/code&gt; library is loaded only when the user interacts with the modal. This way, we avoid loading unnecessary code upfront.&lt;/p&gt;
&lt;h3 id=&quot;lazy-loading-the-animation-component&quot; tabindex=&quot;-1&quot;&gt;Lazy-loading the Animation component&lt;/h3&gt;
&lt;p&gt;First, let’s improve our FancyAnimation component. We can use &lt;code&gt;React.lazy&lt;/code&gt; to dynamically import the react-lottie library, and we’ll also need to wrap this lazy-loaded component in a Suspense component. This ensures that the application handles any slight delay when loading the animation.&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// components/FancyAnimation/index.tsx&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;usePrefersReducedMotion&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;../../hooks/usePrefersReducedMotion&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;lazy&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Suspense&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; easterBunnyAnimation &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;./easter_bunny_anim.json&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Replace the import LottiePlayer from &#39;lottie-react&#39; with this dynamic import&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; LottiePlayer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lazy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;lottie-react&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;FancyAnimation&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; prefersReducedMotion &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;usePrefersReducedMotion&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;min-h-[450px]&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* wrap the LottiePlayer component with Suspense */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Suspense fallback&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;LottiePlayer
          animationData&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;easterBunnyAnimation&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          loop&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          autoplay&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;prefersReducedMotion&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Suspense&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we look at our build output, Vite now creates a separate chunk that contains the code related to &lt;code&gt;react-lottie&lt;/code&gt; and a chunk for the About page of about 30KB.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://oliviac.dev/img/build_output_lottie_after_lazy.png&quot; alt=&quot;In the terminal window, when running &amp;quot;npm run build&amp;quot;, Vite outputs several files. It produces a new index.es-CMK.js that contains the lottie react library. The About page chunk is now 34.46KB.&quot; /&gt;&lt;/p&gt;
&lt;h3 id=&quot;further-optimization%3A-lazy-loading-the-animation-json&quot; tabindex=&quot;-1&quot;&gt;Further optimization: lazy-loading the animation JSON&lt;/h3&gt;
&lt;p&gt;While we’ve reduced the chunk size of our About page, most of the 30KB is still due to the animation JSON itself.
To optimize further, we can load the animation JSON only when the component is rendered rather than include it in the initial load.&lt;/p&gt;
&lt;p&gt;Since we’re using React 19, we can take advantage of the new &lt;a href=&quot;https://react.dev/reference/react/use&quot;&gt;use hook&lt;/a&gt;, which allows us to read the value of a promise (like our JSON animation) and suspend the component while the promise is resolving. By combining the use hook with Suspense, we can lazily load both the react-lottie library and the animation JSON.&lt;/p&gt;
&lt;h4 id=&quot;using-react%E2%80%99s-use-hook-to-load-the-animation-json&quot; tabindex=&quot;-1&quot;&gt;Using React’s &lt;code&gt;use&lt;/code&gt; hook to load the animation JSON&lt;/h4&gt;
&lt;p&gt;Let’s refactor the component to dynamically import the animation JSON and use the use hook to handle the promise resolution. This change will further reduce the initial load size.&lt;/p&gt;
&lt;p&gt;First, let’s create the promise for the animation outside of the component:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// in components/FancyAnimation/index.tsx&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// After the imports, create the promise to import the animation JSON dynamically.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; animationPromise &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;./easter_bunny_anim.json&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;default
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we can create an inner component that our Suspense boundary can wrap. If we don’t, when the animation gets loaded, it will suspend to a Suspense boundary higher up the component tree, as the entire FancyAnimation would suspend.
Let’s use the &lt;code&gt;use&lt;/code&gt; hook and pass it the animation JSON promise we’ve just created.&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;usePrefersReducedMotion&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;../../hooks/usePrefersReducedMotion&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;lazy&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Suspense&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; use&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; LottiePlayer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lazy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;lottie-react&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; animationPromise &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;./easter_bunny_anim.json&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;default
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Create an inner component that contains the LottiePlayer and the animation JSON&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;AnimationContent&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; prefersReducedMotion &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;usePrefersReducedMotion&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; animationData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;animationPromise&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;LottiePlayer
      animationData&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;animationData&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      loop&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      autoplay&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;prefersReducedMotion&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;FancyAnimation&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;min-h-[450px]&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Suspense fallback&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;AnimationContent &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Suspense&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;final-build-output&quot; tabindex=&quot;-1&quot;&gt;Final build output&lt;/h4&gt;
&lt;p&gt;With this refactoring, our build output is back to a tiny JS file size of around 12 KB for the About page. Users not interacting with the modal won&#39;t have to load that JavaScript.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://oliviac.dev/img/build_output_lottie_after_use.png&quot; alt=&quot;Result of running  in the terminal. The output shows that Vite has created a different JS file for the animation JSON. The About chunk is again 12KB.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You can see the final implementation by checking out the &lt;code&gt;end-lazy-loading-component&lt;/code&gt; branch:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; checkout end-lazy-loading-component&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this blog post, we explored some techniques around code-splitting in a React single-page application. We looked at code-splitting at the route level and at a couple of techniques to mitigate the dreaded multiple loaders effect. We had some practice with &lt;code&gt;Suspense&lt;/code&gt; and the new &lt;code&gt;use&lt;/code&gt; hook. We then experimented with optimizing our bundle when we use a heavy component on a page. I hope you found this post helpful! Feel free to reach out on &lt;a href=&quot;https://bsky.app/profile/oliviac.dev&quot;&gt;Bluesky&lt;/a&gt; if you have any questions or would like to share your own experiences with this topic!&lt;/p&gt;
&lt;h2 id=&quot;resources&quot; tabindex=&quot;-1&quot;&gt;Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://tkdodo.eu/blog/react-query-meets-react-router&quot;&gt;Great blog post on using react-query with react-router v6.4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tanstack.com/query/v4/docs/reference/QueryClient#queryclientensurequerydata&quot;&gt;Documentation on the &lt;code&gt;ensureQueryData&lt;/code&gt; hook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tanstack.com/query/latest/docs/framework/react/reference/useSuspenseQuery#usesuspensequery&quot;&gt;Documentation on the &lt;code&gt;useSuspenseQuery&lt;/code&gt; hook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://reactrouter.com/6.4.0/start/overview#data-loading&quot;&gt;Documentation on loading data in React Router&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/liv7c/demo-code-splitting-react-vite&quot;&gt;The repository of this demo on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content
    >
  </entry> 
  <entry>
    <title>An introduction to table driven tests in Vitest</title>
    <link href="
  https://oliviac.dev/blog/introduction-to-table-driven-tests-in-vitest/
  " />
    <updated>2025-04-09T00:00:00Z</updated>
    <id>
  https://oliviac.dev/blog/introduction-to-table-driven-tests-in-vitest/
  </id>
    <content
      type="html"
      >&lt;p&gt;I first encountered the concept of &amp;quot;table driven tests&amp;quot; when coding in the beautiful &lt;a href=&quot;https://go.dev/&quot;&gt;Go language&lt;/a&gt;. The technique is straightforward: You create a table (an array in your JavaScript code) to define the cases you want to test. Then you let the test runner loop through all the test cases. It is an extremely efficient technique for adding new test cases, reducing the boilerplate, and testing a lot more use cases.&lt;/p&gt;
&lt;p&gt;This technique is absolutely brilliant for unit tests. In this blog post, we&#39;ll explore how to use it in Vitest.&lt;/p&gt;
&lt;h2 id=&quot;let&#39;s-write-a-table-driven-test&quot; tabindex=&quot;-1&quot;&gt;Let&#39;s write a table driven test&lt;/h2&gt;
&lt;p&gt;Let&#39;s create a quick function to validate an email:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// utils/validators.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;isValidEmail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; trimmedEmail &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; email&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;trimmedEmail&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; emailRegex &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;^[^&#92;s@]+@[^&#92;s@]+&#92;.[^&#92;s@]+$&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; emailRegex&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;trimmedEmail&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the test file, we will add a describe block for that util function:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// utils/validators.test.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;isValidEmail&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;./validators&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;isValidEmail&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Traditionally, to test this function, we would write tests like the following snippet:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// utils/validators.test.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;isValidEmail&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;./validators&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;validateEmail&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;returns false when email is empty&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;isValidEmail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;returns false when email is empty string with white spaces&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;isValidEmail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;  &#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// lots of edge cases still to cover&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With table driven testing, instead of writing each test manually, we first define our test cases in an array.&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;isValidEmail&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; testCases&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    input&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    expected&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;boolean&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;email is empty&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      input&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      expected&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;email is an empty string with white spaces&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      input&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;  &#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      expected&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;missing domain&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      input&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;username@&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      expected&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;missing username&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      input&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;@email.com&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      expected&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;missing at sign&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      input&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;useremail&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      expected&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;invalidates duplicate email entries with white spaces&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      input&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;   test@email.com    test@email.com&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      expected&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;valid email&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      input&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;test@email.com&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      expected&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;handles leading white spaces&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      input&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;   test@email.com&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      expected&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;handles trailing white spaces&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      input&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;test@email.com    &#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      expected&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;handles trailing and leading white spaces&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      input&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;   test@email.com    &#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      expected&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can define your test cases the way you want. You could rename &lt;code&gt;expected&lt;/code&gt; to &lt;code&gt;want&lt;/code&gt; or &lt;code&gt;expectedOutput&lt;/code&gt;. There is no strict rule here. You can name the properties however you like, and even include additional fields if needed. I like adding a name and using the object structure to make things as readable as possible.&lt;/p&gt;
&lt;p&gt;The only thing left is to run our tests using &lt;a href=&quot;https://vitest.dev/api/#test-each&quot;&gt;&lt;code&gt;test.each()&lt;/code&gt;&lt;/a&gt; from Vitest. We pass our test cases to &lt;code&gt;test.each&lt;/code&gt;, then define a callback that receives each test case&#39;s values.&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;isValidEmail&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;./validators&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;isValidEmail&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; testCases&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    input&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    expected&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;boolean&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;email is empty&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      input&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      expected&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// rest of our test cases...&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// You could also use `it.each`&lt;/span&gt;
  test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;each&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;testCases&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;$name&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; expected&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;isValidEmail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;expected&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Some things to note:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Because we use objects to define each case, we can access each property by their name using the &lt;code&gt;$&lt;/code&gt; notation. If we had used &lt;code&gt;testName&lt;/code&gt; instead of &lt;code&gt;name&lt;/code&gt; in our test cases array, we would have written &lt;code&gt;test.each(testCases)(&#39;$testName&#39;, &lt;/code&gt; instead.&lt;/li&gt;
&lt;li&gt;We define a callback function that receives each test case object. We write the test logic once, and reuse it for each case.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If we run the test, we can see an output where Vitest runs each test case and outputs the result in a very clean, readable way:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt; ✓ src&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;utils&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;validators&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ts&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt; tests&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 2ms
   ✓ isValidEmail &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;email is empty&#39;&lt;/span&gt; 1ms
   ✓ isValidEmail &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;email is empty string with white spac…&#39;&lt;/span&gt; 0ms
   ✓ isValidEmail &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;missing domain&#39;&lt;/span&gt; 0ms
   ✓ isValidEmail &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;missing username&#39;&lt;/span&gt; 0ms
   ✓ isValidEmail &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;missing at sign&#39;&lt;/span&gt; 0ms
   ✓ isValidEmail &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;invalidates duplicate email entries w…&#39;&lt;/span&gt; 0ms
   ✓ isValidEmail &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;valid email&#39;&lt;/span&gt; 0ms
   ✓ isValidEmail &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;handles leading white spaces&#39;&lt;/span&gt; 0ms
   ✓ isValidEmail &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;handles trailing white spaces&#39;&lt;/span&gt; 0ms
   ✓ isValidEmail &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;handles trailing and leading white sp…&#39;&lt;/span&gt; 0ms&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This technique makes it very easy to add new test cases!&lt;/p&gt;
&lt;h3 id=&quot;using-nested-arrays-instead-of-objects-for-the-test-cases&quot; tabindex=&quot;-1&quot;&gt;Using nested arrays instead of objects for the test cases&lt;/h3&gt;
&lt;p&gt;An alternative is to use nested arrays instead of objects, which can be more concise. If you prefer this notation, you would define the test cases like this:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;isValidEmail&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; testCases&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; input&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; expected&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;boolean&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;email is empty&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;email is empty with white spaces&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;  &#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, instead of accessing the properties of an object in your &lt;code&gt;test.each&lt;/code&gt;, you access the different array values based on their position:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;isValidEmail&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; testCases&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; input&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; expected&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;boolean&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;email is empty&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;email is empty with white spaces&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;  &#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;each&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;testCases&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;%s&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; input&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; expected&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;isValidEmail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;expected&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;%s&lt;/code&gt; interpolates the &lt;code&gt;name&lt;/code&gt; we provided. It follows the &lt;a href=&quot;https://nodejs.org/api/util.html#util_util_format_format_args&quot;&gt;&lt;code&gt;printf&lt;/code&gt; formatting rules&lt;/a&gt;. &lt;code&gt;%s&lt;/code&gt; means you want to interpolate a string. For a number, you would write &lt;code&gt;%d&lt;/code&gt; for instance.&lt;/p&gt;
&lt;p&gt;You can choose whichever style feels clearer or more readable to you.&lt;/p&gt;
&lt;h2 id=&quot;when-to-use-table-driven-tests&quot; tabindex=&quot;-1&quot;&gt;When to use table driven tests&lt;/h2&gt;
&lt;p&gt;There’s no hard rule about when to use table driven tests, but it’s especially useful when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There are many slight variations to test (like lots of different types of inputs, etc.), and the test logic remains the same.&lt;/li&gt;
&lt;li&gt;The logic is simple and pure. Table testing shines when testing pure functions, which are functions that, given the same input, will always return the same output.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-about-jest%3F&quot; tabindex=&quot;-1&quot;&gt;What about Jest?&lt;/h2&gt;
&lt;p&gt;In Jest, you can use &lt;code&gt;.each&lt;/code&gt; in the same way as in Vitest. You can check out &lt;a href=&quot;https://jestjs.io/docs/api#each&quot;&gt;the documentation for the each method in Jest here&lt;/a&gt;. The examples in the documentation should feel familiar!&lt;/p&gt;
&lt;h2 id=&quot;complete-code-demo&quot; tabindex=&quot;-1&quot;&gt;Complete code demo&lt;/h2&gt;
&lt;p&gt;If you feel like playing with the code from this blog post, it is available on &lt;a href=&quot;https://stackblitz.com/edit/demo-explore-table-driven-testing-vitest?file=README.md,src%2Futils%2Fvalidators.test.ts&quot;&gt;Stackblitz&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this post, we explored a technique called &lt;em&gt;table driven testing&lt;/em&gt;, which is quite popular in the Go community. However, we can also apply it to our JavaScript code!&lt;/p&gt;
&lt;p&gt;By defining test cases in a table (an array of objects or arrays), we can quickly test multiple input variations without repeating ourselves. This technique reduces the boilerplate and makes adding more test cases easy. It is especially handy when testing pure functions or utils.&lt;/p&gt;
&lt;p&gt;Thanks for reading! I hope you find the post useful. If you have any questions or want to chat about unit tests, don&#39;t hesitate to reach out on &lt;a href=&quot;https://bsky.app/profile/oliviac.dev&quot;&gt;Bluesky&lt;/a&gt; 😀&lt;/p&gt;
&lt;h2 id=&quot;resources&quot; tabindex=&quot;-1&quot;&gt;Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://vitest.dev/api/#test-each&quot;&gt;Vitest&#39;s documentation on test.each&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jestjs.io/docs/api#each&quot;&gt;Jest&#39;s documentation on the &lt;code&gt;.each&lt;/code&gt; method&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dave.cheney.net/2019/05/07/prefer-table-driven-tests&quot;&gt;Great blog post about table driven tests in Go&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content
    >
  </entry> 
  <entry>
    <title>How to use the HTML specification to write better HTML</title>
    <link href="
  https://oliviac.dev/blog/how-to-use-the-html-specification-to-write-better-html/
  " />
    <updated>2025-05-14T00:00:00Z</updated>
    <id>
  https://oliviac.dev/blog/how-to-use-the-html-specification-to-write-better-html/
  </id>
    <content
      type="html"
      >&lt;p&gt;When writing HTML, I often ask myself all kinds of questions. For instance, when should I use an &lt;code&gt;&amp;lt;article&amp;gt;&lt;/code&gt; element? Is it valid HTML to use a &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; tag inside an &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt;? The HTML specification has been my go-to resource for answering these questions, particularly the fourth section, &lt;a href=&quot;https://html.spec.whatwg.org/multipage/semantics.html#semantics&quot;&gt;&amp;quot;The elements of HTML&amp;quot;&lt;/a&gt;. It is an incredible resource, but navigating it can feel a little overwhelming at first.&lt;/p&gt;
&lt;p&gt;This blog post is here to help you find your way through the HTML specification and get the information you need. By understanding how to navigate the specification, you&#39;ll be able to write more semantic HTML that better describes your content.&lt;/p&gt;
&lt;h2 id=&quot;a-first-taste-of-the-html-specification-and-some-key-terms&quot; tabindex=&quot;-1&quot;&gt;A first taste of the HTML specification and some key terms&lt;/h2&gt;
&lt;p&gt;There are different sections in the  &lt;a href=&quot;https://html.spec.whatwg.org/multipage/&quot;&gt;HTML specification&lt;/a&gt;. The section I want to focus on in this blog post is &lt;a href=&quot;https://html.spec.whatwg.org/multipage/semantics.html#semantics&quot;&gt;section 4 &amp;quot;The elements of HTML&amp;quot;&lt;/a&gt;. This section lists each HTML element and explains how and when to use it. It is full of examples and explanations that are invaluable when trying to write semantic HTML.&lt;/p&gt;
&lt;p&gt;When browsing the spec, you&#39;ll notice a few terms, such as &amp;quot;Category&amp;quot; or &amp;quot;Content Model&amp;quot;. Let&#39;s quickly clarify what those are.&lt;/p&gt;
&lt;h3 id=&quot;category&quot; tabindex=&quot;-1&quot;&gt;Category&lt;/h3&gt;
&lt;p&gt;As mentioned in the &lt;a href=&quot;https://html.spec.whatwg.org/multipage/dom.html#kinds-of-content&quot;&gt;spec&lt;/a&gt;, each HTML element belongs to zero or more categories. &lt;strong&gt;A category describes what an element is&lt;/strong&gt;. There are seven categories in the HTML spec:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://html.spec.whatwg.org/multipage/dom.html#metadata-content-2&quot;&gt;Metadata content&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://html.spec.whatwg.org/multipage/dom.html#flow-content-2&quot;&gt;Flow content&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://html.spec.whatwg.org/multipage/dom.html#sectioning-content-2&quot;&gt;Sectioning content&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://html.spec.whatwg.org/multipage/dom.html#heading-content-2&quot;&gt;Heading content&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://html.spec.whatwg.org/multipage/dom.html#phrasing-content-2&quot;&gt;Phrasing content&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://html.spec.whatwg.org/multipage/dom.html#embedded-content-category&quot;&gt;Embedded content&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://html.spec.whatwg.org/multipage/dom.html#interactive-content-2&quot;&gt;Interactive content&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To sum things up:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Flow content is the most common category. Almost every HTML element you use falls inside that category.&lt;/li&gt;
&lt;li&gt;You can think of phrasing content as text. It is the text contained within a paragraph, for instance.&lt;/li&gt;
&lt;li&gt;Heading content is all the elements to declare a heading (e.g., &lt;code&gt;h1&lt;/code&gt;, &lt;code&gt;h2&lt;/code&gt;, etc.)&lt;/li&gt;
&lt;li&gt;Sectioning content refers to the elements used to declare a new section in a document.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;content-model&quot; tabindex=&quot;-1&quot;&gt;Content model&lt;/h3&gt;
&lt;p&gt;Content model describes &lt;strong&gt;what content an element can contain&lt;/strong&gt;. Each HTML element can contain specific categories. Some HTML elements, such as &lt;a href=&quot;https://html.spec.whatwg.org/multipage/sections.html#the-h1,-h2,-h3,-h4,-h5,-and-h6-elements&quot;&gt;the heading tag&lt;/a&gt;, can contain only phrasing content. Whenever you wonder what you can put inside of an HTML element, you should look at the element&#39;s content model.&lt;/p&gt;
&lt;h2 id=&quot;how-to-read-an-html-specification-entry&quot; tabindex=&quot;-1&quot;&gt;How to read an HTML specification entry&lt;/h2&gt;
&lt;p&gt;In this section, we&#39;ll discuss how to read an HTML specification entry. Let&#39;s say you&#39;re looking at &lt;a href=&quot;https://html.spec.whatwg.org/multipage/grouping-content.html#the-li-element&quot;&gt;the specification for the &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt; element&lt;/a&gt;. Each element in the specification is described using a consistent set of sections. Here&#39;s a quick breakdown of some key sections you&#39;ll find for most elements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Content model&lt;/strong&gt;: This tells you what can go inside the element tags. In the case of the &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt; tag, its content model is &amp;quot;flow content&amp;quot;, meaning it can contain almost any HTML element.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Content attributes&lt;/strong&gt;: The section lists the possible attributes you can specify on the element.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Contexts in which the element can be used&lt;/strong&gt;: It indicates where the element can be used. For instance, some elements are only valid within specific parent elements. In the case of the &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt;, this section explains that &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt; should be used inside of &lt;code&gt;&amp;lt;ol&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;menu&amp;gt;&lt;/code&gt; elements.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The specification also includes many clickable links to help you explore further. For example, if you need a refresher on what &amp;quot;flow content&amp;quot; means, click on the link, and you&#39;ll be taken to a detailed overview of that term.&lt;/p&gt;
&lt;h2 id=&quot;building-a-better-mental-image-of-the-different-elements-and-their-purpose&quot; tabindex=&quot;-1&quot;&gt;Building a better mental image of the different elements and their purpose&lt;/h2&gt;
&lt;p&gt;Beyond the category and content model, the HTML specification groups HTML elements into different subsections based on their purpose.&lt;/p&gt;
&lt;p&gt;Here are some of the key subsections in &lt;a href=&quot;https://html.spec.whatwg.org/multipage/#toc-semantics&quot;&gt;section 4 of the specification&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://html.spec.whatwg.org/multipage/semantics.html#document-metadata&quot;&gt;&lt;strong&gt;Document metadata&lt;/strong&gt;&lt;/a&gt;: It contains elements used to describe the document itself rather than its content. It includes elements like the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; element and &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://html.spec.whatwg.org/multipage/sections.html#sections&quot;&gt;&lt;strong&gt;Sections&lt;/strong&gt;&lt;/a&gt;: It groups the different HTML elements that create a new section of the document. Sections are the building blocks of your page layout. It contains elements such as &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;article&amp;gt;&lt;/code&gt; , &lt;code&gt;&amp;lt;section&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;nav&amp;gt;&lt;/code&gt;, etc.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://html.spec.whatwg.org/multipage/grouping-content.html#grouping-content&quot;&gt;&lt;strong&gt;Grouping content&lt;/strong&gt;&lt;/a&gt;: It contains elements such as &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt; that serve to group content together. For example, a  &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt;  groups related sentences, while a &lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt; wraps a list of items.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://html.spec.whatwg.org/multipage/text-level-semantics.html#text-level-semantics&quot;&gt;&lt;strong&gt;Text-level semantics&lt;/strong&gt;&lt;/a&gt;: It contains all the elements that give more meaning to inline text, such as &lt;code&gt;&amp;lt;strong&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;time&amp;gt;&lt;/code&gt;, or &lt;code&gt;&amp;lt;em&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://html.spec.whatwg.org/multipage/forms.html#forms&quot;&gt;&lt;strong&gt;Forms&lt;/strong&gt;&lt;/a&gt;: It contains all the elements to create HTML forms. This is where you can find all the different input types that exist.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are other subsections for &lt;a href=&quot;https://html.spec.whatwg.org/multipage/embedded-content.html#embedded-content&quot;&gt;embedded content&lt;/a&gt; (for HTML elements such as &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;) and a &lt;a href=&quot;https://html.spec.whatwg.org/multipage/tables.html#tables&quot;&gt;separate subsection for tables&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The way the different HTML elements are grouped within each subsection is a good reminder that each element has a particular purpose. If you&#39;re unsure which element to use, start by asking what role the content plays in your document. For example, if you’re organizing your site’s layout, check the &amp;quot;Sections&amp;quot; subsection first.&lt;/p&gt;
&lt;h2 id=&quot;beyond-the-%3Cdiv%3E-element%3A-understanding-semantic-sections-in-html&quot; tabindex=&quot;-1&quot;&gt;Beyond the &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; element: Understanding semantic sections in HTML&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://html.spec.whatwg.org/multipage/grouping-content.html#the-div-element&quot;&gt;The &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; element&lt;/a&gt;, found in the &lt;strong&gt;“Grouping content”&lt;/strong&gt; subsection of the HTML specification, is a generic container used to group elements without conveying any semantic meaning.&lt;/p&gt;
&lt;p&gt;Despite this, many websites still use &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; to wrap entire sections of content. Although valid, there are often better alternatives. The specification provides a set of HTML elements that we can use to describe the different sections more effectively based on their content. Think of each section as a container with its own specific purpose.&lt;/p&gt;
&lt;p&gt;Here are some of the key semantic sectioning elements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://html.spec.whatwg.org/multipage/sections.html#the-article-element&quot;&gt;&lt;code&gt;&amp;lt;article&amp;gt;&lt;/code&gt;&lt;/a&gt;: A self-contained and independent section of the document.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://html.spec.whatwg.org/multipage/sections.html#the-section-element&quot;&gt;&lt;code&gt;&amp;lt;section&amp;gt;&lt;/code&gt;&lt;/a&gt;:   A &lt;strong&gt;thematic grouping of content&lt;/strong&gt; typically including a heading that describes its content.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://html.spec.whatwg.org/multipage/sections.html#the-nav-element&quot;&gt;&lt;code&gt;&amp;lt;nav&amp;gt;&lt;/code&gt;&lt;/a&gt;: A container for navigation links to other pages or sections of the same page.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://html.spec.whatwg.org/multipage/sections.html#the-header-element&quot;&gt;&lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt;&lt;/a&gt;: Introduces a section or a page. It typically contains a logo, a main heading, or a table of contents.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Using a &lt;code&gt;&amp;lt;nav&amp;gt;&lt;/code&gt; indicates that this section contains essential navigation links. Assistive technologies can use this information to detect navigation blocks more easily. Using a &lt;code&gt;&amp;lt;section&amp;gt;&lt;/code&gt; signals that the enclosed content is thematically related and part of the overall document structure (e.g., a section containing all the services your business offers).&lt;/p&gt;
&lt;h2 id=&quot;the-importance-of-headings-to-give-structure-to-your-document&quot; tabindex=&quot;-1&quot;&gt;The importance of headings to give structure to your document&lt;/h2&gt;
&lt;p&gt;Heading elements (&lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt;, etc.) are part of the &amp;quot;Sections&amp;quot; subsection. They are a crucial way to add structure to a document. &lt;a href=&quot;https://html.spec.whatwg.org/multipage/sections.html#the-h1,-h2,-h3,-h4,-h5,-and-h6-elements&quot;&gt;As mentioned in the spec&lt;/a&gt;, &#39;they represent headings for their sections&#39;. There are some critical takeaways to take from that section:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Headings are a way to create sections within your document.&lt;/li&gt;
&lt;li&gt;The different heading levels match the level of nested sections. When you use a &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;, it means the top-level section. If you use a &lt;code&gt;&amp;lt;h3&amp;gt;&lt;/code&gt; after a &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt;, it means a sub-subsection. The levels are a way to add some &lt;strong&gt;hierarchy&lt;/strong&gt; to your content.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Headings form a &lt;a href=&quot;https://html.spec.whatwg.org/multipage/sections.html#headings-and-outlines-2&quot;&gt;&lt;strong&gt;document outline&lt;/strong&gt;&lt;/a&gt;. An outline is like a table of contents of your different headings in the order they appear on the page. I once read that headings can be thought of as chapters in a book.
Getting your headings right is a crucial first step toward making your document &lt;strong&gt;more semantic and accessible&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Let&#39;s look at a quick example:&lt;/p&gt;
&lt;pre class=&quot;language-tsx&quot;&gt;&lt;code class=&quot;language-tsx&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;Super cool business&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;section&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;About&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;Services&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;section&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;section&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;Guides&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;How to use our new AI product&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;section&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The outline of the following code would be:&lt;/p&gt;
&lt;pre class=&quot;language-plaintext&quot;&gt;&lt;code class=&quot;language-plaintext&quot;&gt;- Super cool business
	- About
		- Services
	- Guides
		- How to use our new AI product&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Some general rules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Do not create headings to make some text bigger. A heading marks a section of your document. It should help you determine whether the text is a heading or not.&lt;/li&gt;
&lt;li&gt;Don&#39;t forget to check the hierarchy of your headings. If you have an &lt;code&gt;h3&lt;/code&gt; after an &lt;code&gt;h2&lt;/code&gt;, does that make sense as a sub-subsection?&lt;/li&gt;
&lt;li&gt;Think of headings as a table of contents. This will help determine whether any headings are missing on the page. You can use an extension to quickly view the outline of your document. I use &lt;a href=&quot;https://chromewebstore.google.com/detail/html5-outliner/afoibpobokebhgfnknfndkgemglggomo&quot;&gt;HTML5 Outliner&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;let&#39;s-use-the-spec-to-answer-some-html-questions&quot; tabindex=&quot;-1&quot;&gt;Let&#39;s use the spec to answer some HTML questions&lt;/h2&gt;
&lt;p&gt;Let&#39;s see how the spec can help answer some HTML questions.&lt;/p&gt;
&lt;h3 id=&quot;question-1%3A-is-it-valid-html-to-use-a-%3Cp%3E-tag-inside-a-%3Cbutton%3E-element%3F&quot; tabindex=&quot;-1&quot;&gt;Question 1: Is it valid HTML to use a &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; tag inside a &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; element?&lt;/h3&gt;
&lt;p&gt;Can I write code like this?&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;svg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;/* some cool svg content */&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;svg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;See offer details&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&#39;s answer that step by step!&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;First, let&#39;s &lt;a href=&quot;https://html.spec.whatwg.org/multipage/form-elements.html#the-button-element&quot;&gt;look for the &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; element in the spec&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;To check what the element can contain, we can look at its content model. It states that it expects &lt;a href=&quot;https://html.spec.whatwg.org/multipage/dom.html#phrasing-content-2&quot;&gt;&lt;strong&gt;phrasing content&lt;/strong&gt;&lt;/a&gt; and that you should not nest any interactive element inside of a button. For instance, even if an &lt;code&gt;anchor&lt;/code&gt; link is considered phrasing content, you should not nest it inside of a button.&lt;/li&gt;
&lt;li&gt;If you &lt;a href=&quot;https://html.spec.whatwg.org/multipage/grouping-content.html#the-p-element&quot;&gt;search for the &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; tag inside the spec&lt;/a&gt;, you&#39;ll see it is not phrasing content.&lt;/li&gt;
&lt;li&gt;Therefore, we cannot use a &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; tag inside a &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;There are different options to fix the HTML. If it&#39;s about making the text take up its own line, we can add some CSS to the button, for instance.&lt;/p&gt;
&lt;h3 id=&quot;question-2%3A-how-to-caption-or-annotate-an-image%3F&quot; tabindex=&quot;-1&quot;&gt;Question 2: How to caption or annotate an image?&lt;/h3&gt;
&lt;p&gt;Let&#39;s imagine we have this piece of code:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://cute-dog-pic.png&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;A golden retriever holding a tennis ball in its mouth&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Our dog Poppy right before its 2nd birthday&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With CSS, we can make the &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; tag appear next to or underneath the picture. However, in the HTML, how do we group those two elements? Let&#39;s look at the specs!&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We are trying to create a relationship between 2 elements. So, the &lt;a href=&quot;https://html.spec.whatwg.org/multipage/grouping-content.html#grouping-content&quot;&gt;&amp;quot;Grouping content&amp;quot; subsection&lt;/a&gt; might be the best place to look.&lt;/li&gt;
&lt;li&gt;There are lots of different elements (&lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;ol&amp;gt;&lt;/code&gt;) in this subsection. However, for our image, &lt;a href=&quot;https://html.spec.whatwg.org/multipage/grouping-content.html#the-figure-element&quot;&gt;the &lt;code&gt;&amp;lt;figure&amp;gt;&lt;/code&gt; element&lt;/a&gt; is likely the most suitable choice in our case.&lt;/li&gt;
&lt;li&gt;We see that the &lt;code&gt;&amp;lt;figure&amp;gt;&lt;/code&gt; represents self-contained content, making sense on its own, optionally accompanied by a caption.&lt;/li&gt;
&lt;li&gt;In this case, we can use it to group our image with the text underneath, which we can then turn into a &lt;code&gt;&amp;lt;figcaption&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;figure&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://cute-dog-pic.png&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;A golden retriever holding a tennis ball in its mouth&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;figcaption&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Our dog Poppy right before its 2nd birthday&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;figcaption&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;figure&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;conclusion-and-quick-tips&quot; tabindex=&quot;-1&quot;&gt;Conclusion and quick tips&lt;/h2&gt;
&lt;p&gt;This is a brief overview of how to get started with the HTML spec and start using it. It may appear daunting at first, as it contains a lot of information. However, I hope this blog post gives you a glimpse of how useful it is when trying to mark up a document and choose what element to use.&lt;/p&gt;
&lt;p&gt;Some last quick tips:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can use the &lt;a href=&quot;https://html.spec.whatwg.org/multipage/indices.html#elements-3&quot;&gt;element index&lt;/a&gt; if you want to check for a specific HTML element. It will link you back to the specific section in the spec.&lt;/li&gt;
&lt;li&gt;When reading the spec, if you wonder what an element can contain, look at the &lt;strong&gt;content model&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Read the examples as they often complement or expand on how to use the element.&lt;/li&gt;
&lt;li&gt;Ask yourself how to describe the content best when you choose an HTML element.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;resources&quot; tabindex=&quot;-1&quot;&gt;Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://html.spec.whatwg.org/multipage/&quot;&gt;HTML Specification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://webaim.org/techniques/headings/&quot;&gt;Great article by WebAIM on headings&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://chromewebstore.google.com/detail/html5-outliner/afoibpobokebhgfnknfndkgemglggomo&quot;&gt;HTML5 Outliner Extension&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content
    >
  </entry> 
  <entry>
    <title>How to set up a pre-commit Git hook with Husky and lint-staged</title>
    <link href="
  https://oliviac.dev/blog/set_up_pre_commit_hook_husky_lint_staged/
  " />
    <updated>2025-05-26T00:00:00Z</updated>
    <id>
  https://oliviac.dev/blog/set_up_pre_commit_hook_husky_lint_staged/
  </id>
    <content
      type="html"
      >&lt;p&gt;Git hooks are a great way to automatically run specific tasks (such as formatting or linting tasks) at key moments in your Git workflow. In this post, we&#39;ll explore Git hooks and walk through how to set up a pre-commit hook using &lt;a href=&quot;https://www.npmjs.com/package/husky&quot;&gt;Husky&lt;/a&gt; and &lt;a href=&quot;https://www.npmjs.com/package/lint-staged&quot;&gt;lint-staged&lt;/a&gt; to lint and format your staged files automatically. Let’s dive in.&lt;/p&gt;
&lt;h2 id=&quot;what-are-git-hooks%3F&quot; tabindex=&quot;-1&quot;&gt;What are Git hooks?&lt;/h2&gt;
&lt;p&gt;As mentioned in the &lt;a href=&quot;https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks&quot;&gt;Git documentation&lt;/a&gt;, Git hooks are a way to run scripts at specific moments in your Git workflow. They can help automate repetitive checks and enforce formatting or linting rules that help collaboration.&lt;/p&gt;
&lt;p&gt;Inside any Git-tracked project, open the &lt;code&gt;.git&lt;/code&gt; folder. You’ll find a series of folders that include a &lt;code&gt;hooks&lt;/code&gt; folder.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Structure inside a .git folder showing the hooks directory among others&quot; src=&quot;https://oliviac.dev/img/git-folder.png&quot; /&gt;
  &lt;figcaption&gt;Structure inside a .git folder showing the hooks directory, among others.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The &lt;strong&gt;hooks folder&lt;/strong&gt; contains example hook scripts (e.g., &lt;code&gt;pre-commit.sample&lt;/code&gt;) that you can customize to automate tasks before commits, pushes and more. To make our lives easier, we’ll use &lt;code&gt;husky&lt;/code&gt; to set up a Git hook. Husky makes it easy to create shareable Git hooks that you can add to version control.&lt;/p&gt;
&lt;h2 id=&quot;setting-up-the-demo-project&quot; tabindex=&quot;-1&quot;&gt;Setting up the demo project&lt;/h2&gt;
&lt;p&gt;In this blog post, we’ll work with a simple repository that contains a small React app created with &lt;a href=&quot;https://vite.dev/guide/#scaffolding-your-first-vite-project&quot;&gt;Vite&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To follow along, scaffold a Vite React and Typescript app:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; create vite@latest demo-git-hooks-husky -- &lt;span class=&quot;token parameter variable&quot;&gt;--template&lt;/span&gt; react-ts
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; demo-git-hooks-husky &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point, you have a basic “Hello World” React app. The Vite boilerplate includes an &lt;code&gt;eslint.config.js&lt;/code&gt; file to lint the files. Let’s install &lt;code&gt;prettier&lt;/code&gt; to format our files:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; --save-dev prettier&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, create &lt;code&gt;.prettierrc&lt;/code&gt; at the root of the project with basic rules:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;arrowParens&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;always&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;bracketSpacing&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;printWidth&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;semi&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;singleQuote&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;tabWidth&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;trailingComma&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;es5&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;useTabs&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;installing-and-configuring-husky&quot; tabindex=&quot;-1&quot;&gt;Installing and configuring Husky&lt;/h2&gt;
&lt;p&gt;Husky is a development dependency to make it easier to add Git hooks. First, let’s install it:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; --save-dev husky&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once Husky is installed, run the following:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;npx husky init&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As explained in the &lt;a href=&quot;https://typicode.github.io/husky/get-started.html#husky-init-recommended&quot;&gt;official documentation&lt;/a&gt;, this command adds a “prepare” script to the &lt;code&gt;package.json&lt;/code&gt; and creates a &lt;code&gt;pre-commit&lt;/code&gt; hook in the &lt;code&gt;.husky&lt;/code&gt; folder you should now have at the root of your repository.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;prepare&lt;/code&gt; script is one of the NPM lifecycle scripts that run automatically at specific moments. The &lt;code&gt;prepare&lt;/code&gt; script runs on local &lt;code&gt;npm install&lt;/code&gt; even when no arguments get passed (&lt;a href=&quot;https://docs.npmjs.com/cli/v10/using-npm/scripts#life-cycle-scripts&quot;&gt;see the NPM doc for more details on the &lt;code&gt;prepare&lt;/code&gt; script&lt;/a&gt;). This means that any developer who installs the project dependencies will automatically have the Git hooks correctly set up with Husky.&lt;/p&gt;
&lt;p&gt;Let’s configure the &lt;code&gt;pre-commit&lt;/code&gt; hook that was automatically created to make it more relevant to our project!&lt;/p&gt;
&lt;h2 id=&quot;configuring-the-pre-commit-script-with-lint-staged&quot; tabindex=&quot;-1&quot;&gt;Configuring the &lt;code&gt;pre-commit&lt;/code&gt; script with lint-staged&lt;/h2&gt;
&lt;p&gt;In our demo app, we have linting and formatting rules we want to apply to all our source files. While you could run linting and formatting as a GitHub action on push or pull requests, a &lt;code&gt;pre-commit&lt;/code&gt; hook provides faster feedback by catching issues before a commit is created.
When we try to commit a series of changes, we can write our Git hook to run a list of checks &lt;strong&gt;before a commit gets created&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;update-the-package.json-lint-and-format-scripts&quot; tabindex=&quot;-1&quot;&gt;Update the package.json lint and format scripts&lt;/h3&gt;
&lt;p&gt;By default, the &lt;code&gt;pre-commit&lt;/code&gt; hook in &lt;code&gt;.husky&lt;/code&gt; contains:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;test&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A good start is to ensure that all files are checked by our linter and formatted before they are committed to Git. In our &lt;code&gt;package.json&lt;/code&gt;, we already have a &lt;code&gt;lint&lt;/code&gt; script. Let&#39;s add a few more:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;scripts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;lint&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;eslint .&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;lint:fix&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;eslint --max-warnings=0 --fix&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;format&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;prettier --write .&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;format:file&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;prettier --write&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;lint&lt;/code&gt; runs &lt;code&gt;eslint&lt;/code&gt; on all the files.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;lint:fix&lt;/code&gt; script will try to auto-fix linting issues where possible. With the flag &lt;code&gt;--max-warnings=0&lt;/code&gt;, it will fail (exit with an error) if any errors or warnings remain. We’ll use this script in our pre-commit to add an extra layer of protection and make sure to know as soon as possible if we need to fix the code manually.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;format&lt;/code&gt; will format and &lt;strong&gt;write&lt;/strong&gt; the changes.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;format:file&lt;/code&gt; script formats the files passed to it, which works well with &lt;code&gt;lint-staged&lt;/code&gt; since it provides the staged files as input. It is a slight optimization as a way to only run prettier on staged files and not on the whole project.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;setting-up-lint-staged-to-lint-and-format-staged-files&quot; tabindex=&quot;-1&quot;&gt;Setting up lint-staged to lint and format staged files&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.npmjs.com/package/lint-staged&quot;&gt;&lt;code&gt;lint-staged&lt;/code&gt;&lt;/a&gt; is an NPM package that will help us run our linter or formatter on staged files. We don’t want commits to fail because of issues in unrelated files. &lt;code&gt;lint-staged&lt;/code&gt; will help us &lt;strong&gt;run the checks we define in our pre-commit hook on the files that are in the Git staging area&lt;/strong&gt;. The Git staging area is where your tracked files get placed after you use &lt;code&gt;git add the-file-you-modified&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let’s install &lt;code&gt;lint-staged&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; --save-dev lint-staged&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are many options to configure &lt;code&gt;lint-staged&lt;/code&gt;. One of them is to create a &lt;code&gt;.lintstagedrc&lt;/code&gt; at the root of the project.&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;touch&lt;/span&gt; .lintstagedrc&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the configuration file for &lt;code&gt;lint-staged&lt;/code&gt;, we associate file extensions with the &lt;code&gt;npm&lt;/code&gt; scripts we want to run for those files. Let’s add the following config to our &lt;code&gt;.lintstagedrc&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;*.{js,jsx,ts,tsx}&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;npm run lint:fix&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;npm run format:file&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;*.{json,md,mdx,css,scss,html,yml,yaml}&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;npm run format:file&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also add lint-staged configuration directly in the &lt;code&gt;package.json&lt;/code&gt; if you do not want to create an extra configuration file:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;lint-staged&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;*.{js,jsx,ts,tsx}&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;npm run lint:fix&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;npm run format:file&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;*.{json,md,mdx,css,scss,html,yml,yaml}&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;npm run format:file&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s now add an NPM script to the package.json to run lint-staged:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;scripts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;check:precommit&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;lint-staged&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;use-lint-staged-with-the-husky-pre-commit-hook&quot; tabindex=&quot;-1&quot;&gt;Use lint-staged with the husky &lt;code&gt;pre-commit&lt;/code&gt; hook&lt;/h2&gt;
&lt;p&gt;Now that we have lint-staged configured, we can modify the &lt;code&gt;.husky/precommit&lt;/code&gt; file and use the &lt;code&gt;check:precommit&lt;/code&gt; script we have added to the &lt;code&gt;package.json&lt;/code&gt;. In &lt;code&gt;.husky/pre-commit&lt;/code&gt;, add the following content:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; run check:precommit&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With all those changes, we now have a working pre-commit setup that uses eslint and prettier on the files we want to commit.&lt;/p&gt;
&lt;h2 id=&quot;under-the-hood%3A-how-does-husky-work%3F&quot; tabindex=&quot;-1&quot;&gt;Under the hood: how does husky work?&lt;/h2&gt;
&lt;p&gt;When husky is installed, it runs a script that updates the &lt;code&gt;.git/config&lt;/code&gt; file by setting the &lt;code&gt;core.hooksPath&lt;/code&gt; to the &lt;code&gt;.husky&lt;/code&gt; directory. This tells Git to look in &lt;code&gt;.husky&lt;/code&gt; for hook scripts instead of the default &lt;code&gt;.git/hooks&lt;/code&gt; directory.&lt;/p&gt;
&lt;p&gt;In &lt;code&gt;.git/config&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-ini&quot;&gt;&lt;code class=&quot;language-ini&quot;&gt;&lt;span class=&quot;token section&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token section-name selector&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
  ...
  &lt;span class=&quot;token key attr-name&quot;&gt;hooksPath&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token value attr-value&quot;&gt;.husky/_&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the &lt;code&gt;husky&lt;/code&gt; source code, in the &lt;a href=&quot;https://github.com/typicode/husky/blob/main/index.js&quot;&gt;&lt;code&gt;index.js&lt;/code&gt;&lt;/a&gt;, there is a statement that sets up the &lt;code&gt;hooksPath&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token literal-property property&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; s&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;stderr&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; c&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;spawnSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;git&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&#39;config&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&#39;core.hooksPath&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;d&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/_&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above snippet, &lt;code&gt;c.spawnSync&lt;/code&gt; is a way to launch a child process in Node. This is like running &lt;code&gt;git config core.hooksPath &amp;lt;some_path&amp;gt;&lt;/code&gt; in the terminal.&lt;/p&gt;
&lt;h2 id=&quot;final-project-setup-overview%3A-putting-everything-together&quot; tabindex=&quot;-1&quot;&gt;Final project setup overview: Putting everything together&lt;/h2&gt;
&lt;p&gt;Here&#39;s a quick overview of the key files and their contents once everything is configured:&lt;/p&gt;
&lt;p&gt;In package.json:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;scripts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;lint&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;eslint .&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;format&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;prettier --write .&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;format:file&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;prettier --write&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;lint:fix&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;eslint --max-warnings=0 --fix&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;check:precommit&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;lint-staged&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;devDependencies&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;eslint&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;...&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;husky&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;...&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;lint-staged&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;...&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;prettier&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;...&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In &lt;code&gt;.husky/pre-commit&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; run check:precommit&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In &lt;code&gt;.lintstagedrc&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;*.{js,jsx,ts,tsx}&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;npm run lint:fix&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;npm run format:file&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;*.{json,md,mdx,css,scss,html,yml,yaml}&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;npm run format:file&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This provides a fast, local pre-commit workflow to catch linting or formatting issues before they are committed to Git.&lt;/p&gt;
&lt;p&gt;You can find the whole demo on &lt;a href=&quot;https://github.com/liv7c/demo-git-hooks-husky&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;troubleshooting&quot; tabindex=&quot;-1&quot;&gt;Troubleshooting&lt;/h2&gt;
&lt;p&gt;If the pre-commit does not work:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Make sure you&#39;ve staged the files using &lt;code&gt;git add&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Make sure you&#39;ve staged a file that your lint-staged configuration supports (a &lt;code&gt;tsx&lt;/code&gt;, &lt;code&gt;js&lt;/code&gt; or whatever extension you have configured).&lt;/li&gt;
&lt;li&gt;Reinstall the dependencies if you do not see a &lt;code&gt;.husky&lt;/code&gt; folder at the root of your project.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this blog post, we explored how to use &lt;code&gt;husky&lt;/code&gt; to create a pre-commit hook and how to use lint-staged to run checks on staged files.
Pre-commit hooks help catch problems early and are a fantastic way to improve consistency when working on a shared codebase. I hope you find this blog post helpful. If you have any questions, don’t hesitate to reach out on &lt;a href=&quot;https://bsky.app/profile/oliviac.dev&quot;&gt;Bluesky&lt;/a&gt; 😀&lt;/p&gt;
&lt;h2 id=&quot;resources&quot; tabindex=&quot;-1&quot;&gt;Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/typicode/husky&quot;&gt;Husky repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/lint-staged&quot;&gt;lint-staged package&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks&quot;&gt;Git official documentation on Git hooks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.npmjs.com/cli/v10/using-npm/scripts#life-cycle-scripts&quot;&gt;NPM documentation on the different package.json life cycle scripts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content
    >
  </entry> 
  <entry>
    <title>How to use jq with curl to explore an API’s JSON response</title>
    <link href="
  https://oliviac.dev/blog/how-to-use-jq-with-curl/
  " />
    <updated>2025-06-22T00:00:00Z</updated>
    <id>
  https://oliviac.dev/blog/how-to-use-jq-with-curl/
  </id>
    <content
      type="html"
      >&lt;p&gt;&lt;a href=&quot;https://github.com/jqlang/jq&quot;&gt;jq&lt;/a&gt; is a useful command-line tool to process a JSON payload quickly. I tend to use &lt;code&gt;jq&lt;/code&gt; in conjunction with &lt;code&gt;curl&lt;/code&gt; to explore third-party APIs. &lt;code&gt;jq&lt;/code&gt; is a powerful tool for filtering or transforming JSON data. In this article, we’ll explore a couple of its functionalities while playing with two free third-party APIs. The goal is to become more comfortable with &lt;code&gt;jq&lt;/code&gt; by the end of the blog post and to have started building a cheat sheet of our own.&lt;/p&gt;
&lt;h2 id=&quot;how-to-install-jq&quot; tabindex=&quot;-1&quot;&gt;How to install &lt;code&gt;jq&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;To install &lt;code&gt;jq&lt;/code&gt;, you can download the binary on the &lt;a href=&quot;https://jqlang.org/&quot;&gt;&lt;code&gt;jq&lt;/code&gt; website&lt;/a&gt;. If you are on a Mac, you can install &lt;code&gt;jq&lt;/code&gt; with &lt;a href=&quot;https://brew.sh/&quot;&gt;&lt;code&gt;homebrew&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;brew &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; jq&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For a complete set of installation instructions, check out the &lt;a href=&quot;https://github.com/jqlang/jq?tab=readme-ov-file#installation&quot;&gt;Github repository section on that topic&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;what-is-jq-and-what-can-we-do-with-it%3F&quot; tabindex=&quot;-1&quot;&gt;What is jq and what can we do with it?&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;jq&lt;/code&gt; is described in &lt;a href=&quot;https://jqlang.org/&quot;&gt;its official documentation&lt;/a&gt; as a “lightweight and flexible command-line JSON processor”. &lt;code&gt;jq&lt;/code&gt; is lightweight and quick (it is written in C). Its flexibility comes from the number of features and possibilities available when using it. You could use jq to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pipe JSON data (&lt;code&gt;curl &amp;lt;URL&amp;gt; | jq .&lt;/code&gt;) and get a formatted and colored output.&lt;/li&gt;
&lt;li&gt;Filter out keys and quickly extract the data you are interested in from a JSON output.&lt;/li&gt;
&lt;li&gt;Sort a JSON output based on a specific key.&lt;/li&gt;
&lt;li&gt;Limit the JSON output to &lt;code&gt;n&lt;/code&gt; elements (for instance, you might want the first five elements from a JSON array).&lt;/li&gt;
&lt;li&gt;Retrieve all the keys of a JSON response (this might be handy when interacting with a third-party API).&lt;/li&gt;
&lt;li&gt;And much more!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In all the commands we’ll explore, we’ll &lt;em&gt;pipe&lt;/em&gt; JSON data to &lt;code&gt;jq&lt;/code&gt; to process. Piping means taking the output of a command (such as curl returning API data) and directly passing it to another program for processing. In the shell, to pipe an output, we use the &lt;code&gt;|&lt;/code&gt; symbol. For instance:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;URL&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; jq &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The previous command uses &lt;code&gt;curl&lt;/code&gt; to fetch the data available at a given URL. Then, it passes the data to &lt;code&gt;jq&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You don’t need to pipe data to &lt;code&gt;jq&lt;/code&gt; to use it. You can pass a JSON file to jq as an argument:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;jq &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;filepath_to_json_file&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;processing-json-data-with-jq&quot; tabindex=&quot;-1&quot;&gt;Processing JSON data with &lt;code&gt;jq&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Let’s get started working with JSON arrays. For this section, we will use the &lt;a href=&quot;https://jsonplaceholder.typicode.com/&quot;&gt;JSON placeholder&lt;/a&gt; that provides dummy To-Do API endpoints.&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; https://jsonplaceholder.typicode.com/todos&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this command, we obtain a JSON array of 200 elements.&lt;/p&gt;
&lt;h3 id=&quot;extract-the-length-of-a-json-array-with-jq&quot; tabindex=&quot;-1&quot;&gt;Extract the length of a JSON array with &lt;code&gt;jq&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;If you are wondering how many items are in a JSON array, you can use the &lt;code&gt;length&lt;/code&gt; helper in &lt;code&gt;jq&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; https://jsonplaceholder.typicode.com/todos &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; jq length&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In your terminal, you should see a single number as an output (&lt;code&gt;200&lt;/code&gt; in our case).&lt;/p&gt;
&lt;h3 id=&quot;getting-an-item-at-a-given-index-from-a-json-array-with-jq&quot; tabindex=&quot;-1&quot;&gt;Getting an item at a given index from a JSON array with &lt;code&gt;jq&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Getting the first item of a JSON array is as simple as typing &lt;code&gt;jq &#39;.[0]&#39;&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; https://jsonplaceholder.typicode.com/todos &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; jq &lt;span class=&quot;token string&quot;&gt;&#39;.[0]&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To get the last item of an array, you can use &lt;code&gt;jq &#39;.[-1]&#39;&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; https://jsonplaceholder.typicode.com/todos &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; jq &lt;span class=&quot;token string&quot;&gt;&#39;.[-1]&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;getting-n-elements-of-an-array-with-jq&quot; tabindex=&quot;-1&quot;&gt;Getting &lt;code&gt;n&lt;/code&gt; elements of an array with &lt;code&gt;jq&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;To get the first five elements, you can use a similar notation to Go’s slices:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; https://jsonplaceholder.typicode.com/todos &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; jq &lt;span class=&quot;token string&quot;&gt;&#39;.[:5]&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you write down &lt;code&gt;[:5]&lt;/code&gt;, it means all the indices (starting at 0) &lt;strong&gt;excluding the index of 5&lt;/strong&gt;. You can provide the starting index if you have a range in mind:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; https://jsonplaceholder.typicode.com/todos &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; jq &lt;span class=&quot;token string&quot;&gt;&#39;.[2:5]&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above command &lt;code&gt;jq ‘[2:5]’&lt;/code&gt; includes three elements (the elements at index 2, 3, and 4).&lt;/p&gt;
&lt;h3 id=&quot;selecting-specific-properties&quot; tabindex=&quot;-1&quot;&gt;Selecting specific properties&lt;/h3&gt;
&lt;p&gt;Let’s switch things up! Many APIs include a large amount of data that we may not be interested in. Let’s use the &lt;a href=&quot;https://swapi.py4e.com/documentation&quot;&gt;swapi API&lt;/a&gt; to explore a more complex dataset.&lt;/p&gt;
&lt;p&gt;If we retrieve the Star Wars characters using &lt;a href=&quot;https://swapi.py4e.com/api/people/&quot;&gt;the API&#39;s people endpoint&lt;/a&gt;, we’ll see that the output puts all the characters in a &lt;code&gt;results&lt;/code&gt; key. The top-level keys in the output JSON object include pagination data.&lt;/p&gt;
&lt;p&gt;To solely include the people, we can write:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; https://swapi.py4e.com/api/people/ &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; jq &lt;span class=&quot;token string&quot;&gt;&quot;.results&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;jq “.results”&lt;/code&gt; will process the JSON data and output the result array.&lt;/p&gt;
&lt;p&gt;Then, we can use the previous commands we have learned. We could get the first character from the people API using the following command:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; https://swapi.py4e.com/api/people/ &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; jq &lt;span class=&quot;token string&quot;&gt;&quot;.results | .[0]&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can go even further than that. We can extract the keys we are interested in from the results array.&lt;/p&gt;
&lt;h3 id=&quot;using-the-map-function-to-pick-specific-keys-from-array-items&quot; tabindex=&quot;-1&quot;&gt;Using the map function to pick specific keys from array items&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;map&lt;/code&gt; in &lt;code&gt;jq&lt;/code&gt; will do something similar to the &lt;code&gt;map&lt;/code&gt; array function in JavaScript. It applies a given transformation to each item in the array.&lt;/p&gt;
&lt;p&gt;In &lt;code&gt;jq&lt;/code&gt;, we can build new JSON objects with the properties we want using a shorthand like &lt;code&gt;{name, url}&lt;/code&gt;. This syntax is equivalent to writing &lt;code&gt;{“name”: .name, “url”: .url}&lt;/code&gt;. In our case, we can pass this shorthand to &lt;code&gt;map&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; https://swapi.py4e.com/api/people/ &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; jq &lt;span class=&quot;token string&quot;&gt;&quot;.results | map({name, url})&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It extracts the &lt;code&gt;results&lt;/code&gt; properties and maps each item in the results array to a smaller object containing only the &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;url&lt;/code&gt; fields. In your terminal, you should see an output that looks like the following snippet:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Luke Skywalker&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://swapi.py4e.com/api/people/1/&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;C-3PO&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://swapi.py4e.com/api/people/2/&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// more data...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Beyond picking the properties we are interested in, we can filter the data using &lt;code&gt;jq&lt;/code&gt;. Let’s look at how next!&lt;/p&gt;
&lt;h3 id=&quot;filtering-data-using-the-select-function-in-jq&quot; tabindex=&quot;-1&quot;&gt;Filtering data using the &lt;code&gt;select&lt;/code&gt; function in &lt;code&gt;jq&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Let’s imagine we are looking for one character in particular in our Star Wars API. We can use the &lt;code&gt;select&lt;/code&gt; function to filter by a specific property, such as &lt;code&gt;name&lt;/code&gt; in our case.&lt;/p&gt;
&lt;p&gt;We can do the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;curl&lt;/code&gt; to retrieve data from a specified URL.&lt;/li&gt;
&lt;li&gt;Combine the &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;select&lt;/code&gt; functions to look for our character.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; https://swapi.py4e.com/api/people/ &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; jq &lt;span class=&quot;token string&quot;&gt;&#39;.results | map(select(.name == &quot;Obi-Wan Kenobi&quot;))&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above command, we will select items with a name that matches the string “Obi-Wan Kenobi”.&lt;/p&gt;
&lt;p&gt;If we want to be less restrictive, we can use a regex:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; https://swapi.py4e.com/api/people/ &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; jq &lt;span class=&quot;token string&quot;&gt;&#39;.results | map(select(.name | test(&quot;Leia&quot;; &quot;i&quot;)))&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We pipe the &lt;code&gt;.name&lt;/code&gt; property of each item to the &lt;code&gt;test&lt;/code&gt; function. The second argument of &lt;code&gt;test&lt;/code&gt; is to make the matching pattern case-insensitive.&lt;/p&gt;
&lt;p&gt;There are other functions we can use with select, such as &lt;code&gt;startswith&lt;/code&gt; or &lt;code&gt;endswith&lt;/code&gt;. For instance, let’s say we want all the movies whose title starts with &#39;The&#39;. We could write the following command:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; https://swapi.py4e.com/api/films/ &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; jq &lt;span class=&quot;token string&quot;&gt;&#39;.results | map(select(.title | startswith(&quot;The&quot;)))&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;We first pick the &lt;code&gt;.results&lt;/code&gt; property from the JSON object returned by the API.&lt;/li&gt;
&lt;li&gt;Then, we use &lt;code&gt;map&lt;/code&gt; to indicate this is an operation on each list item. For each list item, we want to select the films with titles that start with “The”.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;sorting-an-array-of-objects-with-jq&quot; tabindex=&quot;-1&quot;&gt;Sorting an array of objects with &lt;code&gt;jq&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Another useful feature of &lt;code&gt;jq&lt;/code&gt; is the ability to sort data using the &lt;code&gt;sort_by&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;Let’s go back to our Star Wars API. Let’s imagine we want to sort the characters by their height.&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; https://swapi.py4e.com/api/people/ &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; jq &lt;span class=&quot;token string&quot;&gt;&quot;.results | sort_by(.height | tonumber) | reverse | map({name, height})&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s dissect that command:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We curl the &lt;code&gt;people&lt;/code&gt; endpoint from the Star Wars API.&lt;/li&gt;
&lt;li&gt;We pick the &lt;code&gt;results&lt;/code&gt; property as it contains the array of characters on the first page.&lt;/li&gt;
&lt;li&gt;We sort the array by each element’s height. Because the API returns each character height as a string, we must convert each height to a number to obtain a correct sorting result.&lt;/li&gt;
&lt;li&gt;We pass to &lt;code&gt;sort_by&lt;/code&gt; the property we want to use to sort our array. We can convert the property if needed. In the example, we use &lt;code&gt;tonumber&lt;/code&gt; to cast each string into a number.&lt;/li&gt;
&lt;li&gt;Then, we can pipe the results to &lt;code&gt;reverse&lt;/code&gt; if we want to reverse the order of the results. In our case, it will return an array from the character with the largest height to the character with the smallest height.&lt;/li&gt;
&lt;li&gt;Finally, we use &lt;code&gt;map&lt;/code&gt; to extract the name and height of each character.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The output looks like:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Darth Vader&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&quot;height&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;202&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Biggs Darklighter&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&quot;height&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;183&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Obi-Wan Kenobi&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&quot;height&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;182&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// some more sorted data...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;inspecting-the-keys-of-a-payload&quot; tabindex=&quot;-1&quot;&gt;Inspecting the keys of a payload&lt;/h3&gt;
&lt;p&gt;To get a quick idea of what keys a given JSON payload contains, you can use the &lt;code&gt;keys&lt;/code&gt; function.&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; https://swapi.py4e.com/api/people/ &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; jq &lt;span class=&quot;token string&quot;&gt;&quot;keys&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In a glimpse, we get back an array of all the keys from the API response:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;count&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;next&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;previous&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;results&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we wanted to get an idea of what type of data the API has for a character, we could do:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; https://swapi.py4e.com/api/people/ &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; jq &lt;span class=&quot;token string&quot;&gt;&quot;.results[0] | keys&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this command, we look at the first element of the result array and get back its keys:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// output from the previous curl command&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;birth_year&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;created&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;edited&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;eye_color&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;films&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;gender&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;hair_color&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;height&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;homeworld&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;mass&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;skin_color&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;species&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;starships&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;vehicles&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;cheat-sheet-and-recap&quot; tabindex=&quot;-1&quot;&gt;Cheat sheet and recap&lt;/h2&gt;
&lt;p&gt;Here&#39;s a small list of the different commands we tried in this post:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;curl &amp;lt;URL&amp;gt; | jq .&lt;/code&gt;: to pretty-print JSON from an API.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jq . &amp;lt;file.json&amp;gt;&lt;/code&gt;: to process JSON data from a local file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;curl -s &amp;lt;URL&amp;gt; | jq length&lt;/code&gt;: to count the number of items in an array (it will only work with JSON arrays).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;curl -s &amp;lt;URL&amp;gt; | jq &#39;.[0]&#39;&lt;/code&gt;: to get the first element of an array.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;curl -s &amp;lt;URL&amp;gt; | jq &#39;.[-1]&#39;&lt;/code&gt;: to get the last element of an array.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;curl -s &amp;lt;URL&amp;gt; | jq &#39;[:5]&#39;&lt;/code&gt;: to get the first N elements of an array (in this case 5).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;curl -s &amp;lt;URL&amp;gt; | jq &#39;.[2:5]&#39;&lt;/code&gt;: to get a slice of an array (indices 2 to 4 in this example).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;curl -s &amp;lt;URL&amp;gt; | jq &#39;.results&#39;&lt;/code&gt;: to extract a specific key from a JSON object.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;curl -s &amp;lt;URL&amp;gt; | jq &#39;.results[0]&#39;&lt;/code&gt;: to get the first object in an array of objects.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;curl -s &amp;lt;URL&amp;gt; | jq &#39;.results | map({name, url})&#39;&lt;/code&gt;: to map array and extract specific keys from each array item.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;curl -s &amp;lt;URL&amp;gt; | jq &#39;.results | map(select(.name == &amp;quot;Obi-Wan Kenobi&amp;quot;))&#39;&lt;/code&gt;: to filter array items using an exact match.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;curl -s &amp;lt;URL&amp;gt; | jq &#39;.results | map(select(.name | test(&amp;quot;Leia&amp;quot;; &amp;quot;i&amp;quot;)))&#39;&lt;/code&gt;: to filter array items using a regular expression.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;curl -s &amp;lt;URL&amp;gt; | jq &#39;.results | map(select(.title | startswith(&amp;quot;The&amp;quot;)))&#39;&lt;/code&gt;: to filter array items where their title starts with a given string.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;curl -s &amp;lt;URL&amp;gt; | jq &#39;.results | sort_by(.height | tonumber) | reverse | map({name, height})&#39;&lt;/code&gt;: to sort by height (casting the height into a number), using a descending order.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;curl -s &amp;lt;URL&amp;gt; | jq &#39;keys&#39;&lt;/code&gt;: to list the keys at the root level.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;curl -s &amp;lt;URL&amp;gt; | jq &#39;.results[0] | keys&#39;&lt;/code&gt;: to list the keys of the first item in the &lt;code&gt;results&lt;/code&gt; array.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this article, we explored the &lt;code&gt;jq&lt;/code&gt; command-line utility. It is a powerful tool for processing and transforming JSON data. We’ve only brushed the surface of what &lt;code&gt;jq&lt;/code&gt; can do. I hope this post provides some ideas on how to use it. As always, if you have any questions or want to chat about &lt;code&gt;jq&lt;/code&gt; or other command-line tools, reach out on &lt;a href=&quot;https://bsky.app/profile/oliviac.dev&quot;&gt;Bluesky&lt;/a&gt;!&lt;/p&gt;
&lt;h2 id=&quot;resources&quot; tabindex=&quot;-1&quot;&gt;Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://jqlang.org/manual/&quot;&gt;&lt;code&gt;jq&lt;/code&gt; Manual&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jqlang/jq&quot;&gt;&lt;code&gt;jq&lt;/code&gt; Github page&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content
    >
  </entry> 
  <entry>
    <title>Build Git helpers from scratch with Bash and fzf</title>
    <link href="
  https://oliviac.dev/blog/build-git-helpers-bash-fzf/
  " />
    <updated>2025-08-03T00:00:00Z</updated>
    <id>
  https://oliviac.dev/blog/build-git-helpers-bash-fzf/
  </id>
    <content
      type="html"
      >&lt;p&gt;&lt;a href=&quot;https://github.com/junegunn/fzf&quot;&gt;&lt;code&gt;fzf&lt;/code&gt;&lt;/a&gt; is a command-line fuzzy-finder you can run in your terminal to filter any list of files, command history, and more. &lt;code&gt;fzf&lt;/code&gt; is versatile and can be used in combination with other tools such as grep and Git.&lt;/p&gt;
&lt;p&gt;In this blog post, we’ll explore how to create small bash helpers for Git using &lt;code&gt;fzf&lt;/code&gt;.
By the end of this post, you’ll understand what &lt;code&gt;fzf&lt;/code&gt; is and how to combine its power with other tools. I hope this tutorial also gives you lots of ideas for applying similar techniques to build your own helpers. Let&#39;s get started!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: if you&#39;re looking for a prebuilt plugin with Git and fzf integrations, check out &lt;a href=&quot;https://github.com/junegunn/fzf-git.sh&quot;&gt;fzf-git.sh&lt;/a&gt; by the creator of fzf. This blog post focuses on building small helpers from scratch combining different programs to make the whole thing less intimidating. Playing around with Bash and fzf is a lot of fun. I hope you enjoy the post!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;what-fzf-is-and-how-to-install-it&quot; tabindex=&quot;-1&quot;&gt;What fzf is and how to install it&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;fzf&lt;/code&gt; is a command-line fuzzy-finder. It is a tool that enables you to quickly browse any kind of list and search for matches by typing.&lt;/p&gt;
&lt;p&gt;In the &lt;code&gt;fzf&lt;/code&gt; repository on Github, you can find &lt;a href=&quot;https://github.com/junegunn/fzf?tab=readme-ov-file#installation&quot;&gt;detailed instructions on how to install it based on your operating system&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;On MacOS, the easiest way is to install it using &lt;code&gt;homebrew&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;brew &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; fzf&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once you’ve installed it, if you type &lt;code&gt;fzf&lt;/code&gt; in your terminal, you should see a list of all the files in your current directory.&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;fzf&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;integrate-fzf-with-bash&quot; tabindex=&quot;-1&quot;&gt;Integrate fzf with Bash&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;fzf&lt;/code&gt; integrates well with several shells, including Bash and Zsh. Integrating it with your shell activates a series of cool features, such as being able to select a command in your command-line history and paste it.&lt;/p&gt;
&lt;p&gt;Add this to your &lt;code&gt;bashrc&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Set up fzf key bindings and fuzzy completion&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;eval&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;fzf &lt;span class=&quot;token parameter variable&quot;&gt;--bash&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you are following along using another shell, check out &lt;a href=&quot;https://github.com/junegunn/fzf?tab=readme-ov-file#setting-up-shell-integration&quot;&gt;the official documentation on how to set shell integration&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Don’t forget to source your shell config after modifying it (e.g., &lt;code&gt;source ~/.bashrc&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Now, what does adding shell integration do?
You should now be able to type &lt;code&gt;&amp;lt;Ctrl-r&amp;gt;&lt;/code&gt; (Control key + r) in your terminal, select a command from your history, and paste it directly into your terminal.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://oliviac.dev/blog/img/command_hist_fzf.png&quot; alt=&quot;&amp;quot;Output of using Control + r in the command line. It displays a list of commands from the command history&amp;quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I use this keybinding &lt;strong&gt;all the time&lt;/strong&gt;. Now, let’s move to the next level and see how we can build useful utilities with &lt;code&gt;fzf&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;combine-the-power-of-fzf-with-git-to-create-small-helpers&quot; tabindex=&quot;-1&quot;&gt;Combine the power of fzf with Git to create small helpers&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;fzf&lt;/code&gt; is a fuzzy-finder, and you can pipe data from many sources, including Git, into it. This makes it easy to create small helpers. Let’s build a couple of helpers to use Git more efficiently.
To follow along, create a new file in your home directory called &lt;code&gt;.bash_helpers&lt;/code&gt; (you can call it whatever you want!):&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;touch&lt;/span&gt; ~/.bash_helpers&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, source it in your &lt;code&gt;.bashrc&lt;/code&gt;. Sourcing it tells your shell to import all the functions from the &lt;code&gt;~/.bash_helpers&lt;/code&gt; so you can use them.&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Add this to your ~/.bashrc&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;source&lt;/span&gt; ~/.bash_helpers&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is a good way to keep things more organized.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;After modifying &lt;code&gt;.bashrc&lt;/code&gt; or &lt;code&gt;.bash_helpers&lt;/code&gt;, don&#39;t forget to source your shell config (&lt;code&gt;source ~/.bashrc&lt;/code&gt;) in your terminal to apply the changes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;let%E2%80%99s-create-a-helper-to-check-out-a-specific-git-branch&quot; tabindex=&quot;-1&quot;&gt;Let’s create a helper to check out a specific git branch&lt;/h3&gt;
&lt;p&gt;If you navigate to a local Git repository, you can list all of your branches using:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; --no-pager branch&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above command:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--no-pager&lt;/code&gt; is used to remove Git pagination and get the full list of branches.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If we pipe it to &lt;code&gt;fzf&lt;/code&gt;, we end up with a list of the git branches that we can search through and select.&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; --no-pager branch &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; fzf&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The idea for this first example is to create a helper that shows us the list of branches through &lt;code&gt;fzf&lt;/code&gt; and, when we select a branch, we switch to that branch.&lt;/p&gt;
&lt;p&gt;In the &lt;code&gt;.bash_helpers&lt;/code&gt;, let’s create a function and let’s call it, for instance, &lt;code&gt;sfb&lt;/code&gt; (for &lt;code&gt;“switch find branch”&lt;/code&gt;):&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-name function&quot;&gt;sfb&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token builtin class-name&quot;&gt;local&lt;/span&gt; line branch
	&lt;span class=&quot;token assign-left variable&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; --no-pager branch &lt;span class=&quot;token parameter variable&quot;&gt;-vv&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; fzf&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token assign-left variable&quot;&gt;branch&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$line&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-E&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;s/^[* ]+([^ ]+).*/&#92;1/&#39;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; switch &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$branch&lt;/span&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&#39;s break down what this function does:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;With &lt;code&gt;local&lt;/code&gt;, we create two local variables scoped to the function: &lt;code&gt;branch&lt;/code&gt; and &lt;code&gt;line&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;line&lt;/code&gt; stores the full row selected from the fzf list, which includes extra info like the tracking status.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;branch&lt;/code&gt; stores the branch name extracted from the &lt;code&gt;line&lt;/code&gt; variable.&lt;/li&gt;
&lt;li&gt;We use &lt;code&gt;sed&lt;/code&gt; to extract the branch name. When you run &lt;code&gt;git branch&lt;/code&gt;, you’ll see output like this: an asterisk in front of your current branch and some extra information like tracking details. The &lt;code&gt;sed&lt;/code&gt; command strips away all this extra formatting to get a clean branch name.&lt;/li&gt;
&lt;li&gt;Let&#39;s look at what this &lt;code&gt;sed&lt;/code&gt; command &lt;code&gt;sed -E &#39;s/^[* ]+([^ ]+).*/&#92;1/&#39;&lt;/code&gt; does.
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;sed&lt;/code&gt; is called a stream editor. It is a way to modify a stream of text.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-E&lt;/code&gt; enables us to pass a regular expression to sed to edit a given string.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;^[* ]+&lt;/code&gt;: We start by matching any asterisk or space at the start of the line.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;([^ ]+)&lt;/code&gt;: It is a capture group for the branch name. It takes any subsequent character that is not a space. And it will stop the capture group once it encounters a space.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.*&lt;/code&gt;: We match with &lt;code&gt;.*&lt;/code&gt; any other character that follows the branch name.&lt;/li&gt;
&lt;li&gt;With &lt;code&gt;&#92;1&lt;/code&gt;, we tell &lt;code&gt;sed&lt;/code&gt; to replace the input string with the capture group that contains the branch name.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git switch&lt;/code&gt; is equivalent to &lt;code&gt;git checkout&lt;/code&gt; and will check out the branch we selected.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Next, before testing it, we could add an extra check to make sure the command is run in a Git repository. Let&#39;s use the handy command &lt;code&gt;git rev-parse --is-inside-work-tree&lt;/code&gt;. &lt;a href=&quot;https://git-scm.com/docs/git-rev-parse#Documentation/git-rev-parse.txt---is-inside-git-dir&quot;&gt;This Git command&lt;/a&gt; returns a boolean indicating whether we are in a Git repository or not.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-name function&quot;&gt;sfb&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; rev-parse --is-inside-work-tree &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&gt;&lt;/span&gt;/dev/null&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;then&lt;/span&gt;
		&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Error: Not inside a Git repository&quot;&lt;/span&gt;
		&lt;span class=&quot;token builtin class-name&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;fi&lt;/span&gt;

	&lt;span class=&quot;token builtin class-name&quot;&gt;local&lt;/span&gt; line branch
	&lt;span class=&quot;token assign-left variable&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; --no-pager branch &lt;span class=&quot;token parameter variable&quot;&gt;-vv&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; fzf&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token assign-left variable&quot;&gt;branch&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$line&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-E&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;s/^[* ]+([^ ]+).*/&#92;1/&#39;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; switch &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$branch&lt;/span&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git rev-parse&lt;/code&gt; returns a boolean. If it returns &lt;code&gt;false&lt;/code&gt;, we exit the function.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;amp;&amp;gt;/dev/null&lt;/code&gt;: It is a way to ignore the output of the Git command. &lt;code&gt;&amp;amp;&amp;gt;&lt;/code&gt; redirects both standard output and standard error to &lt;code&gt;/dev/null&lt;/code&gt;, which is what is called a &lt;a href=&quot;https://en.wikipedia.org/wiki/Null_device&quot;&gt;&amp;quot;Null device&amp;quot;&lt;/a&gt;. It is a way to discard the command output completely.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s give it a go. Save your file and go back to your shell. Source your bashrc (&lt;code&gt;source ~/.bashrc&lt;/code&gt;). Go to a local repository that has several branches and type in your command line:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;sfb&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&#39;s an example output of running this command:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://oliviac.dev/blog/img/fzf_git_branches_sfb.png&quot; alt=&quot;Output of running  in the terminal. It shows a fzf prompt where you can type. Above the fzf prompt, there is a list of all the git branches in the current repository that you can interact it.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You should see the fzf picker showing all your Git branches. The &lt;code&gt;*&lt;/code&gt; in front of the branch indicates your current checked-out branch. If you select one, you should now be checked out on that other branch.&lt;/p&gt;
&lt;h3 id=&quot;extracting-the-git-rev-parse-check-in-its-own-function&quot; tabindex=&quot;-1&quot;&gt;Extracting the &lt;code&gt;git rev-parse&lt;/code&gt; check in its own function&lt;/h3&gt;
&lt;p&gt;We will reuse the logic to check whether the directory is a Git repository. Let&#39;s extract the logic with &lt;code&gt;git rev-parse&lt;/code&gt; in a function for easier reuse. In your &lt;code&gt;.bash_helpers&lt;/code&gt;, add:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-name function&quot;&gt;ensure_git_repo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; rev-parse --is-inside-work-tree &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&gt;&lt;/span&gt;/dev/null&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;then&lt;/span&gt;
        &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Error: Not inside a Git repository&quot;&lt;/span&gt;
        &lt;span class=&quot;token builtin class-name&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can then use it in our &lt;code&gt;sfb&lt;/code&gt; helper:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-name function&quot;&gt;sfb&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	ensure_git_repo &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;

	&lt;span class=&quot;token builtin class-name&quot;&gt;local&lt;/span&gt; line branch
	&lt;span class=&quot;token assign-left variable&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; --no-pager branch &lt;span class=&quot;token parameter variable&quot;&gt;-vv&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; fzf&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token assign-left variable&quot;&gt;branch&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$line&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-E&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;s/^[* ]+([^ ]+).*/&#92;1/&#39;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; switch &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$branch&lt;/span&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;ensure_git_repo || return 1&lt;/code&gt; is a shorthand syntax. It is equivalent to doing:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; ensure_git_repo&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;then&lt;/span&gt;
		&lt;span class=&quot;token builtin class-name&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;fi&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With the &lt;code&gt;||&lt;/code&gt; syntax, if the first expression is truthy, the second expression does not get checked. In our case, if &lt;code&gt;ensure_git_repo&lt;/code&gt; is successful (returns 0), the &lt;code&gt;return 1&lt;/code&gt; won&#39;t get evaluated.&lt;/p&gt;
&lt;h3 id=&quot;let&#39;s-create-a-helper-to-delete-a-git-branch-using-fzf&quot; tabindex=&quot;-1&quot;&gt;Let&#39;s create a helper to delete a Git branch using fzf&lt;/h3&gt;
&lt;p&gt;Using a very similar logic, we can create a helper to delete a branch.
Let’s create another function &lt;code&gt;dfb&lt;/code&gt; (that stands for “delete find branch”) and reuse the branch selection through &lt;code&gt;fzf&lt;/code&gt; logic:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-name function&quot;&gt;dfb&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token comment&quot;&gt;# Let&#39;s use our helper to check if it is a Git repository&lt;/span&gt;
	ensure_git_repo &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;

	&lt;span class=&quot;token builtin class-name&quot;&gt;local&lt;/span&gt; line branch
	&lt;span class=&quot;token assign-left variable&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; --no-pager branch &lt;span class=&quot;token parameter variable&quot;&gt;-vv&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; fzf&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token assign-left variable&quot;&gt;branch&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$line&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-E&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;s/^[* ]+([^ ]+).*/&#92;1/&#39;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, because it is a destructive operation, let’s add a confirmation step. With Bash, we can use &lt;code&gt;read -p&lt;/code&gt; to get user input and confirm that the user wants to delete the branch:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-name function&quot;&gt;dfb&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	ensure_git_repo &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;

  &lt;span class=&quot;token builtin class-name&quot;&gt;local&lt;/span&gt; line branch
	&lt;span class=&quot;token assign-left variable&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; --no-pager branch &lt;span class=&quot;token parameter variable&quot;&gt;-vv&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; fzf&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token assign-left variable&quot;&gt;branch&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$line&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-E&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;s/^[* ]+([^ ]+).*/&#92;1/&#39;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

	&lt;span class=&quot;token comment&quot;&gt;# show the user what command it is about to run&lt;/span&gt;
	&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;git branch -D &lt;span class=&quot;token variable&quot;&gt;$branch&lt;/span&gt;&quot;&lt;/span&gt;
	&lt;span class=&quot;token builtin class-name&quot;&gt;read&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Are you sure you want to delete this branch? [y|n]&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-n&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;
	&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token environment constant&quot;&gt;$REPLY&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=~&lt;/span&gt; ^&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Yy&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;then&lt;/span&gt;
		&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; branch &lt;span class=&quot;token parameter variable&quot;&gt;-D&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$branch&lt;/span&gt;&quot;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;
	  &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Branch deletion aborted&quot;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;read -p&lt;/code&gt; will prompt the user. &lt;code&gt;-n 1&lt;/code&gt; means we only take one character from the user input.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$REPLY&lt;/code&gt; is a global shell variable. By default, &lt;code&gt;read&lt;/code&gt; will store the user input in &lt;code&gt;$REPLY&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;In the &lt;code&gt;if&lt;/code&gt; statement, we use &lt;code&gt;=~&lt;/code&gt; to match the user input with a regular expression &lt;code&gt;^[Yy]$&lt;/code&gt;. If the user types &lt;code&gt;Y&lt;/code&gt; or &lt;code&gt;y&lt;/code&gt;, we delete the branch.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s try it out. In your shell, source your bashrc and then type:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;dfb&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It should show you a list of branches. If you select one, you will be prompted to confirm whether you want to delete it.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://oliviac.dev/blog/img/git_branches_delete-confirm.png&quot; alt=&quot;Shows the output of running the function  in the terminal. Once a branch to delete is selected, it shows a confirmation prompt that says, &amp;quot;Are you sure you want to delete this branch? [y|n]&amp;quot;&quot; /&gt;&lt;/p&gt;
&lt;h3 id=&quot;let%E2%80%99s-create-a-helper-to-choose-a-commit-to-rebase-a-branch-onto&quot; tabindex=&quot;-1&quot;&gt;Let’s create a helper to choose a commit to rebase a branch onto&lt;/h3&gt;
&lt;p&gt;One of my favorite Git + fzf utilities is one I call &lt;code&gt;gri&lt;/code&gt;. It enables me to choose the commit I want to rebase my branch on. Let’s build this one together.&lt;/p&gt;
&lt;p&gt;First, let’s create a Bash function called &lt;code&gt;gri&lt;/code&gt; (it stands for “git rebase interactive”).&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-name function&quot;&gt;gri&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	ensure_git_repo &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First, we need to list all the commits and pipe them to fzf.&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; log &lt;span class=&quot;token parameter variable&quot;&gt;--color&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;always &lt;span class=&quot;token parameter variable&quot;&gt;--pretty&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;oneline --abbrev-commit&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--color=always&lt;/code&gt; keeps the colored output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--pretty=oneline&lt;/code&gt; keeps the commit information on a single line.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--abbrev-commit&lt;/code&gt; shortens the commit hash.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you try out this command, it will print out in this format:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://oliviac.dev/blog/img/git_log_abbrev_output.png&quot; alt=&quot;&amp;quot;Output of running the above git log command. 3 lines get printed out, each matching a specific commit. On each line, there is first the commit hash in dark yellow, then the commit message. On the latest commit, between the commit hash and the commit message, there is a (HEAD-&amp;gt; main) that shows the latest commit on the branch.&amp;quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Next, we need to pipe it into fzf to allow the user to select a commit.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-name function&quot;&gt;gri&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	ensure_git_repo &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;

	&lt;span class=&quot;token builtin class-name&quot;&gt;local&lt;/span&gt; line commit
	&lt;span class=&quot;token assign-left variable&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; log &lt;span class=&quot;token parameter variable&quot;&gt;--color&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;always &lt;span class=&quot;token parameter variable&quot;&gt;--pretty&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;oneline --abbrev-commit &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; fzf &lt;span class=&quot;token parameter variable&quot;&gt;--ansi&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To keep the colored output, we pass &lt;code&gt;--ansi&lt;/code&gt; to &lt;code&gt;fzf&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To extract just the commit hash, we can use &lt;code&gt;sed&lt;/code&gt; again. Here’s what the final function looks like:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-name function&quot;&gt;gri&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	ensure_git_repo &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;

	&lt;span class=&quot;token builtin class-name&quot;&gt;local&lt;/span&gt; line commit
	&lt;span class=&quot;token assign-left variable&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; log &lt;span class=&quot;token parameter variable&quot;&gt;--color&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;always &lt;span class=&quot;token parameter variable&quot;&gt;--pretty&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;oneline --abbrev-commit &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; fzf &lt;span class=&quot;token parameter variable&quot;&gt;--ansi&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-z&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$line&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;then&lt;/span&gt;
		&lt;span class=&quot;token builtin class-name&quot;&gt;return&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;fi&lt;/span&gt;

	&lt;span class=&quot;token assign-left variable&quot;&gt;commit&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$line&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-E&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;s/^([^ ]+).*/&lt;span class=&quot;token entity&quot; title=&quot;&#92;1&quot;&gt;&#92;1&lt;/span&gt;/&quot;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; rebase &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$commit&lt;/span&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;We use a capture group in the regular expression in &lt;code&gt;sed&lt;/code&gt; to capture the commit hash only.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-z&lt;/code&gt; is a string test operator in Bash. It checks if the string is empty. This condition handles the case when the user doesn’t select a commit.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now test it in your terminal:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;gri&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should see a menu with your commits. If you select one, you’ll be taken to Git’s interactive rebase menu.&lt;/p&gt;
&lt;h2 id=&quot;other-ideas&quot; tabindex=&quot;-1&quot;&gt;Other ideas&lt;/h2&gt;
&lt;p&gt;In this post, we explored the power of fzf, taking &lt;code&gt;git&lt;/code&gt; as an example. But you can use it with many other programs. One recent use case I had was that I wanted to select a Docker container to execute a command inside of it. At work, I have at times 60 containers running simultaneously, so it can be tricky to find the one I’m looking for.&lt;/p&gt;
&lt;p&gt;I ended up doing a command that looked like that:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;docker exec -it $(docker ps --format &amp;quot;{{.Names}}&amp;quot; | fzf) sh&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker container exec&lt;/code&gt; allows you to execute a command inside a running container.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-it&lt;/code&gt; means that I want to have an interactive mode within the container.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sh&lt;/code&gt; is the program I want to launch within the container.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker ps --format “{{.Names}}”&lt;/code&gt; lists out only the names of the containers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We could put this command in a Bash function, too. There are so many useful use cases of using &lt;code&gt;fzf&lt;/code&gt;. The sky is really the limit!&lt;/p&gt;
&lt;h2 id=&quot;complete-code-from-this-post&quot; tabindex=&quot;-1&quot;&gt;Complete code from this post&lt;/h2&gt;
&lt;p&gt;You can find all the code from this post in the &lt;a href=&quot;https://github.com/liv7c/fzf-git-tutorial&quot;&gt;fzf-git-tutorial repository&lt;/a&gt; on Github.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this blog post, we explored &lt;code&gt;fzf&lt;/code&gt; and built together a couple of Bash utils combining the power of &lt;code&gt;fzf&lt;/code&gt; with &lt;code&gt;Git&lt;/code&gt;. We built one to check out a Git branch, being able to pick from the available local branches. We also looked at how to build a helper to rebase onto a commit by using &lt;code&gt;fzf&lt;/code&gt; to see a list of the different commits. We&#39;ve only really scratched the surface of all the useful things we could do with &lt;code&gt;fzf&lt;/code&gt;. I hope this blog post gives you some ideas! You can find all the code examples from this tutorial in the &lt;a href=&quot;https://github.com/liv7c/fzf-git-tutorial&quot;&gt;fzf-git-tutorial repository&lt;/a&gt;. Like always, if you have any questions or would like to share some of your own utils, don’t hesitate to reach out on &lt;a href=&quot;https://bsky.app/profile/oliviac.dev&quot;&gt;Bluesky&lt;/a&gt;!&lt;/p&gt;
&lt;h2 id=&quot;versions-used-in-this-post&quot; tabindex=&quot;-1&quot;&gt;Versions used in this post&lt;/h2&gt;
&lt;p&gt;Here are the versions of Bash and fzf used in this post:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;bash&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--version&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# GNU bash, version 5.2.37(1)-release (aarch64-apple-darwin23.4.0)&lt;/span&gt;

fzf &lt;span class=&quot;token parameter variable&quot;&gt;--version&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# 0.65.0&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--version&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# git version 2.50.0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You don&#39;t need these exact versions, but if you run into any issues (particularly with Bash), try updating Bash or fzf.&lt;/p&gt;
&lt;h2 id=&quot;further-resources&quot; tabindex=&quot;-1&quot;&gt;Further resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/junegunn/fzf&quot;&gt;fzf Github repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://devhints.io/bash&quot;&gt;Bash scripting cheatsheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/liv7c/fzf-git-tutorial&quot;&gt;fzf-git-tutorial repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/liv7c/dotfiles/blob/main/sources/functions&quot;&gt;My Bash utility functions in my dotfiles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;For a more advanced Git + fzf integration, check out &lt;a href=&quot;https://github.com/junegunn/fzf-git.sh&quot;&gt;fzf-git by the creator of fzf&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content
    >
  </entry> 
  <entry>
    <title>How to test packages locally before publishing using yalc</title>
    <link href="
  https://oliviac.dev/blog/test-packages-locally-before-publishing-yalc/
  " />
    <updated>2025-11-16T00:00:00Z</updated>
    <id>
  https://oliviac.dev/blog/test-packages-locally-before-publishing-yalc/
  </id>
    <content
      type="html"
      >&lt;p&gt;If you maintain an npm package, you might want to test changes locally in an app that depends on it before publishing. This article shows how to do that using &lt;a href=&quot;https://www.npmjs.com/package/yalc&quot;&gt;&lt;code&gt;yalc&lt;/code&gt;&lt;/a&gt;, an alternative to &lt;code&gt;npm link&lt;/code&gt; and &lt;code&gt;yarn link&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In this tutorial, we’ll use a common real-world example: a shared frontend configuration package consumed by an application. We’ll add new configuration settings to the frontend config package and test how those changes affect the app that uses it without publishing or pushing any code on GitHub.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This tutorial uses a React-based example, but the workflow using yalc is the same regardless of whether you use Vue, Svelte, or another framework.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;initial-setup&quot; tabindex=&quot;-1&quot;&gt;Initial setup&lt;/h2&gt;
&lt;p&gt;In this tutorial, we’ll use two repositories:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/liv7c/tutorial-frontend-config&quot;&gt;tutorial-frontend-config&lt;/a&gt;: this is the repository containing the frontend configuration to be shared across projects. It contains ESLint and Prettier configuration files.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/liv7c/react-yalc-tutorial&quot;&gt;react-yalc-tutorial&lt;/a&gt;: it’s a small application built with &lt;a href=&quot;https://vite.dev/&quot;&gt;Vite&lt;/a&gt;. It is a typical React/TypeScript app with a few components. It already uses the &lt;code&gt;tutorial-frontend-config&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Clone the frontend config package and install its dependencies&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; clone git@github.com:liv7c/tutorial-frontend-config.git
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; tutorial-frontend-config
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Go back to your parent folder (if needed)&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Clone the example React app and install its dependencies&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; clone git@github.com:liv7c/react-yalc-tutorial.git
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; react-yalc-tutorial
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Before we continue, let’s install &lt;code&gt;yalc&lt;/code&gt; globally so it’s ready to use:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-g&lt;/span&gt; yalc&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Everything is set up, so let’s get started.&lt;/p&gt;
&lt;h2 id=&quot;let%E2%80%99s-update-the-config-package&quot; tabindex=&quot;-1&quot;&gt;Let’s update the config package&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;tutorial-frontend-config&lt;/code&gt; repository contains all our shared frontend configuration rules for linting and formatting. We have a &lt;a href=&quot;https://www.npmjs.com/package/@oliviacl/tutorial-frontend-config&quot;&gt;published version on &lt;code&gt;npm&lt;/code&gt;&lt;/a&gt;, and several projects already depend on it.
Let’s say we want to try out a new ESLint plugin: &lt;a href=&quot;https://github.com/azat-io/eslint-plugin-perfectionist&quot;&gt;eslint-plugin-perfectionist&lt;/a&gt;. It not only handles import ordering but also includes sorting rules for TypeScript types and component props.
Let’s go to our frontend config repo and create a new Git branch:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; PATH_TO_REPO/tutorial-frontend-config
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; switch &lt;span class=&quot;token parameter variable&quot;&gt;-C&lt;/span&gt; feature/use-perfectionist-eslint-plugin&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;a-quick-tour-of-the-tutorial-frontend-config-repository&quot; tabindex=&quot;-1&quot;&gt;A quick tour of the tutorial-frontend-config repository&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;tutorial-frontend-config&lt;/code&gt; repository is an npm workspace. A workspace is a way to have multiple packages within the same repo. In this case, there are two packages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;configs&lt;/code&gt; that contains the package published on npm.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;example-app&lt;/code&gt;: a demo app that consumes the configs package.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here are a few useful details about npm workspaces:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When you run &lt;code&gt;npm install&lt;/code&gt; at the root of the workspace, it will install the dependencies of all workspace packages. This works thanks to the &lt;a href=&quot;https://github.com/liv7c/tutorial-frontend-config/blob/main/package.json#L6-L9&quot;&gt;&lt;code&gt;workspace&lt;/code&gt; property in the root package.json&lt;/a&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// in package.json&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;workspaces&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;packages/*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;example-app&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Packages can reference each other. I have an example app in the repo that &lt;a href=&quot;https://github.com/liv7c/tutorial-frontend-config/blob/main/example-app/package.json#L19C1-L19C47&quot;&gt;references the other workspace package in its dependencies&lt;/a&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// in example-app/package.json&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;@oliviacl/tutorial-frontend-config&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you want to work on a specific package inside a monorepo, navigate into that package’s folder. Each package has its own package.json file, which contains specific dependencies. In our case, we’ll be working in the &lt;code&gt;configs&lt;/code&gt; package.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; tutorial-frontend-config/packages/configs&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;let%E2%80%99s-add-the-perfectionist-plugin-to-our-eslint-config&quot; tabindex=&quot;-1&quot;&gt;Let’s add the Perfectionist plugin to our ESLint config&lt;/h3&gt;
&lt;p&gt;The goal is to modify the ESLint config to use a new plugin: &lt;a href=&quot;https://github.com/azat-io/eslint-plugin-perfectionist&quot;&gt;eslint-plugin-perfectionist&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Make sure you are in the correct directory (&lt;code&gt;tutorial-frontend-config/packages/configs&lt;/code&gt;).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If we examine the &lt;code&gt;eslint.js&lt;/code&gt; file, we currently use &lt;code&gt;eslint-plugin-import&lt;/code&gt; with a few rules. With eslint-plugin-perfectionist, we can remove &lt;code&gt;eslint-plugin-import&lt;/code&gt; and the rules we had for this plugin, as the perfectionist plugin will handle those functionalities. In the &lt;code&gt;packages/configs&lt;/code&gt; directory, run:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; uninstall eslint-plugin-import&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then remove all references to &lt;code&gt;eslint-plugin-import&lt;/code&gt; from &lt;code&gt;eslint.js&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// remove import&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; importPlugin &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;eslint-plugin-import&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// eslint.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
	&lt;span class=&quot;token comment&quot;&gt;// delete the plugin from the plugins section&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	  &lt;span class=&quot;token comment&quot;&gt;// Delete the following line&lt;/span&gt;
	  &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; importPlugin&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;rules&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	  &lt;span class=&quot;token comment&quot;&gt;// Delete this block in the rules&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;&#39;import/order&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&#39;warn&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;groups&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;builtin&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;external&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;internal&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;parent&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;sibling&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;index&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token string-property property&quot;&gt;&#39;newlines-between&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;always&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;alphabetize&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;order&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;asc&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;caseInsensitive&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s commit those changes:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; commit &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;chore(eslint): remove eslint-plugin-import with rules&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, let’s install the new ESLint plugin (make sure you are still in the &lt;code&gt;packages/configs&lt;/code&gt; directory):&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; eslint-plugin-perfectionist&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We add it as a dependency so projects using our config don’t need to install it themselves.&lt;/p&gt;
&lt;p&gt;Let’s update our ESLint config to use the plugin. We can use a ready-made config as mentioned in the &lt;a href=&quot;https://github.com/azat-io/eslint-plugin-perfectionist?tab=readme-ov-file#configs&quot;&gt;plugin documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;First, import the plugin:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// in eslint.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; perfectionist &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;eslint-plugin-perfectionist&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, add the perfectionist plugin:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// in eslint.js&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
  js&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;configs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;recommended&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;tseslint&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;configs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;recommended&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  perfectionist&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;configs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;recommended-natural&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s commit this:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; commit &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;feat(eslint): add perfectionist plugin&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;testing-our-changes-with-yalc&quot; tabindex=&quot;-1&quot;&gt;Testing our changes with yalc&lt;/h2&gt;
&lt;p&gt;This is where &lt;code&gt;yalc&lt;/code&gt; comes in. We want to test the changes we made to our ESLint config before pushing or publishing the changes.&lt;/p&gt;
&lt;h3 id=&quot;publishing-our-package-locally-via-yalc-publish&quot; tabindex=&quot;-1&quot;&gt;Publishing our package locally via yalc publish&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;yalc&lt;/code&gt; creates a local store on your computer inside a &lt;code&gt;~/.yalc&lt;/code&gt; directory. We can publish packages to this directory. &lt;code&gt;yalc&lt;/code&gt; then makes it easy to use the packages published to that local store in applications that depend on them.&lt;/p&gt;
&lt;p&gt;In the &lt;code&gt;packages/configs&lt;/code&gt; directory, run:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;yalc publish&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After running the command, you should see the following message in your terminal:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;@oliviacl/tutorial-frontend-config@1.0.4 published &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; store.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you inspect the &lt;code&gt;.yalc&lt;/code&gt; directory in your home folder, you should see the following structure:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;❯ tree ~/.yalc
.yalc
├── installations.json
└── packages
    └── @oliviacl
        └── tutorial-frontend-config
               └── &lt;span class=&quot;token number&quot;&gt;1.0&lt;/span&gt;.4
                ├── CHANGELOG.md
                ├── eslint.d.ts
                ├── eslint.js
                ├── index.d.ts
                ├── index.js
                ├── package.json
                ├── prettier.d.ts
                ├── prettier.js
                ├── README.md
                └── yalc.sig

&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; directories, &lt;span class=&quot;token number&quot;&gt;11&lt;/span&gt; files&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;adding-the-package-via-yalc-add&quot; tabindex=&quot;-1&quot;&gt;Adding the package via yalc add&lt;/h3&gt;
&lt;p&gt;Now, let’s change directory and move to the tutorial application we cloned in the previous section:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; PATH_TO_REPO/react-yalc-tutorial&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Make sure you’ve run &lt;code&gt;npm install&lt;/code&gt; first. Now, to use our package published in the yalc local store, we only need to run:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;yalc &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; @oliviacl/tutorial-frontend-config&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you open your package.json, you’ll see that the dependency was replaced with a reference to the &lt;code&gt;.yalc&lt;/code&gt; directory:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;	&lt;span class=&quot;token comment&quot;&gt;// in your package.json&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;devDependencies&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;@oliviacl/tutorial-frontend-config&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;file:.yalc/@oliviacl/tutorial-frontend-config&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Inside the repo, you should also see a &lt;code&gt;.yalc&lt;/code&gt; folder containing the latest version of your package. When you run &lt;code&gt;yalc add&lt;/code&gt;, &lt;code&gt;yalc&lt;/code&gt; copies the package from the &lt;code&gt;~/.yalc&lt;/code&gt; store into your repo.&lt;/p&gt;
&lt;p&gt;Run &lt;code&gt;npm install&lt;/code&gt;. This will install any new dependencies required by the updated ESLint config.&lt;/p&gt;
&lt;p&gt;If you run &lt;code&gt;npm run lint&lt;/code&gt;, you should see new warnings coming from this new plugin:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://oliviac.dev/blog/img/warning_eslint_perfectionist.png&quot; alt=&quot;&amp;quot;ESLint errors from perfectionist plugin showing sorting violations in JSX props and TypeScript object types&amp;quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;It works!&lt;/p&gt;
&lt;h3 id=&quot;making-multiple-changes-and-propagating-them-with-yalc-push&quot; tabindex=&quot;-1&quot;&gt;Making multiple changes and propagating them with &lt;code&gt;yalc push&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Now, let’s say we want to make more changes to &lt;code&gt;tutorial-frontend-config&lt;/code&gt;. In &lt;code&gt;tutorial-frontend-config&lt;/code&gt;, we could modify the prettier config and update it to use double quotes, for instance:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// in packages/configs/prettier.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;semi&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;trailingComma&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;es5&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// we switch singleQuote from true to false&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;singleQuote&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;printWidth&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;tabWidth&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;useTabs&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;arrowParens&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;always&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;endOfLine&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;lf&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To propagate the changes, no need to run &lt;code&gt;yalc publish&lt;/code&gt;. You can run:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# run this command from packages/configs&lt;/span&gt;
yalc push&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;yalc push&lt;/code&gt; pushes the changes to the Yalc store and automatically updates all projects using the published version in yalc.&lt;/p&gt;
&lt;p&gt;You should see a command output that looks like this:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;@oliviacl/tutorial-frontend-config@1.0.4 published &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; store.
Pushing @oliviacl/tutorial-frontend-config@1.0.4 &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; /Users/YOUR_USERNAME/projects/react-yalc-tutorial
Package @oliviacl/tutorial-frontend-config@1.0.4 added &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; /Users/YOUR_USERNAME/projects/react-yalc-tutorial/node_modules/@oliviacl/tutorial-frontend-config&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you go back to the &lt;code&gt;react-yalc-tutorial&lt;/code&gt; project and open the &lt;code&gt;.yalc&lt;/code&gt; folder, you should see that the Prettier file has been updated. And if you run &lt;code&gt;npx prettier --check src&lt;/code&gt; or enable format-on-save, you should see the new Prettier rules being applied.&lt;/p&gt;
&lt;h3 id=&quot;cleaning-things-up-when-done-testing-with-yalc-remove&quot; tabindex=&quot;-1&quot;&gt;Cleaning things up when done testing with &lt;code&gt;yalc remove&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Once we’re done testing, we can run the following command inside &lt;code&gt;react-yalc-tutorial&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;yalc remove @oliviacl/tutorial-frontend-config&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command removes the yalc entry from &lt;code&gt;package.json&lt;/code&gt; and cleans up the &lt;code&gt;yalc.lock&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;If you’re testing multiple packages with yalc and want to remove all of them at once, run:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;yalc remove &lt;span class=&quot;token parameter variable&quot;&gt;--all&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;working-with-component-libraries&quot; tabindex=&quot;-1&quot;&gt;Working with component libraries&lt;/h2&gt;
&lt;p&gt;In this tutorial, we worked with a configuration package that doesn’t require a build step. However, the workflow with &lt;code&gt;yalc&lt;/code&gt; is almost the same when working with a component library that has a build step.
The only difference is that you will want to run &lt;code&gt;npm run build&lt;/code&gt; to build your library before running &lt;code&gt;yalc publish&lt;/code&gt; or &lt;code&gt;yalc push&lt;/code&gt;. &lt;code&gt;yalc&lt;/code&gt; will copy all the files that should be published, using your package.json as a source of truth.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; run build &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; yalc publish&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this post, we looked at how to use &lt;code&gt;yalc&lt;/code&gt; to test a package locally without publishing it or pushing any changes. It’s a very useful tool for trying out changes locally.
&lt;code&gt;yalc&lt;/code&gt; is a great alternative to &lt;code&gt;npm link&lt;/code&gt; or &lt;code&gt;yarn link&lt;/code&gt; and, as you saw in the example, is pretty straightforward to use.&lt;/p&gt;
&lt;p&gt;I hope this tutorial was helpful! As always, if you have any questions or would like to chat, don’t hesitate to reach out on &lt;a href=&quot;https://bsky.app/profile/oliviac.dev&quot;&gt;Bluesky&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;extra-resources&quot; tabindex=&quot;-1&quot;&gt;Extra resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/wclr/yalc&quot;&gt;yalc repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.npmjs.com/cli/v7/using-npm/workspaces?v=true&quot;&gt;Documentation on npm workspaces if you are curious&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content
    >
  </entry> 
  <entry>
    <title>Improve your Git CLI experience with Git aliases, delta, and custom functions</title>
    <link href="
  https://oliviac.dev/blog/customize-git-cli-aliases-delta/
  " />
    <updated>2026-02-27T00:00:00Z</updated>
    <id>
  https://oliviac.dev/blog/customize-git-cli-aliases-delta/
  </id>
    <content
      type="html"
      >&lt;p&gt;In this article, we’ll explore various settings we can add to our Git config to make it nicer to work with when using the Git command-line interface. We’ll look at Git aliases, customizing the Git pager, and custom functions you could build on top of Git.
One of the best aspects of using the Git CLI is the number of customizations you can add to match your workflow. The beauty of it is that all those customizations are portable. You can switch editor and your Git workflow stays the same.&lt;/p&gt;
&lt;h2 id=&quot;a-quick-tour-of-the-gitconfig&quot; tabindex=&quot;-1&quot;&gt;A quick tour of the gitconfig&lt;/h2&gt;
&lt;p&gt;There are many ways to configure Git. You can configure it at the repository level in the &lt;code&gt;.git/config&lt;/code&gt; inside of your &lt;a href=&quot;https://git-scm.com/docs/git-config#Documentation/git-config.txt---local&quot;&gt;local repository&lt;/a&gt;. You can also configure Git globally or at the &lt;a href=&quot;https://git-scm.com/docs/git-config#Documentation/git-config.txt---system&quot;&gt;system level&lt;/a&gt;. In this article, we will focus on the global settings. It’s a file located &lt;strong&gt;at the root of your user directory&lt;/strong&gt; named &lt;code&gt;.gitconfig&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; ~/.gitconfig&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You might remember typing &lt;code&gt;git config --global user.name &amp;quot;John Doe&amp;quot;&lt;/code&gt; when you first installed Git on your computer. This command creates and writes to your global git config. This file contains several sections with settings you want to set globally and apply to any Git project on your machine. Here’s an example of a &lt;code&gt;gitconfig&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  name = John Doe
  email = johndoe@email.com

&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;core&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  editor = nvim
  excludesfile = ~/.gitignore_global

&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;init&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  defaultBranch = main

&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;commit&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  gpgsign = true

&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;push&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  default = simple
  autoSetupRemote = true&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All settings inside the &lt;code&gt;gitconfig&lt;/code&gt; are grouped within sections. Here’s an overview of the sections:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;user&lt;/code&gt; section contains your name and email that will be used as committer fields in your commits.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;core&lt;/code&gt; section contains configurations such as the editor you wish to use when you amend a commit. You also add a global gitignore file in &lt;code&gt;excludesfile&lt;/code&gt;. Git will then automatically ignore the files mentioned in this global gitignore for any local repository on your computer.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;init&lt;/code&gt; section contains settings that get applied when you run &lt;code&gt;git init&lt;/code&gt;. With &lt;code&gt;defaultBranch&lt;/code&gt; set to &lt;code&gt;main&lt;/code&gt;, the default branch created will be named &lt;code&gt;main&lt;/code&gt; instead of &lt;code&gt;master&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;commit&lt;/code&gt; and &lt;code&gt;push&lt;/code&gt; sections are to configure how Git behaves when pushing or committing. In the example, &lt;code&gt;autoSetupRemote&lt;/code&gt; creates the remote branch automatically if it isn’t yet created in your remote repository, on Github for instance.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first step to further customizing Git on the command line is to use another feature we haven’t looked at yet: &lt;strong&gt;Git aliases&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;create-your-own-shortcuts-with-git-aliases&quot; tabindex=&quot;-1&quot;&gt;Create your own shortcuts with Git aliases&lt;/h2&gt;
&lt;p&gt;In your gitconfig, you can add a section called &lt;code&gt;[alias]&lt;/code&gt;. An alias looks like:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;alias&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
	st = status&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On the left side, you add your alias name. The alias name is the shortcut you want to use. On the right is the value the alias expands to. You can use any Git command with its various flags as an alias value.
In this first example, we have an alias &lt;code&gt;st&lt;/code&gt; that expands to &lt;code&gt;status&lt;/code&gt;. In your terminal, you can now type:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;$ &lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; st&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command will give the same output as typing &lt;code&gt;git status&lt;/code&gt; as &lt;code&gt;st&lt;/code&gt; expands to &lt;code&gt;status&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We all have commands we end up using all the time, or useful commands we’d use more often if we could remember which flags to pass.
Let’s imagine you use &lt;code&gt;git log --oneline&lt;/code&gt; all the time.&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; log &lt;span class=&quot;token parameter variable&quot;&gt;--oneline&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command provides a more compact overview of the last commits on a branch. Here’s an example of a typical output:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;69ca546 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HEAD -&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; main, origin/main&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; chore&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bash&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;: remove bash_completion from bash_profile
775be90 feat&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bash&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;: &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; wasm build to path
4f545cc feat&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bash&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;: disable go pls telemetry&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With Git aliases, you can add a shortcut that will expand to that exact command:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# In your ~/.gitconfig&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;alias&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  lo = &quot;log &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;oneline&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, you can type:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; lo&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And it will expand to &lt;code&gt;git log --oneline&lt;/code&gt;, giving you the same output.&lt;/p&gt;
&lt;p&gt;In my gitconfig, I have a series of aliases I use to add files, push, unstage commits, and many others:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;alias&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  aa = add &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;all
  s = status &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;s
  st = status
  br = branch
  c = commit &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;verbose
  cm = commit &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;m
  cp = cherry&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;pick
  co = checkout
  ll = log &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;oneline &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;graph
  p = push
  pf = push &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;force&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;with&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;lease
  unstage = restore &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;staged .&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One of my favorites from this example is &lt;code&gt;unstage&lt;/code&gt;. With &lt;code&gt;git unstage&lt;/code&gt;, I unstage any file I might have added to the Git staging area.
To commit with a message, I do a &lt;code&gt;git cm “my commit message”&lt;/code&gt; and it does the same thing as typing &lt;code&gt;git commit -m “my commit message”&lt;/code&gt;. Git aliases are quick to add and can make a difference in your everyday Git CLI experience.&lt;/p&gt;
&lt;h2 id=&quot;add-a-syntax-highlighter-for-the-git-pager&quot; tabindex=&quot;-1&quot;&gt;Add a syntax highlighter for the Git pager&lt;/h2&gt;
&lt;p&gt;When you use commands like &lt;code&gt;git diff&lt;/code&gt; and &lt;code&gt;git show&lt;/code&gt;, Git uses a &lt;em&gt;pager&lt;/em&gt; to show their respective output. By default, Git uses &lt;code&gt;less&lt;/code&gt;. As mentioned in the &lt;a href=&quot;https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration&quot;&gt;documentation&lt;/a&gt;, you can choose your own pager. &lt;a href=&quot;https://github.com/dandavison/delta&quot;&gt;&lt;strong&gt;delta&lt;/strong&gt;&lt;/a&gt; is a great alternative to the default pager. It provides language syntax highlighting and configurable options. You can customize delta to show the Git diff in a split view. You can also make it show line numbers. There are many &lt;a href=&quot;https://dandavison.github.io/delta/&quot;&gt;features worth exploring&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To use delta, first install it following &lt;a href=&quot;https://dandavison.github.io/delta/installation.html&quot;&gt;their installation guide&lt;/a&gt;. If you’re on MacOS, you can use Homebrew (&lt;code&gt;brew install git-delta&lt;/code&gt;).
Then, in your &lt;code&gt;~/.gitconfig&lt;/code&gt;, add the following rule to the &lt;code&gt;core&lt;/code&gt; settings section:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;core&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    pager = delta&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To customize delta further, you can also add to your &lt;code&gt;gitconfig&lt;/code&gt; a &lt;code&gt;[delta]&lt;/code&gt; section:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;delta&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
	navigate = true
	side&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;by&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;side = true
	line&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;numbers = true&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;navigate&lt;/code&gt; activates navigation keybindings. You can now use &lt;code&gt;n&lt;/code&gt; to jump to the next Git diff or &lt;code&gt;N&lt;/code&gt; to jump backwards.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;side-by-side&lt;/code&gt; changes the output to show on the left the previous committed version of the committed file and on the right the current modifications.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;line-numbers&lt;/code&gt; is to display the line numbers. You can turn it off by passing &lt;code&gt;false&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you run &lt;code&gt;git diff&lt;/code&gt; now, you should see a much clearer Git diff. For instance, here’s the before/after of running &lt;code&gt;git show&lt;/code&gt; in one of my repos.&lt;/p&gt;
&lt;p&gt;Before adding delta:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://oliviac.dev/blog/img/git_diff_svelte_before_delta.png&quot; alt=&quot;Terminal output of git show using the default Git pager. It shows a diff of a Svelte component called LiveSVGEditor, where the worker initialization code was refactored. Five lines were removed (colored in red). They are replaced by a single added line (in green) that imports an editorWorker directly. The diff is displayed in a single column with no line numbers and no syntax highlighting.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;After adding delta:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://oliviac.dev/blog/img/git_diff_svelte_after_delta.png&quot; alt=&quot;Terminal output of the same git show command after adding delta as the Git pager. The diff is now displayed in a side-by-side view with line numbers. The left column shows the previous version of LiveSVGEditor.svelte with the removed worker initialization code highlighted in red across lines 11–14. The right column shows the updated version with the single replacement line highlighted in green at line 12. The code has full syntax highlighting with keywords and strings in different colors.&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;build-custom-functions-for-more-complex-tasks-with-git&quot; tabindex=&quot;-1&quot;&gt;Build custom functions for more complex tasks with Git&lt;/h2&gt;
&lt;p&gt;You can think of Git as a powerful utility that you can combine with other utilities to make certain tasks easier. The power of Git lies in its composability.&lt;/p&gt;
&lt;p&gt;In a former blog post &lt;a href=&quot;https://oliviac.dev/blog/build-git-helpers-bash-fzf/&quot;&gt;“Build Git helpers from scratch with Bash and fzf”&lt;/a&gt;, I wrote about how to create Git helpers with &lt;code&gt;fzf&lt;/code&gt;. &lt;code&gt;fzf&lt;/code&gt; is a &lt;a href=&quot;https://github.com/junegunn/fzf&quot;&gt;command-line fuzzy finder&lt;/a&gt;. In that article, we build several utilities with Git and &lt;code&gt;fzf&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://oliviac.dev/blog/build-git-helpers-bash-fzf/#let&#39;s-create-a-helper-to-delete-a-git-branch-using-fzf&quot;&gt;&lt;code&gt;dfb&lt;/code&gt;&lt;/a&gt;: a helper function to delete a Git branch more easily&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://oliviac.dev/blog/build-git-helpers-bash-fzf/#let%E2%80%99s-create-a-helper-to-choose-a-commit-to-rebase-a-branch-onto&quot;&gt;&lt;code&gt;gri&lt;/code&gt;&lt;/a&gt;: With this function, you can choose via &lt;code&gt;fzf&lt;/code&gt; which commit you want to rebase your branch onto. Then you get the classic Git rebase-interactive menu.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;You can add shell functions directly in your &lt;code&gt;~/.bashrc&lt;/code&gt;, &lt;code&gt;~/.zshrc&lt;/code&gt;, or any file loaded by your shell config file. To test the following function, you can add it directly for now in your bashrc or zshrc, reload your config file via a &lt;code&gt;source ~/.bashrc&lt;/code&gt; or &lt;code&gt;source ~/.zshrc&lt;/code&gt;, and then you should be able to use it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Another common Git task is staging a file or specific changes in a modified file. Let’s create a small helper that follows the same technique as the ones mentioned before.&lt;/p&gt;
&lt;p&gt;In my bash config, I have a &lt;code&gt;bash&lt;/code&gt; function called &lt;code&gt;gaf&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-name function&quot;&gt;ensure_git_repo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; rev-parse --is-inside-work-tree &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&gt;&lt;/span&gt; /dev/null&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;then&lt;/span&gt;
        &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Error: Not inside a Git repository&quot;&lt;/span&gt;
        &lt;span class=&quot;token builtin class-name&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# use fzf to stage modified or untracked files.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-name function&quot;&gt;gaf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    ensure_git_repo &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; ls-files &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; --exclude-standard &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; fzf &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--print0&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;xargs&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-0&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we dissect this function:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ensure_git_repo&lt;/code&gt; is a small check to make sure you use this function inside a Git repository.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git ls-files&lt;/code&gt; is a way to list files in your repository. The flag &lt;code&gt;-m&lt;/code&gt; means we include in the list only modified files. &lt;code&gt;-o&lt;/code&gt; is a way to include untracked files in the output. If you create a file that you have not committed yet, this file will be included in the list. &lt;code&gt;--exclude-standard&lt;/code&gt; means the list won’t include excluded files. This command will take your &lt;code&gt;.gitignore&lt;/code&gt; into account.&lt;/li&gt;
&lt;li&gt;This command pipes the result of &lt;code&gt;git ls-files&lt;/code&gt; to &lt;code&gt;fzf&lt;/code&gt;. Then, &lt;code&gt;fzf&lt;/code&gt; will show to standard output a list of the modified files you can then add. &lt;code&gt;fzf -m&lt;/code&gt; enables multi-selection. You can then select several files at once using the &lt;code&gt;Tab&lt;/code&gt; key.&lt;/li&gt;
&lt;li&gt;The final part uses &lt;code&gt;xargs&lt;/code&gt; to flatten the list of selected files and pass them to &lt;code&gt;git add&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After adding the function, navigate to a local directory with some uncommitted changes, and then type:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;$ gaf&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should see a list of modified files, similar to the following screenshot:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://oliviac.dev/blog/img/gaf_fzf_picker.png&quot; alt=&quot;Output of running the  command. The screen shows an interactive list of two files: README.md and an index Astro file. It also shows an interactive prompt that enables filtering&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You can then select a single file in the list with the &lt;code&gt;Enter&lt;/code&gt; key. It will select the current file highlighted. If you want to select multiple files at once, you can use the &lt;code&gt;Tab&lt;/code&gt; key and &lt;code&gt;Shift Tab&lt;/code&gt; to unselect a file. If you then run &lt;code&gt;git status&lt;/code&gt;, you should see that your selected files are now in the Git staging area. In the example, I selected the README in the fzf menu:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://oliviac.dev/blog/img/gaf_git_status_after_menu.png&quot; alt=&quot;Output of the  command. It shows the README in the staging area. The Astro file is still unstaged&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You can use &lt;code&gt;gaf -p&lt;/code&gt; to stage specific modifications from a file. When you select a file, you then get the Git interactive menu, where you can stage portions of that file:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;$ gaf &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In my repo, I then select my README and get the interactive menu where I can choose to stage or not a specific portion of the README:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://oliviac.dev/blog/img/gafp_stage_changes.png&quot; alt=&quot;Terminal output of git add -p showing a diff of README.md in single-column view with line numbers. Two added lines are highlighted in green at lines 3 and 4: &#39;Repository to showcase a SVG interactive editor.&#39; and a blank line. At the bottom, the interactive prompt reads &#39;(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]?’&quot; /&gt;&lt;/p&gt;
&lt;p&gt;There are many utilities you can come up with that match those micro tasks you do with Git and enable you to stay in your shell and not depend on a specific graphical interface. If you are curious, here’s a link to my dotfiles that contain &lt;a href=&quot;https://github.com/liv7c/dotfiles/blob/main/sources/functions#L22&quot;&gt;Git helpers I use every day&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this article, we looked at a few ways to make the Git command-line interface more user-friendly. Git aliases are a great first step toward creating your own shortcuts for Git commands, with or without flags. &lt;a href=&quot;https://github.com/dandavison/delta&quot;&gt;Delta&lt;/a&gt; is a small utility that improves the readability of Git diffs and works with little configuration.
Finally, we explored an example of creating functions on top of Git to make common tasks easier. The possibilities are endless. I hope this article gives you a few ideas. If you have any questions or would like to chat, as always, don’t hesitate to reach out on &lt;a href=&quot;https://bsky.app/profile/oliviac.dev&quot;&gt;Bluesky&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;resources&quot; tabindex=&quot;-1&quot;&gt;Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The article gave a quick overview of the &lt;code&gt;gitconfig&lt;/code&gt;. For a more complete overview of all available settings, check out the &lt;a href=&quot;https://git-scm.com/docs/git-config&quot;&gt;Git documentation&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;For a more comprehensive overview of delta, check out &lt;a href=&quot;https://dandavison.github.io/delta/introduction.html&quot;&gt;the delta documentation&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If you want a step-by-step guide on how to build Git and fzf helpers, check out my former blog post &lt;a href=&quot;https://oliviac.dev/blog/build-git-helpers-bash-fzf/&quot;&gt;&amp;quot;Build Git helpers from scratch with Bash and fzf&amp;quot;&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
</content
    >
  </entry>
</feed>
