<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tanishq Singla</title>
    <description>The latest articles on DEV Community by Tanishq Singla (@tanishqsingla).</description>
    <link>https://dev.to/tanishqsingla</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F468550%2Fa600f95a-bbd3-4de0-a195-3254f6097b29.jpeg</url>
      <title>DEV Community: Tanishq Singla</title>
      <link>https://dev.to/tanishqsingla</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tanishqsingla"/>
    <language>en</language>
    <item>
      <title>Eating the toast</title>
      <dc:creator>Tanishq Singla</dc:creator>
      <pubDate>Wed, 19 Mar 2025 10:43:46 +0000</pubDate>
      <link>https://dev.to/tanishqsingla/eating-the-toast-42a9</link>
      <guid>https://dev.to/tanishqsingla/eating-the-toast-42a9</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I have a bad habit of stopping in middle of a task and step out in thinking mode. It has both worked as a power-up and a kryptonite. &lt;/p&gt;

&lt;p&gt;One such task was this simple page with a forgot password that I was developing for &lt;a href="https://monkeys.com.co" rel="noopener noreferrer"&gt;Monkeys&lt;/a&gt;. A fairly simple task a form with one field nothing odd about it. &lt;/p&gt;

&lt;p&gt;Here's a small preview of the page.&lt;/p&gt;

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

&lt;p&gt;I regret not writing this blog earlier, if I did I would have known what led me to this adventure, the adventure I am writing in this blog.&lt;/p&gt;

&lt;p&gt;The gif is of a user with email &lt;a href="mailto:gopal@echitti.com"&gt;gopal@echitti.com&lt;/a&gt; using the forgot password page, to send the link for resetting the password.&lt;br&gt;
There's nothing wrong in the gif, the user types their email, clicks on send and a toast pops up alerting the user that the link has been sent successfully.&lt;/p&gt;
&lt;h2&gt;
  
  
  The toast
&lt;/h2&gt;

&lt;p&gt;Suddenly something popped in my head and I starting reflecting back on the whole transaction the user had.&lt;/p&gt;

&lt;p&gt;It was the toast, as the title makes it obvious. &lt;/p&gt;

&lt;p&gt;Toast is a fairly common component which is often used to display a message or sometimes feedback of an action on the screen. &lt;br&gt;
A more formal definition by &lt;a href="https://web.dev" rel="noopener noreferrer"&gt;https://web.dev&lt;/a&gt; state is this way:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Toasts are non-interactive, passive, and asynchronous short messages for users. Generally they are used as an interface feedback pattern for informing the user about the results of an action.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://web.dev/articles/building/a-toast-component" rel="noopener noreferrer"&gt;https://web.dev/articles/building/a-toast-component&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;output&lt;/code&gt; tag is not necessarily used, but if you care about HTML semantics and A11Y (specifically the WCAG).&lt;/p&gt;

&lt;p&gt;When I tested our toast using &lt;a href="https://chromewebstore.google.com/detail/screen-reader/kgejglhpjiefppelpmljglcjbhoiplfn" rel="noopener noreferrer"&gt;Chrome Vox extension&lt;/a&gt; to test our application for screen readers, it worked well. The toast message would announce itself promptly as it would show up.&lt;/p&gt;

&lt;p&gt;Something still looked out of place a bit and the page felt incomplete. As I pondered more about it, I started reading and found some good articles that clarified a lot for me.&lt;/p&gt;
&lt;h2&gt;
  
  
  Toasts can be missed
&lt;/h2&gt;

&lt;p&gt;Speaking metaphorically and literally, toasts are meant to be consumed, missing one might lead you to stay hungry for your breakfast or in our context hungry for feedback or the message that was contained in the toast.&lt;/p&gt;

&lt;p&gt;Let's say our user, after submitting the form got interrupted by something which took their attention away from the screen, and in that meanwhile the toast appeared and then disappeared.&lt;br&gt;
When the user gets their attention back they won't have any conclusion of their action. The Doorway Effect is an even worse enemy here, the user may completely forget if they clicked the button at all.&lt;/p&gt;

&lt;p&gt;I call things like these smell, and when a lot of smell accumulates the application becomes smelly. This makes your app uninviting and less of an incentive, this makes you rely more on business and marketing.&lt;/p&gt;
&lt;h2&gt;
  
  
  Smells of toast
&lt;/h2&gt;

&lt;p&gt;In the blog &lt;a href="https://adrianroselli.com/2020/01/defining-toast-messages.html" rel="noopener noreferrer"&gt;Defining 'Toasts' Message&lt;/a&gt;, &lt;a href="https://adrianroselli.com/" rel="noopener noreferrer"&gt;Adrian&lt;/a&gt; gives a more in-depth rundown of smells in the context of accessibility.&lt;/p&gt;

&lt;p&gt;A quote from the blog.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"By their very nature, toasts are likely to fail a WCAG audit right out of the gate if some effort is not made from the start. Following are WCAG 2.1 Success Criteria you should keep in mind when building your own or testing one of the existing options."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here's a list of rules that our page probably violates.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.w3.org/WAI/WCAG21/Understanding/timing-adjustable.html" rel="noopener noreferrer"&gt;Timing adjustable (2.2.1)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.w3.org/WAI/WCAG21/Understanding/content-on-hover-or-focus.html" rel="noopener noreferrer"&gt;Content Hover on focus (1.4.13)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.w3.org/WAI/WCAG21/Understanding/target-size.html" rel="noopener noreferrer"&gt;Target size (2.5.5)&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When developing components we often forget about how different users access different parts of the web. While WCAG is treated as a dense manual it can bring interesting insights on how components are used or at least how they are naturally perceived to be used.&lt;/p&gt;

&lt;p&gt;Speaking in another way WCAG is more of an engineering manual. While software development especially frontend development is treated as a creative endeavor, WCAG is an engineering guide to that creative endavour.&lt;/p&gt;

&lt;p&gt;Think of it like making a car, while you can make a car look cool and futuristic, if raising the blinker lever and actual direction the blinkers blink is inverted then it's a bad design overall.&lt;/p&gt;

&lt;p&gt;Similarly the &lt;a href="https://www.w3.org/WAI/WCAG21/Understanding/content-on-hover-or-focus.html" rel="noopener noreferrer"&gt;Content Hover on focus (1.4.13)&lt;/a&gt; is a real bummer, no amount of observability, user events tracking can save you from this. Users would press &lt;code&gt;Esc&lt;/code&gt; and instead of toast closing an another element like a tooltip may close and this will leave them a lot frustrated.&lt;/p&gt;
&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;Let's solve the problem in our page and start by breaking down our problem &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Success

&lt;ul&gt;
&lt;li&gt;It is redundant for user to submit the form again on success. So our message can't be short-lived, as toasts are easy to miss.&lt;/li&gt;
&lt;li&gt;We also cannot permanently disable the 'submit' button, cause the user can change the input and would like to submit again.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Error - Validation errors

&lt;ul&gt;
&lt;li&gt;Validation errors are straightforward and we don't need to change anything for them, the existing one works great.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Error - Submit

&lt;ul&gt;
&lt;li&gt;Submission errors are rare and can only occur from server's end, so they are a special scenario.&lt;/li&gt;
&lt;li&gt;So we want to prompt our user to contact support if they face such an anomaly, or provide an option to retry submitting.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Utilizing our button
&lt;/h3&gt;

&lt;p&gt;Our button is the first point of interaction here, and we're already dynamically showing a loader on the button. We're wasting a lot of potential as this dynamic element can be utilized to do much more.&lt;/p&gt;

&lt;p&gt;Let's start by incorporating our button with a success and a failure state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;export function ForgotPasswordForm() {
&lt;/span&gt;    const [loading, setLoading] = useState(false);
&lt;span class="gi"&gt;+   const [isSuccess, setIsSuccess] = useState(false);
+   const [isError, setIsError] = useState(false);
&lt;/span&gt;}
&lt;span class="err"&gt;
&lt;/span&gt;...
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;function handleSubmt() {
&lt;/span&gt;    try {
        //...
&lt;span class="gi"&gt;+       setIsSuccess(true);
+       setIsError(false);
&lt;/span&gt;    } catch (err) {
        //...
&lt;span class="gi"&gt;+       setIsError(true);
+       setIsSuccess(true);
&lt;/span&gt;    } finally {
        setLoading(false);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our button can now have different text based on the state we added earlier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&amp;lt;button
&lt;span class="gd"&gt;-   disabled={loading}
&lt;/span&gt;&lt;span class="gi"&gt;+   disabled={loading || isSuccess}
&amp;gt;
+  {!isError &amp;amp;&amp;amp; !isSuccess &amp;amp;&amp;amp; 'Submit'}
+  {!isError &amp;amp;&amp;amp; 'Click to Retry'}
+  {!isSuccess &amp;amp;&amp;amp; 'Submitted Successfully'}
&lt;/span&gt;&amp;lt;/button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We disable the button on success because we don't want the user to send again and again as it is redundant.&lt;/p&gt;

&lt;p&gt;Since we're disabling the button on success, we should also add some way to reset the state. So that the user doesn't have to refresh the page to enter another input.&lt;/p&gt;

&lt;p&gt;I went with a button to clear the input, which will also reset the success state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;const handleChange = () =&amp;gt; {
&lt;/span&gt;&lt;span class="gi"&gt;+ if (isSuccess) setIsSuccess(false);
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;//...
}
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gi"&gt;+const handleClear = (e) =&amp;gt; {
&lt;/span&gt;    //....
&lt;span class="gi"&gt;+   setIsSuccess(false);
+}
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;//...
&amp;lt;label&amp;gt;Email&amp;lt;/label&amp;gt;
&amp;lt;input type="email" onChange={handleChange} /&amp;gt;
&lt;span class="gi"&gt;+&amp;lt;button onClick={handleClear} aria-label='clear button'&amp;gt;X&amp;lt;/button&amp;gt;
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this we ensured the user has a way to reset the input.&lt;/p&gt;

&lt;p&gt;Finally to display the error message, we can use our existing toast. Or we can just show a error text on the form.&lt;/p&gt;

&lt;p&gt;The final result looks like this&lt;/p&gt;

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

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

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

&lt;p&gt;While design needs to be visible, bold and generate a brand; UX on the other hand needs to be as hidden as possible.&lt;br&gt;
A good UX should comes in the way of user and feels much more natural. It is always the small details that whiff out and causes smell in the UX and when these smell accumulates the UX becomes smelly and the product becomes uninviting.&lt;br&gt;
By no means I want to convey that toasts are bad, our eyes are often deceiving, just by hiding the toast or looking beyond it the underlying problems looks more clearer.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://web.dev/articles/building/a-toast-component" rel="noopener noreferrer"&gt;https://web.dev/articles/building/a-toast-component&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://adrianroselli.com/2020/01/defining-toast-messages.html" rel="noopener noreferrer"&gt;https://adrianroselli.com/2020/01/defining-toast-messages.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>frontend</category>
      <category>ux</category>
    </item>
    <item>
      <title>Handling config files in go</title>
      <dc:creator>Tanishq Singla</dc:creator>
      <pubDate>Fri, 01 Mar 2024 18:08:00 +0000</pubDate>
      <link>https://dev.to/tanishqsingla/handling-config-files-in-go-k85</link>
      <guid>https://dev.to/tanishqsingla/handling-config-files-in-go-k85</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Learning a new language and leaving the comfort zone of your tech stack is a challenging process, one can phrase the experience similar to walking in an unknown territory.&lt;br&gt;
I am currently developing my back-end in go programming language, which came with it's own challenges. Luckily go programming language was very simple, in syntax as well as behavior, so it did not take much effort to get comfortable with it.&lt;br&gt;
However when I got ready to make my first application, my head got clouded with questions. Those questions would typically fall in the following category&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is this a good practice?&lt;/li&gt;
&lt;li&gt;How is this organised?&lt;/li&gt;
&lt;li&gt;Is this how you're supposed to use the framework?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In every step these questions would stop me from developing my application. &lt;br&gt;
The Go docs and manual were not able to satisfy my hunger. I tried reading popular books, but they would leave me with more questions than answers.&lt;/p&gt;
&lt;h2&gt;
  
  
  The solution
&lt;/h2&gt;

&lt;p&gt;I resorted to learning from open source projects. Go has a huge community, also the nature of Go programming language there are plenty of clever programming tips to learn from them. Combining both of the traits you get a lot of open source projects to learn from.&lt;/p&gt;
&lt;h2&gt;
  
  
  Config Handling
&lt;/h2&gt;

&lt;p&gt;One such technique I learned was handling configs in a Go program. This comes from an open source project &lt;a href="https://github.com/Shivamsouravjha/Rocket"&gt;Rocket&lt;/a&gt; by &lt;a href="https://github.com/Shivamsouravjha/"&gt;Shivam Sourav Jha&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;The gist of the approach was to have a separate &lt;code&gt;config&lt;/code&gt; file, and define a global struct/variables for the config and initialize the environment variables. &lt;/p&gt;

&lt;p&gt;If you understood the approach, you don't have to continue. If you're new to go and want to understand what I am talking about I'll be explaining it in detail.&lt;/p&gt;
&lt;h2&gt;
  
  
  Things I improvised
&lt;/h2&gt;

&lt;p&gt;The usage of &lt;code&gt;init&lt;/code&gt; was clever and it was new to me when I first looked at the repo. There are some good ideas to learn from it and also some things that I thought can be improvised.&lt;/p&gt;

&lt;p&gt;For me in the context of this config handling approach, I changed a few things. They are mentioned below&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Remove the &lt;code&gt;Get()&lt;/code&gt; to access env variable. The function can be handy if there is some behavior I want to add before any function can access the config variable, but for now I did not find any use case for it.&lt;/li&gt;
&lt;li&gt;Not exporting the config struct. In the repo for some reason the author exported the &lt;code&gt;Config&lt;/code&gt; struct, I found it useless and kept it in the scope of the package.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Config handling in action
&lt;/h2&gt;

&lt;p&gt;First you need a separate config file and name it under a package.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// config/config.go&lt;/span&gt;
&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;

&lt;span class="c"&gt;// Define your env variables and their type&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;configuration&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// declaring global variable. This is going to be exported in the package.&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;Config&lt;/span&gt; &lt;span class="n"&gt;configuration&lt;/span&gt;

&lt;span class="c"&gt;// Here we initialize our config variables&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="n"&gt;Config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Configuration&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;// assign values to variables&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we're relying on &lt;code&gt;init&lt;/code&gt; function to initialize a variable. Now go has a really neat feature with packages, this &lt;code&gt;init&lt;/code&gt; function gets executed when the  package is used somewhere. So we don't have to manually run the &lt;code&gt;init&lt;/code&gt; function.&lt;/p&gt;

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

&lt;p&gt;Go programming language is rich with open source repos to learn. People creating these repos range from students to professionals helping the world to learn from their code and for me simplifying my learning. Do show them some love by starring their repos.&lt;/p&gt;

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

</description>
      <category>go</category>
    </item>
    <item>
      <title>Deciphering JWTs</title>
      <dc:creator>Tanishq Singla</dc:creator>
      <pubDate>Fri, 23 Feb 2024 17:05:52 +0000</pubDate>
      <link>https://dev.to/tanishqsingla/deciphering-jwts-f4j</link>
      <guid>https://dev.to/tanishqsingla/deciphering-jwts-f4j</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Underpinning seamless logins across apps, JWTs are the workhorses of modern authentication. Their compact structure and built-in security make them ubiquitous in web development frameworks, simplifying token creation and management.&lt;br&gt;
In a tweet exemplifying the growth of a software engineer's focus on understanding the "why" behind technologies, &lt;a href="https://twitter.com/chinmay185"&gt;Chinmay Naik&lt;/a&gt; shared an anecdote &lt;a href="https://x.com/chinmay185/status/1759919896807559529?s=20"&gt;(link)&lt;/a&gt; about early engineers not grasping the problems JWTs solve.&lt;br&gt;
Hence the motivation to write this blog. If you wish to read more on JWT, the &lt;a href="https://auth0.com/resources/ebooks/jwt-handbook"&gt;JWT Handbook&lt;/a&gt; is the go to resource.&lt;/p&gt;
&lt;h2&gt;
  
  
  What are JWTs?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;JSON&lt;/strong&gt; &lt;strong&gt;W&lt;/strong&gt;eb &lt;strong&gt;T&lt;/strong&gt;oken abbreviated as JWT is an open standard &lt;a href="https://datatracker.ietf.org/doc/html/rfc7519"&gt;RFC 7519&lt;/a&gt; which defines a compact and self-contained way for securely transferring information between parties as JSON object.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you too wondered what is &lt;code&gt;self-contained&lt;/code&gt;, then let me explain. JWTs are self-contained as they contain their own information of how they were made e.g What encryption algorithm was used, when they were issued, when they will expire etc.&lt;/p&gt;

&lt;p&gt;As mentioned in the definition, JWTs are used for &lt;em&gt;information transfer&lt;/em&gt;, while we use them for authentication in our applications all we are doing actually is transferring information contained in a JSON format in a JWT.&lt;/p&gt;

&lt;p&gt;Let us look at how this self-contained information is stored in a JWT.&lt;/p&gt;
&lt;h2&gt;
  
  
  Structure of a JWT
&lt;/h2&gt;

&lt;p&gt;Depending on the type of JWT the structure may vary, so before looking at the composition let's explore what are those different types.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unsecured JWTs&lt;/li&gt;
&lt;li&gt;Signed JWTs&lt;/li&gt;
&lt;li&gt;Encrypted JWTs
The information in a JWT is serialized compactly via encoding each part using Base64URL into printable strings and separating them using dots (.)
E.g
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.
TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The decoded header is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"alg"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HS256"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"typ"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"JWT"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The decoded payload is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sub"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1234567890"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John Doe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"admin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Unsecured and Signed JWTs
&lt;/h3&gt;

&lt;p&gt;Unsigned or non-encrypted JWTs are termed as Unsecured JWTs. When you sign an unsecure JWT it becomes a signed JWT.&lt;br&gt;
Both Unsecured and Signed JWT contain &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;header&lt;/li&gt;
&lt;li&gt;payload&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The header and payload contains information termed as &lt;em&gt;claims&lt;/em&gt;.&lt;br&gt;
These &lt;em&gt;claims&lt;/em&gt; establish information about the JWT such as the algorithm used, whether the JWT is signed or unsigned or encrypted, and how to parse the JWT.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Signing the JWT&lt;/strong&gt;&lt;br&gt;
When you sign the JWT using a private key, a signature is appended in the end separated by the (.) to the existing JWT containing the encoded header and payload.&lt;br&gt;
The flow somewhat looks like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;encoded_header &amp;lt;- Base64Encode(header)
encoded_payload &amp;lt;- Base64Encode(payload)
signature &amp;lt;- Base64Encode(Encrypt("encoded_header" + "." + "encoded_payload", private_key))
jwt = encoded_header + "." encoded_payload + "." + signature
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here &lt;code&gt;Base64Encode&lt;/code&gt; function encodes the input to Base64URL encoding and &lt;code&gt;Encrypt&lt;/code&gt; function encrypts the input using private_key which is specified by you.&lt;/p&gt;

&lt;p&gt;If you've been reading closely you would've noticed that we're appending the encrypted key while the header and payload are only encoded.&lt;/p&gt;

&lt;p&gt;To put it simply, the header and payload of a JWT are transparent, implying they can be read by anyone. Hence only non-sensitive information are carried by Signed JWTs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Encrypted JWT&lt;/strong&gt;&lt;br&gt;
To protect the body of a JWT, Encrypted JWTs are created. This type of JWT comprises of&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Header&lt;/li&gt;
&lt;li&gt;The encrypted key&lt;/li&gt;
&lt;li&gt;The initialization vector&lt;/li&gt;
&lt;li&gt;The encrypted data&lt;/li&gt;
&lt;li&gt;The authentication tag&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  More on claims
&lt;/h2&gt;

&lt;p&gt;This was all about the structure of a JWT, let's look at what does each structure contains.&lt;/p&gt;

&lt;p&gt;Information contained inside a JWT is called a &lt;em&gt;claim&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Header claims&lt;/strong&gt;&lt;br&gt;
For non-encrypted JWT the only mandatory claim is the &lt;code&gt;alg&lt;/code&gt; claim which defines the main algorithm in use for encrypting/decrypting the JWT.&lt;/p&gt;

&lt;p&gt;If the JWT doesn't use any encryption algorithm then the &lt;code&gt;alg&lt;/code&gt; value should be "none". E.g&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "alg": "none"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Payload claims&lt;/strong&gt;&lt;br&gt;
There are 3 types of payload claims. The one provided by the JWT standard are called &lt;em&gt;Registered claims&lt;/em&gt;.&lt;br&gt;
These registered claims are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;iss&lt;/code&gt; - from the word issuer, it contains a case-sensitive string or URI that uniquely identifies the party that issued the JWT.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sub&lt;/code&gt; - from the word subject, it contains the information about the subject the JWT is issued for.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;aud&lt;/code&gt; - from the audience, It can be a single case-sensitive string or URI or an array of such values uniquely identifying the intended recipients for the JWT.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;exp&lt;/code&gt; - from the word expiration, contains the UNIX epoch time denoting the expiry time for the JWT.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;nbf&lt;/code&gt; - from &lt;em&gt;not before&lt;/em&gt;, the opposite of &lt;code&gt;exp&lt;/code&gt;, this claim contains the UNIX epoch time denoting the time from which the JWT will be valid.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;iat&lt;/code&gt; - from &lt;em&gt;issued at&lt;/em&gt;, a number (UNIX epoch) denoting at what time the JWT was issued.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;jti&lt;/code&gt; - from &lt;em&gt;JWT ID&lt;/em&gt; - a string representing unique identifier for JWT.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Public and Private claims&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Public claims&lt;/em&gt; are those claims that are either registered with IANA JSON Web Token Claims, registry or named using a collision resistant name.&lt;br&gt;
Whereas &lt;em&gt;private claims&lt;/em&gt; are claims that are defined by the users. Because of their nature of being user defined, care must be taken to prevent collisions with public/registered claims.&lt;/p&gt;

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

&lt;p&gt;I hope through this blog now you know a little more about JWTs. &lt;/p&gt;

</description>
    </item>
    <item>
      <title>The problem with Software Testing Curricula on Web</title>
      <dc:creator>Tanishq Singla</dc:creator>
      <pubDate>Fri, 10 Nov 2023 22:59:41 +0000</pubDate>
      <link>https://dev.to/tanishqsingla/the-problem-with-software-testing-curricula-on-web-4g4h</link>
      <guid>https://dev.to/tanishqsingla/the-problem-with-software-testing-curricula-on-web-4g4h</guid>
      <description>&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;: I don't mean to convey any negative messages towards any individual or organisation. Treat this post as an opinions, and my opinion wouldn't change the world. There maybe some subjects or contents I have misunderstood due to language barrier so feel free to enlighten me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;As a self learner with no mentorship I treat internet as my mentor, and I have preached numerous times that you don't need a course or pay for any books because that information is available on the internet in some form. However the lightning struck when I stepped into the confusing lair of google seo to teach me software testing. &lt;br&gt;
I was not willing to learn it through courses or books so searched google for any resources. I found two blog series&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Wikipedia&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.browserstack.com/guide/what-is-software-testing" rel="noopener noreferrer"&gt;Browserstack guides on testing&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There were few more, but they were completely off track from the core software testing topic so I didn't read them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing type, a total mess
&lt;/h2&gt;

&lt;p&gt;Browserstack and Wikipedia both confused me a lot, during learning I mostly had to piece out what I think was relevant and assume the rest of it as outdated of false. &lt;br&gt;
The first I got confused reading about software testing was Browserstack functional testing guide.&lt;br&gt;
The functional testing guide named as &lt;a href="https://www.browserstack.com/guide/functional-testing" rel="noopener noreferrer"&gt;Functional Testing : A Detailed Guide&lt;/a&gt; teaches about functional testing where Unit testing is mentioned as a part of functional testing as mentioned in their diagram just below &lt;strong&gt;Types of Functional Testing&lt;/strong&gt;.&lt;/p&gt;

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

&lt;p&gt;As mentioned in the guide, &lt;strong&gt;Unit Testing&lt;/strong&gt; is mentioned as a category of functional testing.&lt;br&gt;
The link here references another guide named as &lt;a href="https://www.browserstack.com/guide/unit-testing-a-detailed-guide" rel="noopener noreferrer"&gt;Unit Testing: A Detailed Guide&lt;/a&gt;&lt;br&gt;
When you reach to the &lt;strong&gt;Unit Testing Techniques&lt;/strong&gt; section, you'll encounter that &lt;strong&gt;functional testing&lt;/strong&gt; which links us back to the Functional Testing Guide is mentioned as a technique of Unit testing but we just read that Unit testing is a type of functional testing.&lt;br&gt;
What adds more to the confusion is the TDD section under Unit Testing guide, the &lt;strong&gt;Read More&lt;/strong&gt; section links an article named as &lt;a href="https://www.browserstack.com/guide/difference-between-functional-testing-and-unit-testing" rel="noopener noreferrer"&gt;Differences between Functional Testing and Unit Testing&lt;/a&gt;. &lt;br&gt;
I was already trying to make a sense of this cyclic reference of Unit and Functional Test, and now there's an article that writes about the differences between those.&lt;br&gt;
There were similar articles other than Browserstack's that had the same cyclic reference problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Jargon Problem
&lt;/h2&gt;

&lt;p&gt;It kills my soul when I see a veteran dev or a tester who happen to read about all the jargon ask the newbies to tell differences between tests like Smoke and Sanity tests and carries on a sly smirk.&lt;br&gt;
While working in some orgs, I have realised terms like Sanity doesn't mean anything and testers and software developers love to throw around this word without any context or meaning.&lt;br&gt;
Software testing terms don't provide any meaningful context from the name, some of them are not even native to Software Testing and hence lack the meaning. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Smoke Testing&lt;/li&gt;
&lt;li&gt;Sanity Testing&lt;/li&gt;
&lt;li&gt;Regression Testing&lt;/li&gt;
&lt;li&gt;Structural Testing&lt;/li&gt;
&lt;li&gt;Big Bang Testing (what the hell does it even mean!)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The list goes on as you delve more into the types of tests.&lt;/p&gt;

&lt;p&gt;Software Development in today's standard is also a responsibility of the developer and not just the tester, however the terms used in both disciplines are the same but the whole function and pipeline of the test differ.&lt;br&gt;
&lt;strong&gt;Sanity Vs Smoke Tests&lt;/strong&gt;&lt;br&gt;
If you will search about sanity test and smoke test individually, you'll find their definition same. Wikipedia refers Sanity Tests as a alias of Smoke Tests in their wiki &lt;a href="https://en.wikipedia.org/wiki/Smoke_testing_(software)" rel="noopener noreferrer"&gt;Smoke Testing&lt;/a&gt;.&lt;br&gt;
Luckily after browsing a lot a common pattern appeared which was the difference on how these tests are done and when they are done.&lt;br&gt;
Smoke tests can be done using automation and are performed before they were handed over to the QA, which I imply as a developer running their suite of tests before handing their app to QA. Whereas Sanity Tests are performed after the developer hands over their build to QA.&lt;br&gt;
In other words, smoke tests are performed by developers after they complete their feature or before handing out the final build, and sanity tests are performed by tester after the developer hands out the build of the application.&lt;/p&gt;

&lt;p&gt;Smoke tests and sanity tests by definition are the same, both are confidence tests but the key difference lies in the stage of development pipeline.&lt;/p&gt;

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

&lt;p&gt;I would like to conclude this blog by saying Software Curriculum on web is a mess apart from the weird guides the theoretical content regarding Software Testing is highly outdated and severely lacks in abstracting its core concepts while completely ignoring the modern software development value stream and we need new and better structure to understand software testing.&lt;/p&gt;

</description>
      <category>testing</category>
    </item>
    <item>
      <title>Write your own pre-commit hooks</title>
      <dc:creator>Tanishq Singla</dc:creator>
      <pubDate>Sat, 12 Aug 2023 18:04:17 +0000</pubDate>
      <link>https://dev.to/tanishqsingla/write-your-own-pre-commit-hooks-3ag8</link>
      <guid>https://dev.to/tanishqsingla/write-your-own-pre-commit-hooks-3ag8</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;If you've never written a git hooks don't worry. Writing git hooks is far more easier than you think it is. In this blog I'll be sharing a basic idea how pre-commit hooks are made by creating a simple &lt;code&gt;pre-commit&lt;/code&gt; hook that runs a formatting and linting check on our project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the project
&lt;/h2&gt;

&lt;p&gt;The example in this blog is a simple hello world application using node.js and express but you don't have to learn anything about them as the main focus is to run the scripts and not to create a web-server.&lt;br&gt;
You can find the project in this repo - &lt;a href="https://github.com/TanishqSingla/pre-commit-example"&gt;pre-commit-example&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Project overview
&lt;/h2&gt;

&lt;p&gt;The project contains our hello world application and the logic for it is defined in &lt;code&gt;server.js&lt;/code&gt; and then there are some config files for &lt;code&gt;eslint&lt;/code&gt; and &lt;code&gt;prettier&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;server.js&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello world&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;server is running on http://127.0.0.1:3000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;eslint and prettier&lt;/strong&gt;&lt;br&gt;
As for eslint and prettier, I am using prettier plugins with eslint, you can find more details for it in this blog - &lt;a href="https://dev.to/tanishqsingla/you-might-not-need-separate-config-for-prettier-and-eslint-m9e"&gt;You might not need a separate config for eslint and prettier&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;env&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;commonjs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;es2021&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;extends&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eslint:recommended&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;plugin:prettier/recommended&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;plugins&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prettier&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;parserOptions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ecmaVersion&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;latest&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rules&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prettier/prettier&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;semi&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;useTab&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;indent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tab&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;semi&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;always&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;quotes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;double&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you take a look at our config and &lt;code&gt;server.js&lt;/code&gt; file, you will realize that when we will run our linter it is going throw errors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;scripts&lt;/strong&gt;&lt;br&gt;
I've added scripts to run our eslint in the &lt;code&gt;package.json&lt;/code&gt; file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;scripts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lint&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eslint .&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lint:fix&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; eslint --fix .&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Writing our pre-commit
&lt;/h2&gt;

&lt;p&gt;Let's write our pre-commit hook. The general idea of writing our pre-commit hook (in this case) is to avoid code with linting errors to get commited, this will streamline our development cycle as developers often forget small things in the code which might get alarmed in our lint stage.&lt;/p&gt;

&lt;p&gt;To write a pre-commit hook all we need to do is a create a bash script file named &lt;code&gt;pre-commit&lt;/code&gt; in the &lt;code&gt;hooks&lt;/code&gt; folder under &lt;code&gt;.git&lt;/code&gt; folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;

npm run lint

&lt;span class="nv"&gt;SUCCESS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;

&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$SUCCESS&lt;/span&gt; &lt;span class="nt"&gt;-ne&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="nb"&gt;exit &lt;/span&gt;0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it! Yes, this is our pre commit hook that checks if our code is formatted or not. Let's look at what we're doing here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;npm run lint&lt;/strong&gt;&lt;br&gt;
This is the command we defined in our &lt;code&gt;package.json&lt;/code&gt;, this commands run the eslint command and displays the error.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SUCCESS=$?&lt;/strong&gt;&lt;br&gt;
Here we're assigning a variable named &lt;code&gt;SUCCESS&lt;/code&gt; and assigning it to the status code of the last command that ran i.e &lt;code&gt;npm run lint&lt;/code&gt;. Commands that run successfully return 0 as their value and those who don't  returns a non-zero value.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[ $SUCCESS -ne 0] &amp;amp;&amp;amp; exit 1&lt;/strong&gt;&lt;br&gt;
This is our conditional statement that checks if the &lt;code&gt;SUCCESS&lt;/code&gt; value is not 0, if it is not 0 then it exits with code 1 which is a non-zero value implying our program exited with an error.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;exit 0&lt;/strong&gt;&lt;br&gt;
If our conditional statement returned false, we exit the program with 0 meaning success.&lt;/p&gt;
&lt;h3&gt;
  
  
  One last step
&lt;/h3&gt;

&lt;p&gt;Now that we've created our script we need to make it an executable so that the git can execute this file before we hit commit. To do that we provide the file with execute access. Run this command in your terminal to do that&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x .git/hooks/pre-commit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now when you'll try to commit the changes it won't let you do that, as we have linting errors in our code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations of this approach
&lt;/h2&gt;

&lt;p&gt;As simple as this approach looks there is one limitation with this approach, the hooks are not versioned by git and hence not stored in the repo. &lt;br&gt;
There are work arounds to this mentioned in this &lt;a href="https://stackoverflow.com/questions/427207/can-git-hook-scripts-be-managed-along-with-the-repository"&gt;stackoverflow post&lt;/a&gt;. But this relies on Git v2.9 or older. &lt;br&gt;
You can also create a simple script that copies the contents of your git hooks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other solutions
&lt;/h2&gt;

&lt;p&gt;You can follow &lt;a href="https://githooks.com/"&gt;Git Hooks&lt;/a&gt; docs, this doc contains some amazing project that can supercharge your development cycle with git hooks.&lt;br&gt;
You can also use &lt;code&gt;pre-commit&lt;/code&gt; a very famous package for setup like this. You can refer this &lt;a href="https://twitter.com/TanishqSingla_/status/1690422847448244224?s=20"&gt;tweet&lt;/a&gt; of mine.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>git</category>
      <category>bash</category>
    </item>
    <item>
      <title>You might not need separate config for prettier and eslint</title>
      <dc:creator>Tanishq Singla</dc:creator>
      <pubDate>Thu, 10 Aug 2023 05:58:55 +0000</pubDate>
      <link>https://dev.to/tanishqsingla/you-might-not-need-separate-config-for-prettier-and-eslint-m9e</link>
      <guid>https://dev.to/tanishqsingla/you-might-not-need-separate-config-for-prettier-and-eslint-m9e</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;Recently &lt;a href="https://github.com/lambtron"&gt;Andy Jiang&lt;/a&gt; from Deno posted this wonderful article &lt;a href="https://deno.com/blog/node-config-hell"&gt;Node.js's Config Hell Problem&lt;br&gt;
&lt;/a&gt; highlighting the config hell in a project that uses Node.js and this makes a wonderful case for using Deno over Node.js in this particular case.&lt;br&gt;
In this blog series I will be exploring some ways to reduce config hell. Let's start with the first part of this series.&lt;/p&gt;
&lt;h2&gt;
  
  
  You might not need separate config for prettier and eslint
&lt;/h2&gt;

&lt;p&gt;If you use eslint and prettier together you might be familiar with conflicting styling rules of eslint and prettier, and would've preferred to only using eslint for linting and prettier for formatting, and end up creating 2 files like &lt;code&gt;.prettierrc&lt;/code&gt; and &lt;code&gt;.eslintrc&lt;/code&gt; and let me show you, you only need one.&lt;/p&gt;

&lt;p&gt;Linting and formatting are often clubbed together and it makes sense to have one config that handles both. By using eslint plugins we can achieve that.&lt;/p&gt;
&lt;h3&gt;
  
  
  Using eslint plugins
&lt;/h3&gt;

&lt;p&gt;We'll be using these 2 plugins&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;eslint-config-prettier&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;eslint-plugin-prettier&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By using these we eliminate the need &lt;code&gt;prettier&lt;/code&gt; installed as dev dependency, if you want to add prettier as a eslint rule (which this blog does).&lt;/p&gt;

&lt;p&gt;Install these two plugins with the following command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# for npm&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-D&lt;/span&gt; eslint-config-prettier eslint-plugin-prettier

&lt;span class="c"&gt;# for yarn&lt;/span&gt;
yarn add &lt;span class="nt"&gt;-D&lt;/span&gt; eslint-config-prettier eslint-plugin-prettier

&lt;span class="c"&gt;# for pnpm&lt;/span&gt;
pnpm add &lt;span class="nt"&gt;-D&lt;/span&gt; eslint-config-prettier eslint-plugin-prettier
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After adding the dependency let's modify our &lt;code&gt;eslint&lt;/code&gt; config. I am using &lt;code&gt;.eslintrc.json&lt;/code&gt;, if you're using other formats you can change the syntax according to that.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;eslint&lt;/code&gt; config add &lt;code&gt;plugin:prettier/recommend&lt;/code&gt; in the extends field and add &lt;code&gt;prettier&lt;/code&gt; in &lt;code&gt;plugins&lt;/code&gt; field&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// .eslintrc.json&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;extends&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;your&lt;/span&gt; &lt;span class="nx"&gt;configs&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;plugin:prettier/recommended&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;plugins&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;your&lt;/span&gt; &lt;span class="nx"&gt;plugins&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prettier&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's add our rules&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// .eslintrc.json&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rules&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prettier/prettier&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;useTabs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;singleQuote&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;semi&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;indent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tab&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;quotes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;single&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;semi&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;always&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the config file mentioned above we're using the &lt;code&gt;prettier&lt;/code&gt; config options such as &lt;code&gt;useTabs&lt;/code&gt;, &lt;code&gt;singleQuote&lt;/code&gt; and &lt;code&gt;semi&lt;/code&gt; inside the eslint rule.&lt;br&gt;
This config allows us to format the documents using prettier and with our desired config when we run &lt;code&gt;eslint --fix .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This method saves us having 2 different files for linter and formatter, I'll be exploring more ways and them in this series. As always do let me know your suggestions.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://prettier.io/docs/en/integrating-with-linters"&gt;Integrating with linters - Prettier Docs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/prettier/eslint-config-prettier"&gt;eslint-config-prettier&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/prettier/eslint-plugin-prettier"&gt;eslint-plugin-prettier&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>bash</category>
    </item>
    <item>
      <title>How google keep does input form</title>
      <dc:creator>Tanishq Singla</dc:creator>
      <pubDate>Mon, 12 Dec 2022 19:15:46 +0000</pubDate>
      <link>https://dev.to/tanishqsingla/how-google-keep-does-input-form-2p3o</link>
      <guid>https://dev.to/tanishqsingla/how-google-keep-does-input-form-2p3o</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In my last blog, I realized that I actually bumped onto a tip of iceberg, the google keep input form is a lot more complicated and the previous blog didn't do any justice to explain the complexity.&lt;br&gt;
Hence I started this series with the previous blog as part 1. If you haven't read the previous part yet, you can check it out &lt;/p&gt;
&lt;h2&gt;
  
  
  The problem with input tags
&lt;/h2&gt;

&lt;p&gt;The problem with using input tags is that you can only have a single line input.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fumrudwr5ldphupdvk7jl.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fumrudwr5ldphupdvk7jl.gif" alt="Image showing input tag problem" width="600" height="133"&gt;&lt;/a&gt;&lt;br&gt;
So multiline input was a problem, then I thought of trying out textarea, but adding new rows to textarea dynamically was a pain, so textarea also didn't work out.&lt;/p&gt;
&lt;h2&gt;
  
  
  Divs to the rescue
&lt;/h2&gt;

&lt;p&gt;Turns out I didn't need any input tag to solve the problem, but a very useful property of div's (useful at least in this scenario).&lt;/p&gt;
&lt;h3&gt;
  
  
  contentEditable Divs
&lt;/h3&gt;

&lt;p&gt;If you guessed &lt;strong&gt;contentEditable&lt;/strong&gt; divs you deserve a pat on the back. It turns out divs with contentEditable attribute solves our problems.&lt;br&gt;
Let's jump into our code and use them. If you're following up from the previous part, you can just update your code or you can check out full code at &lt;a href="https://codepen.io/Tanishq/pen/poKmOre" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;strong&gt;HTML&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"createForm"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"input"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"title"&lt;/span&gt; &lt;span class="na"&gt;contentEditable&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"input"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"content"&lt;/span&gt; &lt;span class="na"&gt;contentEditable&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;CSS&lt;/strong&gt;&lt;br&gt;
For CSS I'll just update the form with the id &lt;code&gt;createForm&lt;/code&gt; and input with class &lt;code&gt;input&lt;/code&gt;.&lt;br&gt;
&lt;strong&gt;JS&lt;/strong&gt;&lt;br&gt;
In JS only the &lt;code&gt;form&lt;/code&gt; selector needs to be corrected i.e&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;createForm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final result should look like this.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7z4o4nqh8vtcykiroeu0.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7z4o4nqh8vtcykiroeu0.gif" alt="Image showing result after changes" width="600" height="338"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Adding Placeholder
&lt;/h3&gt;

&lt;p&gt;The absence of placeholder is hard to ignore, let's work on fixing that.&lt;br&gt;
Luckily there are some neat css properties we can use just to do that, so no need to add javascript.&lt;br&gt;
We need to add some text content to our divs, if you guessed &lt;code&gt;content&lt;/code&gt; property of pseudo-elements then you deserve a pat on back. But here's a catch we only need to add content when there there is no text present in our div, here again we're going to use css saving us a bunch of JS logic, we're going to use &lt;code&gt;:empty&lt;/code&gt; pseudo-class, a combination of both of them is just what we need.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nf"&gt;#title&lt;/span&gt;&lt;span class="nd"&gt;:empty::before&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;"Title"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;#content&lt;/span&gt;&lt;span class="nd"&gt;:empty::before&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;"Take a note..."&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;Better Approach&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
Suppose we're working on a solution which requires us to do something like this and we have a lot of editable divs, by using this style we're writing css for every div that contains a placeholder and not to mention we're also writing same css for styling placeholder causing our css to bloat up.&lt;br&gt;
We can solve this by adding an attribute in our div tag that will hold the value of placeholder and using that value in our css with &lt;code&gt;attr()&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"createForm"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"input"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"title"&lt;/span&gt; &lt;span class="na"&gt;contentEditable&lt;/span&gt; &lt;span class="na"&gt;data-placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"input"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"content"&lt;/span&gt; &lt;span class="na"&gt;contentEditable&lt;/span&gt; &lt;span class="na"&gt;data-placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Take a note..."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.input&lt;/span&gt;&lt;span class="nd"&gt;:empty::before&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data-placeholder&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  One last problem
&lt;/h3&gt;

&lt;p&gt;If you're using firefox you may not notice it, but there's a bug in our input form. When we focus out of div that contains title, instead of focusing out we focus back on the content div.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjkwahzv0988rpcad1zw7.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjkwahzv0988rpcad1zw7.gif" alt="Video showing the bug" width="600" height="338"&gt;&lt;/a&gt;&lt;br&gt;
If you want to know why this is happening you can look at the explanation &lt;a href="https://stackoverflow.com/a/34445203" rel="noopener noreferrer"&gt;here&lt;/a&gt; by a stack overflow user.&lt;br&gt;
As mentioned in the solution we can get around with this bug by simply wrapping our contentEditable divs inside a div.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"createForm"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"input"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"title"&lt;/span&gt; &lt;span class="na"&gt;contentEditable&lt;/span&gt; &lt;span class="na"&gt;data-placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"input"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"content"&lt;/span&gt; &lt;span class="na"&gt;contentEditable&lt;/span&gt; &lt;span class="na"&gt;data-placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Take a note..."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Wrap up
&lt;/h2&gt;

&lt;p&gt;I hope you learned some new tricks from the blog, as always feel free to use comment section for suggestions or corrections.&lt;/p&gt;

</description>
      <category>gratitude</category>
      <category>career</category>
    </item>
    <item>
      <title>Google Keep style input form in VanillaJS</title>
      <dc:creator>Tanishq Singla</dc:creator>
      <pubDate>Fri, 02 Dec 2022 08:55:52 +0000</pubDate>
      <link>https://dev.to/tanishqsingla/google-keep-style-input-form-in-vanillajs-19d3</link>
      <guid>https://dev.to/tanishqsingla/google-keep-style-input-form-in-vanillajs-19d3</guid>
      <description>&lt;h2&gt;
  
  
  What we're building
&lt;/h2&gt;

&lt;p&gt;If you've ever used google keep you must be familiar with their dynamic input form for creating a note. The form looks simple on first look, but it can be a bit tricky to come up with a solution.&lt;br&gt;
The end result is going to look like this.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F67r5zvsyavijm1e0uqjz.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F67r5zvsyavijm1e0uqjz.gif" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you directly want to dive into the code, you can check out the codepen &lt;a href="https://codepen.io/Tanishq/pen/gOKBjwL" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Markup
&lt;/h2&gt;

&lt;p&gt;Let's work on our form markup i.e html and css. I am just going to create a simple form with two input tags. This part is completely optional, if you're a beginner you may find some new things but if you're not you can skip to the next section.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Title"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"title"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Take a note..."&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"content"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since I am creating this form in &lt;a href="https://codepen.io/" rel="noopener noreferrer"&gt;codepen&lt;/a&gt;, you may see some CSS on the body, the CSS in body just centers the form, and you may skip over it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Styling our form
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;form&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-flow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;540px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="m"&gt;#5f6368&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;3px&lt;/span&gt; &lt;span class="m"&gt;5px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To stack the input I've used &lt;code&gt;display: flex&lt;/code&gt; with column direction.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Script
&lt;/h2&gt;

&lt;p&gt;Now let's add some interactivity on our form using JavaScript. In google keep's input the title input is shown after the input that contains the content for our note is focused, we're going to implement the same.&lt;br&gt;
First I am going to get the elements in our html inside javascript.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;form&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a user first looks at the form, we don't want to show the title input, to do that, we're going to set the display property to none.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;display&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the user focuses on content input we want to show the title input.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;focus&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;display&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can show the title input when the content input is focused, but we should also be able to hide the title when the user is not focused on both of the inputs, let's work on that.&lt;br&gt;
I am going to capture &lt;code&gt;focusout&lt;/code&gt; event in the form.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;focusOut&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleFocusOut&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you may wonder why &lt;code&gt;focusout&lt;/code&gt; on form instead of &lt;code&gt;blur&lt;/code&gt; event on inputs? &lt;br&gt;
By listening on &lt;code&gt;focusout&lt;/code&gt; event we get access to &lt;code&gt;relatedTarget&lt;/code&gt; property, which is useful since we want to know if the user has clicked on an input inside the form or the user has clicked outside the form.&lt;br&gt;
Now let's define the callback function we passed i.e &lt;code&gt;handleFocusOut&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleFocusOut&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;relatedTarget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;relatedTarget&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  
  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;relatedTarget&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;display&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Wrap up
&lt;/h2&gt;

&lt;p&gt;Our google keep style form is complete, if you want to look at the code the you can checkout the codepen &lt;a href="https://codepen.io/Tanishq/pen/gOKBjwL" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;br&gt;
Feel free to add suggestions using the comment section.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>html</category>
      <category>css</category>
    </item>
    <item>
      <title>Setup vercel with supabase for our project</title>
      <dc:creator>Tanishq Singla</dc:creator>
      <pubDate>Sun, 11 Sep 2022 07:44:41 +0000</pubDate>
      <link>https://dev.to/tanishqsingla/setup-vercel-with-supabase-for-our-project-528b</link>
      <guid>https://dev.to/tanishqsingla/setup-vercel-with-supabase-for-our-project-528b</guid>
      <description>&lt;p&gt;Now that we're done with our supabase setup let's work on our frontend environment for our application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Github Setup
&lt;/h2&gt;

&lt;p&gt;Before we setup vercel, we're going to setup our code repository first, I'll be using github to upload the repository. Let's quickly make our repo, since we'll be working with Nextjs I'll be creating a Nextjs app using&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-next-app taskboard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you like to work with typescript you can pass the ts flag in the command, your command should look like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-next-app &lt;span class="nt"&gt;--ts&lt;/span&gt; taskboard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;NOTE: I'll be using javascript throughout the tutorial, this series will have add an extra part where I'll be porting the app to typescript.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now let's make our github repository and push the code in our local machine to the repo.&lt;/p&gt;

&lt;p&gt;I'll be creating different releases, so you can go through the different version and check what the code looked like in each of them.&lt;/p&gt;

&lt;p&gt;You can find the link for my repo &lt;a href="https://github.com/TanishqSingla/supanext-taskboard"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vercel Setup
&lt;/h2&gt;

&lt;p&gt;For hosting our project on vercel we will need the code repository first.&lt;/p&gt;

&lt;p&gt;This is how my project configuration looks like in vercel.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ny62dktk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sikh4nxunv0b3ad27l2s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ny62dktk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sikh4nxunv0b3ad27l2s.png" alt="Image showing vercel page with project details" width="800" height="464"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;HIT DEPLOY!&lt;/p&gt;

&lt;p&gt;you can find the link for the application &lt;a href="https://supanext-taskboard.vercel.app/"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrating Supabase
&lt;/h2&gt;

&lt;p&gt;We've successfully created our Nextjs app and it is deployed, now vercel, the last step that is remaining is integrating our project with supabase. &lt;br&gt;
Click on setting tab of your project and then click integrations&lt;/p&gt;

&lt;p&gt;You can refer this &lt;a href="https://supabase.com/docs/guides/integrations/vercel"&gt;doc&lt;/a&gt; created by supabase or follow the steps below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CWiAlOi7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/csucn18a53xq5vr2ja9k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CWiAlOi7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/csucn18a53xq5vr2ja9k.png" alt="Vercel project page with arrows pointing to settings tab and integration button" width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now click on &lt;code&gt;Browse Marketplace&lt;/code&gt; and search for &lt;code&gt;supabase&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9FzLBVrR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c3v6meoleoxv2g6ixwyu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9FzLBVrR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c3v6meoleoxv2g6ixwyu.png" alt="Vercel integration page with arrow pointing to browse marketplace button" width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fyCJOu23--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qnbx88m6bf2txxyzkxjz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fyCJOu23--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qnbx88m6bf2txxyzkxjz.png" alt="Vercel integration marketplace with supabase searched" width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eisvLywv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/55nu9mrmfwwykhs8yay8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eisvLywv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/55nu9mrmfwwykhs8yay8.png" alt="Vercel supabase integration page with arrow pointing to add integration" width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you'll click &lt;code&gt;add integration&lt;/code&gt; vercel will ask for the vercel account you want to add integration to, select your account and hit continue.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WDXCvkd8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3ucke0pu40p7nnmknucv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WDXCvkd8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3ucke0pu40p7nnmknucv.png" alt="Vercel supabase integration modal asking to input the scope" width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--d_P5JTOA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b6c0aulvz54hthv8i9w4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--d_P5JTOA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b6c0aulvz54hthv8i9w4.png" alt="Vercel supabase integration configuration page with modal asking to input project name" width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hit continue and then add integration&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6XfRKexC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5mz93xtnwif44kppsbce.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6XfRKexC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5mz93xtnwif44kppsbce.png" alt="Modal asking to input supabase and vercel project name" width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now when you'll click on your project setting and check environment variables section you'll see supabase environment variables already added&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aJTDnGvZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5swfvqo2so4bcvde9tsh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aJTDnGvZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5swfvqo2so4bcvde9tsh.png" alt="Vercel Project settings environment variables tag showing supabase environment variables already added" width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>vercel</category>
      <category>supabase</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Let's make a task managing app with nextjs and supabase</title>
      <dc:creator>Tanishq Singla</dc:creator>
      <pubDate>Sun, 11 Sep 2022 06:14:47 +0000</pubDate>
      <link>https://dev.to/tanishqsingla/lets-make-a-task-managing-app-with-nextjs-and-supabase-40hg</link>
      <guid>https://dev.to/tanishqsingla/lets-make-a-task-managing-app-with-nextjs-and-supabase-40hg</guid>
      <description>&lt;p&gt;Hello everyone! Welcome to my tutorial, here I'll be showing you how I made a task managing app using Supabase and Next.js. The frontend will be hosted on &lt;a href="https://vercel.app"&gt;vercel&lt;/a&gt; and we will be using &lt;a href="https://supabase.com"&gt;supabase&lt;/a&gt; for managing our database.&lt;/p&gt;

&lt;p&gt;Before I begin I would like to address that there might be some implementations or practices used which might have a better alternative and there may be some which are not recommended at all. I am open for recommendations as well as correction and you may use the comment section to do so.&lt;/p&gt;

&lt;p&gt;The purpose of the blog is not to teach you the basics so knowledge of fundamental concepts is required.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's begin
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Supabase setup
&lt;/h3&gt;

&lt;p&gt;First, let's setup our database in supabase. Before creating your database you need to create a project in supabase, to do so click on new project and select your organization if you already have one, if not then make a new by clicking on &lt;code&gt;New Organization&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now enter your project details&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GppVHa6e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0kzkwc3txumbz9j0ca24.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GppVHa6e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0kzkwc3txumbz9j0ca24.png" alt="Screenshot of supabase create project form" width="800" height="444"&gt;&lt;/a&gt;&lt;br&gt;
Here's how my project details look like. Now let's hit &lt;code&gt;Create New Project&lt;/code&gt;, now supabase will take a minute or two to setup your project.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;NOTE: While creating your project details there will be an option to select region, you can select any region but keep in mind that you won't be able to change it later.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Creating our database table in supabase
&lt;/h3&gt;

&lt;p&gt;Now this is one of the things I like about supabase. Supabase provides you two options for managing tables, either you can use the supabase UI or if you love writing SQL queries to manage your database you can do that too!&lt;br&gt;
I am going to demonstrate how to create a table in both of them.&lt;/p&gt;
&lt;h4&gt;
  
  
  Create Table using Supabase UI
&lt;/h4&gt;

&lt;p&gt;For using supabase UI go to &lt;code&gt;table editor&lt;/code&gt; in the left pane and click new table.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PSveqJ8P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nzztkbacvdttw18mjqgw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PSveqJ8P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nzztkbacvdttw18mjqgw.png" alt="Project home page in supabase with arrow pointing to table editors icon" width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ILkz0E3Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/domnxn9yzsslhhl596dw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ILkz0E3Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/domnxn9yzsslhhl596dw.png" alt="Supabase table editor page with arrows pointing to create table buttons" width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After you click on create table you'll see a sidebar. In the sidebar you'll see option to provide name and description to your table and two database columns already provided i.e id and created_at.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RJwEZYxn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/49e1dkoegy1rjozahie2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RJwEZYxn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/49e1dkoegy1rjozahie2.png" alt="Image showing create table sidebar" width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I am going to change a few values&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;id&lt;/code&gt; data type to &lt;code&gt;uuid&lt;/code&gt; and its default value will be generated by default value to to a function that will return uuids, you can do that by clicking on the hamburger menu inside the default value input field and selecting the &lt;code&gt;uuid_generate_v4()&lt;/code&gt; under suggestions.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;created_at&lt;/code&gt; to &lt;code&gt;createdAt&lt;/code&gt;, cause I like camel casing.&lt;/li&gt;
&lt;li&gt;I am also going to enable realtime, to show data instantly when someone updates it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jaqVjKvB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tlrz3lt4bfowxzmopdnr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jaqVjKvB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tlrz3lt4bfowxzmopdnr.png" alt="Image showing sidebar after my changes" width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, let's add different fields to our table. I am going to add following fields to the table.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;title&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;description&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;status&lt;/code&gt; with default value &lt;code&gt;pending&lt;/code&gt;
and their type is going to be &lt;code&gt;text&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result is going to look like this:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7Vjox_hi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6h71rjct0jdx1ojvw093.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7Vjox_hi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6h71rjct0jdx1ojvw093.png" alt="Image showing final changes in table editor" width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now just hit save and you have successfully created your database table.&lt;/p&gt;
&lt;h4&gt;
  
  
  Creating table using Supabase SQL editor
&lt;/h4&gt;

&lt;p&gt;For creating table using SQL editor click on the SQL editor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Nw3jMmiD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/60u09393vwm8y7dysa3o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Nw3jMmiD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/60u09393vwm8y7dysa3o.png" alt="Image showing SQL editor page with arrow pointing to SQL editor icon in left pane" width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on &lt;code&gt;New Query&lt;/code&gt; to open an editor where we will be writing our SQL query.&lt;/p&gt;

&lt;p&gt;This is the query I'll be using to create our table.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;create&lt;/span&gt; &lt;span class="k"&gt;table&lt;/span&gt; &lt;span class="n"&gt;tasks&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt;  &lt;span class="n"&gt;uuid&lt;/span&gt;  &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="n"&gt;uuid_generate_v4&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="k"&gt;primary&lt;/span&gt; &lt;span class="k"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nv"&gt;"createdAt"&lt;/span&gt; &lt;span class="nb"&gt;timestamp&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="nb"&gt;text&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="s1"&gt;'pending'&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After writing the query click run and your table will be created, you can check that by clicking on &lt;code&gt;table editor&lt;/code&gt; or view your database by clicking the database icon. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--j262n-bv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lvhtrbs63tqeqcxo9o6m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--j262n-bv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lvhtrbs63tqeqcxo9o6m.png" alt="Image showing sql editor page with arrows pointing to run button" width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now if you remember we enabled realtime in our table when we created it using the supabase UI, we can do the same for this table by writing a new query or using supabase UI.&lt;/p&gt;

&lt;p&gt;You can refer &lt;a href="https://supabase.com/docs/guides/database#realtime"&gt;supabase doc&lt;/a&gt; for enabling realtime. &lt;code&gt;I've used the following query to enable realtime:&lt;br&gt;
&lt;/code&gt;``sql&lt;br&gt;
begin;&lt;br&gt;
  drop publication if exists supabase_realtime;&lt;/p&gt;

&lt;p&gt;create publication supabase_realtime;&lt;br&gt;
commit;&lt;/p&gt;

&lt;p&gt;alter publication supabase_realtime add table tasks&lt;br&gt;
`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Using supabase UI to enable realtime.
&lt;/h4&gt;

&lt;p&gt;For enabling realtime using UI click on &lt;code&gt;Database&lt;/code&gt; icon in the left pane&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--c71OC66u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jyugga9bbnteikqc72ct.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--c71OC66u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jyugga9bbnteikqc72ct.png" alt="Image showing database page of supabase with arrow pointing to database icon in left pane" width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now click on Replications and click on the button under source column. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--l9o8kXqq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sic5g6dsmavzz74zb4a6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--l9o8kXqq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sic5g6dsmavzz74zb4a6.png" alt="Image showing replication section under Database page with arrows pointing to replication section button and source column button" width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now click on the switch to enable replication for your table, this will enable realtime for your database table.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vbezDcbe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5do69gtb5t78d3brlg35.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vbezDcbe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5do69gtb5t78d3brlg35.png" alt="Tables under replication section with arrows pointing to enable replication switch" width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;NOTE: Supabase recommends using RLS (Row level security) when using realtime this is to prevent unauthorized read and writes to your DB, we will setup this later when we will setup authentication for our app.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Hurray! You've successfully created your table in supabase.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>supabase</category>
    </item>
    <item>
      <title>The DevOps Handbook review</title>
      <dc:creator>Tanishq Singla</dc:creator>
      <pubDate>Mon, 02 May 2022 19:33:43 +0000</pubDate>
      <link>https://dev.to/tanishqsingla/the-devops-handbook-review-3ohi</link>
      <guid>https://dev.to/tanishqsingla/the-devops-handbook-review-3ohi</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;It is often advised that one should not judge the book by its cover but it was not the cover that kept me from reading the book, it was the title, 'DevOps Handbook' and frankly I am not a devops guy, as a person who finds docker and Kubernetes very intimidating one can relate to my reluctance.&lt;br&gt;
What got me started was the subtitle of the book 'How to Create World-Class Agility, Reliability, and Security in Technology Organizations', as it implies the book focuses more on designing the organization, rather than learning about a specific tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who is this book for?
&lt;/h2&gt;

&lt;p&gt;If you work in a company that works on a particular piece of technology then this book is for you irrespective of your role (Development/QA/Deployment or Operations/Security/Sales).&lt;/p&gt;

&lt;h2&gt;
  
  
  My Review of the book
&lt;/h2&gt;

&lt;p&gt;The book starts with a brief history of various movements in manufacturing sector namely &lt;strong&gt;The Lean Movement&lt;/strong&gt;, &lt;strong&gt;Toyota kata&lt;/strong&gt; as well as movements in technology sector such as &lt;strong&gt;The Agile Manifesto&lt;/strong&gt; and The &lt;strong&gt;Continuous Delivery Movement&lt;/strong&gt;, and explains how all this resulted in what we call today DevOps.&lt;/p&gt;

&lt;p&gt;Further into the book we encounter the concept of value stream, which the book centres around a lot. Value stream especially technology value stream is defined as the process required to convert a business hypothesis into a technology-enabled service that delivers value to the customers. The book explains the various parts of the value stream both in manufacturing sector and relates it with the different phases in technology sector.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;DevOps Ideal&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;The authors consciously use the word ideal and encourage the reader to &lt;strong&gt;&lt;em&gt;continually improve our setup/organisation&lt;/em&gt;&lt;/strong&gt; to meet that ideal. Continuous Improvement in DevOps finds it roots back to The Lean Movement significance of which was realised in Toyota Kata.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;The Three Ways: The principles of Underpinning DevOps&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;Finally we learn about the three important ways factoring on which we can define DevOps in practice in an organisation.&lt;br&gt;
The first way enables fast left-to-right flow of work, the flow of work is the technology value stream which starts from Development to Operations and to the customer. In the first way we make our work more visible and constantly optimise our processes down the value stream.&lt;br&gt;
The second way facilitates the fast and constant flow of feedback from right to left at all stages of our value stream. This requires &lt;em&gt;Amplifying the feedbacks&lt;/em&gt; to prevent the mistakes from repeating as well as enabling faster detection and recovery.&lt;br&gt;
The third way facilitates the creation of a generative, high-trust culture that supports dynamic disciplined and scientific approach to experimentation as well as risk-taking, overall creating a framework for organisational learning both from success and failure.&lt;/p&gt;

&lt;p&gt;In the later part of the book we dive deeper into aforementioned concepts and explore DevOps in practice in various organisation. The authors provide real-life examples of organisations that adopted DevOps and how it improved their organisation as well as the product/service they offer the customer.&lt;/p&gt;

&lt;p&gt;I hope this review kindles your interest in the book and encourages you to read it.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Too many commits, squash'em!!</title>
      <dc:creator>Tanishq Singla</dc:creator>
      <pubDate>Thu, 21 Oct 2021 20:24:40 +0000</pubDate>
      <link>https://dev.to/tanishqsingla/too-many-commits-squashem-k0o</link>
      <guid>https://dev.to/tanishqsingla/too-many-commits-squashem-k0o</guid>
      <description>&lt;p&gt;If you're someone like me who likes to commit every small change and end up having too many commits for a single feature and think "Wouldn't it be nice if you can merge some of those meaningless commits?"&lt;/p&gt;

&lt;h2&gt;
  
  
  Squash to the rescue
&lt;/h2&gt;

&lt;p&gt;Turns out you can do just that in OG git. Let us look how to use &lt;code&gt;squash&lt;/code&gt;, for following the tutorial I've created a github repo, you can open the repo by clicking &lt;a href="https://github.com/TanishqSingla/squash-example"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fixing those commits
&lt;/h2&gt;

&lt;p&gt;Take a min and look at the commit section in the repo and check the content of those commits.&lt;br&gt;
If you're also weirded out by those awful commits then don't worry, we'll fix them together.&lt;/p&gt;

&lt;p&gt;First let's find the commits that are meaningless.&lt;br&gt;
The first one that I feel is meaningless is the 3rd commit form the start of branch, here we only change the title of the this can easily be merged with the boilerplate commit.&lt;/p&gt;

&lt;p&gt;In a terminal do &lt;code&gt;git rebase -i HEAD~5&lt;/code&gt;. This command will open the rebase command in interactive mode with the last 5 commits you've from the current commit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pick b1b37b5 Added boiler plate code
pick 125e103 Changing title
pick c6c03ac Adding navbar list
pick 3816fa0 Adding Downloads in navbar list
pick 10534c0 Added Pricing section

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

&lt;/div&gt;



&lt;p&gt;You should see something like this in your text editor which you've chosen as default in git. You can do a bunch of stuff in here, commands for which will be available in the same.&lt;br&gt;
Now, what we do is change that &lt;code&gt;pick&lt;/code&gt; in our commit where we change our title to &lt;code&gt;squash&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The end result should look like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pick b1b37b5 Added boiler plate code
squash 125e103 Changing title
pick c6c03ac Adding navbar list
pick 3816fa0 Adding Downloads in navbar list
pick 10534c0 Added Pricing section
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Changing the &lt;code&gt;pick&lt;/code&gt; to &lt;code&gt;squash&lt;/code&gt; will basically merge the &lt;code&gt;Changing title&lt;/code&gt; commit with the &lt;code&gt;Added boiler plate code&lt;/code&gt; commit.&lt;/p&gt;

&lt;p&gt;Save the file and close it. &lt;/p&gt;

&lt;p&gt;Now you should see this message popping up in a file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# This is a combination of 2 commits.
# This is the 1st commit message:

Added boiler plate code

# This is the commit message #2:

Changing title

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Fri Oct 22 01:02:46 2021 +0530
#
# interactive rebase in progress; onto 2814ed0
# Last commands done (2 commands done):
#    pick b1b37b5 Added boiler plate code
#    squash 125e103 Changing title
# Next commands to do (3 remaining commands):
#    pick c6c03ac Adding navbar list
#    pick 3816fa0 Adding Downloads in navbar list
# You are currently rebasing branch 'master' on '2814ed0'.
#
# Changes to be committed:
#   modified:   index.html
#
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this file you can change the commit message for your final commit i.e commit formed after merging. As mentioned in the instructions, lines starting with &lt;code&gt;#&lt;/code&gt; are going to get ignored, so I am going to comment the &lt;code&gt;Changing title&lt;/code&gt; message and change the &lt;code&gt;Added boiler plate code&lt;/code&gt; to `Added boilerplate and changed title.&lt;/p&gt;

&lt;p&gt;Save and close the file and now do &lt;code&gt;git log&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tada!&lt;/strong&gt; our commits are merged into one and our changes look more meaningful.&lt;/p&gt;

&lt;p&gt;Now try doing the same for &lt;code&gt;Added downloads section&lt;/code&gt; and &lt;code&gt;Added Pricing section&lt;/code&gt; commits.&lt;/p&gt;

</description>
      <category>git</category>
      <category>tutorial</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
