<?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: Saunved</title>
    <description>The latest articles on DEV Community by Saunved (@saunved).</description>
    <link>https://dev.to/saunved</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%2F304017%2F9fc995d7-f66b-4277-a8f5-c34a3ad26ade.jpeg</url>
      <title>DEV Community: Saunved</title>
      <link>https://dev.to/saunved</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/saunved"/>
    <language>en</language>
    <item>
      <title>What the heck is Prototypal Inheritance? Part 1: Object Prototypes</title>
      <dc:creator>Saunved</dc:creator>
      <pubDate>Sat, 02 Jul 2022 10:00:50 +0000</pubDate>
      <link>https://dev.to/saunved/what-the-heck-is-prototypal-inheritance-part-1-object-prototypes-53j1</link>
      <guid>https://dev.to/saunved/what-the-heck-is-prototypal-inheritance-part-1-object-prototypes-53j1</guid>
      <description>&lt;p&gt;&lt;em&gt;Photo by &lt;a href="https://unsplash.com/@holly_buildalifeyoulove?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Holly Stratton&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/stack?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Before you dive in, you should have a decent understanding of &lt;a href="https://www.programiz.com/javascript/object" rel="noopener noreferrer"&gt;Objects&lt;/a&gt; and &lt;a href="https://www.programiz.com/javascript/function" rel="noopener noreferrer"&gt;Functions&lt;/a&gt; in Javascript.&lt;/p&gt;

&lt;p&gt;Prototypes and prototypal inheritance in Javascript can be confusing, especially if you have learned Object Oriented Programming from the perspective of Java or C++.&lt;/p&gt;

&lt;p&gt;These posts aim to clear up some of the confusion, and make prototypal inheritance easier to understand.&lt;/p&gt;




&lt;p&gt;Let's start!&lt;/p&gt;

&lt;p&gt;First off, there are two "kinds" of prototypes in Javascript:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Object prototypes&lt;/li&gt;
&lt;li&gt;Function prototypes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Although they both have similarities, it's best to treat them separately. In this article, we will be looking only at Object Prototypes.&lt;/p&gt;

&lt;p&gt;Some facts I need you to keep in mind while reading this article:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Any data type in Javascript that is not a &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Primitive" rel="noopener noreferrer"&gt;primitive&lt;/a&gt; is an Object&lt;/li&gt;
&lt;li&gt;By extension, functions are technically objects in Javascript, albeit with some extra gimmicks, e.g. you can invoke them. &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions" rel="noopener noreferrer"&gt;MDN reference&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Objects can contain functions as their properties (keys). When functions are part of an object, they are called &lt;em&gt;methods&lt;/em&gt;. Methods &lt;em&gt;act&lt;/em&gt; on an object.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// For example&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Luke&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Hello, I am &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Prints 'Hello, I am Luke'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;em&gt;this&lt;/em&gt; keyword is deliberately not used in the above example to avoid confusion.&lt;/p&gt;

&lt;p&gt;Alright so...&lt;/p&gt;

&lt;h3&gt;
  
  
  What is an object prototype?
&lt;/h3&gt;

&lt;p&gt;Let's create an object:&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;character&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;hearts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you create an object in Javascript, it contains the properties you have defined (in this case &lt;code&gt;character.hearts&lt;/code&gt;). However, this object also has some hidden properties, magically obtained from the Javascript Gods.&lt;/p&gt;

&lt;p&gt;For example, if you were to do &lt;code&gt;character.toString()&lt;/code&gt;, it will print &lt;code&gt;"[object Object]"&lt;/code&gt;.  You didn't define any &lt;code&gt;toString()&lt;/code&gt; method inside &lt;code&gt;character&lt;/code&gt;. So where the heck did it come from?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enter the prototype&lt;/strong&gt;&lt;br&gt;
Follow along with the steps below to explore this interesting phenomenon:&lt;/p&gt;

&lt;p&gt;(1) Open your console (in any browser, I am using Firefox) by pressing F12 &amp;gt; then click on "Console"&lt;br&gt;
(2) Type and enter &lt;code&gt;window.Object.prototype&lt;/code&gt;. It looks 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%2Fajb88ipueyk72mwoqill.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%2Fajb88ipueyk72mwoqill.png" alt="window.Object.prototype console output"&gt;&lt;/a&gt;&lt;br&gt;
We can see that this is an object with a bunch of predefined properties and methods.&lt;br&gt;
(3) Type &lt;code&gt;const character = {hearts: 1}&lt;/code&gt; and press enter&lt;br&gt;
(4) Type &lt;code&gt;character&lt;/code&gt; and press enter. The output looks 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%2Foei9p0fo87mpihxay4s4.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%2Foei9p0fo87mpihxay4s4.png" alt="character console output"&gt;&lt;/a&gt;&lt;br&gt;
(5) Type &lt;code&gt;character.__proto__&lt;/code&gt; and press enter. The output looks 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%2Fdrwaetu6s33jvvpf1u69.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%2Fdrwaetu6s33jvvpf1u69.png" alt="character.__proto__ console output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Keep the console open, and continue reading.&lt;/p&gt;

&lt;p&gt;Do the objects at steps (2) and (5) look the same to you, despite being a part of different objects? &lt;/p&gt;

&lt;p&gt;Well guess what, &lt;em&gt;they are the same&lt;/em&gt;. And we can prove it.&lt;/p&gt;

&lt;p&gt;Do this:&lt;br&gt;
(1) Enter &lt;code&gt;character.toString()&lt;/code&gt;, and observe the output&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%2Fbexsow3i6g3u9gx49bog.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%2Fbexsow3i6g3u9gx49bog.png" alt="character.toString() console output"&gt;&lt;/a&gt;&lt;br&gt;
(2) Now we will redefine the &lt;code&gt;toString()&lt;/code&gt; the method defined in &lt;code&gt;window.Object.prototype&lt;/code&gt;. Enter this in the console:&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="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Proved it&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;(3) Now, enter &lt;code&gt;character.toString()&lt;/code&gt; again and check the output&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%2Fvrhne1ybv33l0vc2cgbc.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%2Fvrhne1ybv33l0vc2cgbc.png" alt="character.toString() after modification"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You modified a method that was owned by &lt;code&gt;window.Object.prototype&lt;/code&gt; and somehow, like spooky action at a distance, your &lt;code&gt;character.toString()&lt;/code&gt; method's output changed. Crazy stuff right?&lt;/p&gt;

&lt;p&gt;This is a good time to pause and review the steps we performed above.&lt;/p&gt;




&lt;p&gt;Time to understand this whole gimmick in depth.&lt;/p&gt;

&lt;p&gt;All objects contain a &lt;em&gt;prototype property&lt;/em&gt;. This "prototype property" is NOT available at  &lt;code&gt;character.prototype&lt;/code&gt;.  It is, instead, called  &lt;code&gt;__proto__&lt;/code&gt; and is available as &lt;code&gt;character.__proto__&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;The word "prototype" can be confusing. To make things easier to process, you can think of it as "parent" instead. So when you see &lt;code&gt;character.__proto__&lt;/code&gt;, you can think of it as "parent of &lt;code&gt;character&lt;/code&gt;".&lt;/p&gt;

&lt;p&gt;What do you think will be the parent of &lt;code&gt;character.__proto__&lt;/code&gt;?&lt;br&gt;
Well, you can chain these! So you can do: &lt;code&gt;character.__proto__.__proto__&lt;/code&gt;. This time, you will get &lt;code&gt;null&lt;/code&gt;. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;null&lt;/code&gt; is the ultimate ancestor of all Objects.&lt;/p&gt;

&lt;p&gt;Note: &lt;code&gt;__proto__&lt;/code&gt; is not the standard way to access Object prototypes. The standard way is to do &lt;code&gt;Object.getPrototypeOf(obj)&lt;/code&gt;, but things are easier to write, explain, and understand when using &lt;code&gt;__proto__&lt;/code&gt;. Do not use this in production!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The following diagram should help clear a few things up.&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%2Fzv7b2ro4utuaa11rhjr7.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%2Fzv7b2ro4utuaa11rhjr7.png" alt="Prototypal inheritance in Javascript"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see above:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All Objects in Javascript inherently are nothing, denoted by &lt;code&gt;null&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;From this nothingness, arises &lt;em&gt;something&lt;/em&gt; - the most &lt;em&gt;basic object&lt;/em&gt; you can have -- an object with some default properties, e.g. &lt;code&gt;toString()&lt;/code&gt;, &lt;code&gt;valueOf()&lt;/code&gt;. This primal object can be found at &lt;code&gt;window.Object.prototype&lt;/code&gt; and is defined by the browser&lt;/li&gt;
&lt;li&gt;When you create your own object (any object at all, even an empty object), it &lt;em&gt;inherits&lt;/em&gt; the properties of this basic object. &lt;/li&gt;
&lt;li&gt;So if you try to call &lt;code&gt;character.toString()&lt;/code&gt;, Javascript checks if the method exists on the object &lt;code&gt;character&lt;/code&gt;. If not, it &lt;em&gt;drills down&lt;/em&gt; and checks the parent of &lt;code&gt;character&lt;/code&gt;, which in this case is the &lt;code&gt;window.Object.prototype&lt;/code&gt; object.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;According to the Oxford Languages dictionary, the word "prototype" means:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The first model or design of something from which other forms will be developed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's a succinct definition that applies well to the above behavior of prototype. It starts off as nothing and can progressively build up.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>programming</category>
      <category>oop</category>
    </item>
    <item>
      <title>70 lessons from the last year as a developer and co-founder</title>
      <dc:creator>Saunved</dc:creator>
      <pubDate>Fri, 09 Jul 2021 16:01:55 +0000</pubDate>
      <link>https://dev.to/saunved/70-lessons-from-the-last-year-as-a-developer-and-co-founder-5h2h</link>
      <guid>https://dev.to/saunved/70-lessons-from-the-last-year-as-a-developer-and-co-founder-5h2h</guid>
      <description>&lt;p&gt;This time last year, we changed our business model and began partnering with small businesses and startups to create tech solutions for them. &lt;/p&gt;

&lt;p&gt;This is an exhaustive list of things I've learned since then. The process of writing and organizing these helped me process the learnings better, and I hope it helps someone out there too.&lt;/p&gt;

&lt;p&gt;A few of these things might seem like common sense, but I learned them from experience so they had an impact on my behavior or my understanding of my work and life in general.&lt;/p&gt;




&lt;p&gt;Organized by&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Life&lt;/li&gt;
&lt;li&gt;Business&lt;/li&gt;
&lt;li&gt;Tech and UX&lt;/li&gt;
&lt;li&gt;Tech for everyone&lt;/li&gt;
&lt;li&gt;Tech for developers&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Life
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Communication is crucial for your survival in any profession. Just talk to people you're working with (or for) about your tasks. Drop them a message once a day at least and keep them in the loop, especially if you're going to be late with something.&lt;/li&gt;
&lt;li&gt;Most difficult problems are solved when you periodically step away and do something else for a bit.&lt;/li&gt;
&lt;li&gt;Coffee is your friend as long as it doesn't mess with your sleep cycle&lt;/li&gt;
&lt;li&gt;Writing your own tasks down on paper and crossing them out is more efficient and rewarding than any online tool.&lt;/li&gt;
&lt;li&gt;Walk around the house if you're on a phone call. It helps keep you active.&lt;/li&gt;
&lt;li&gt;Spending some time every day looking at trees and plants is very soothing.&lt;/li&gt;
&lt;li&gt;Hugging your pets at random intervals during the day is a free dose of happiness.&lt;/li&gt;
&lt;li&gt;An 18-minute nap in the afternoon does wonders for productivity&lt;/li&gt;
&lt;li&gt;Time tracking (using a tool like Toggl) for personal analysis is very useful. You begin to learn how you spend or waste time and even understand how to estimate time for tasks correctly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Business
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Making an app or website for someone doesn't guarantee them sales, and convincing them otherwise can lead to very difficult conversations about their business model.&lt;/li&gt;
&lt;li&gt;More effort doesn't equal more reward. Pick your work wisely.&lt;/li&gt;
&lt;li&gt;Getting your personal, relationship, and business goals to align will take a toll on your mental health. It's best to process this in a healthy way. Talking to someone, writing about it, or simply being aware of what's causing you to feel a certain way helps a lot.&lt;/li&gt;
&lt;li&gt;If you can write well in at least one language, you can usually do well in any desk job. If you don't write well, start practicing. If you can't write well, focus on calling people and talking more on the phone. Either way, communicate.&lt;/li&gt;
&lt;li&gt;Running a startup means dealing with the fear of failure and doubt every day. That's okay. It can get better as long as you learn from it and communicate with your cofounders.&lt;/li&gt;
&lt;li&gt;Lesser-paying contracts can sometimes give way more happiness than higher-paying ones. Who your customer or client is matters a lot.&lt;/li&gt;
&lt;li&gt;A good designer can do wonders for your product. Don't hesitate to hire designers even if you are "decent" at design.&lt;/li&gt;
&lt;li&gt;Always get written contracts before starting any work. Verbal contracts and handshake contracts leave room for miscommunication.&lt;/li&gt;
&lt;li&gt;Always tell the truth about timelines. If something is going to take 8 weeks, don't say you can do it in 4 weeks.&lt;/li&gt;
&lt;li&gt;Always take an advance before starting any project. Decide your amount. For large contracts, 10% can be okay. For small contracts, 50% is good, but always take an advance.&lt;/li&gt;
&lt;li&gt;Adapt to the client's style of communication instead of forcing them to use a particular app or website. If your client likes email, use email. If they like Whatsapp, use Whatsapp. You'll just speed things up for yourself down the line.&lt;/li&gt;
&lt;li&gt;UI is what you interact with. UX is how you feel after you interact with it. The thinking processes involved in both are vastly different. Try NOT to use these terms interchangeably because they mean different things.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tech and UX
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Encourage designers/yourself to make designs for mobile-first (especially for websites). It's always easier to expand from a place of constraint than to contract design from a large space.&lt;/li&gt;
&lt;li&gt;Menu buttons should ideally be labeled "Menu" if they contain important links that cannot be found with other actions&lt;/li&gt;
&lt;li&gt;Users forget their passwords. Allow them to sign in through magic links too.&lt;/li&gt;
&lt;li&gt;Fall into the habit of writing user feedback loops. Basically, if the user does something, open a toast telling them that it's done. A simple "Data updated" toast builds trust with your system.&lt;/li&gt;
&lt;li&gt;Fall into the habit of adding loaders wherever network calls are made. It's super annoying to press a button and have nothing happen for 1 second. I have seen plenty of reputed websites that somehow think it's okay to do this.&lt;/li&gt;
&lt;li&gt;If an error occurs on a user action, NEVER show it as a disappearing toast. Make it persist on the screen until the user manually clears the error&lt;/li&gt;
&lt;li&gt;Don't use words like "Cancel" in a dialog box. Use "Back" instead. "Back" is comforting, it's a casual escape. "Cancel" is ambiguous and brings an alarming feeling, as if the user is doing something wrong.&lt;/li&gt;
&lt;li&gt;Always use the combination of "Sign in" and "Register". Never use "Sign in" + "Sign Up" or "log in" + "sign up". It's not easy on the eyes&lt;/li&gt;
&lt;li&gt;Have separate forms for registration and signing in, preferably on separate pages instead of in modals (for SEO purposes)&lt;/li&gt;
&lt;li&gt;Keep an easily accessible "Feedback" button in your application so users can report bugs and issues &lt;/li&gt;
&lt;li&gt;Well-tested user interfaces require fewer updates and are a joy to use even if they don't "look" great&lt;/li&gt;
&lt;li&gt;Always make sure your site has a navbar and a footer, otherwise it looks "naked"&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tech for everyone
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Never buy hosting from GoDaddy. Use DigitalOcean or Vercel or Vultr&lt;/li&gt;
&lt;li&gt;Buy domains from Google or Namecheap.&lt;/li&gt;
&lt;li&gt;Web apps are not worth the hype until Apple decides to adopt and support them properly. You will still need an "app" to give an app-like experience with push notifications and other permissions on iOS.&lt;/li&gt;
&lt;li&gt;The largest delays in development and testing times are caused by third-party dependencies (e.g. payment gateways, email delivery services, etc.). Make sure you have all the documentation, approvals, and data formats available before the developers start coding anything.&lt;/li&gt;
&lt;li&gt;Live streaming is complicated, especially if there is an authentication layer associated with the stream. The most affordable custom live-streaming services I've found are OneStream, LivePush, and Castr.&lt;/li&gt;
&lt;li&gt;WordPress is still better than about 95% of the new content management systems out there (for general use cases of course).&lt;/li&gt;
&lt;li&gt;Strapi is a decent choice for a custom CMS, but it is by no means bug-free, especially when it comes to nested queries in GraphQL or renaming collections, or developing locally. Look for lighter alternatives before you get here.&lt;/li&gt;
&lt;li&gt;When most people say "AI", they usually mean "ML". When most people say "ML", they usually mean dynamic output based on user-input (which is basically a bunch of "if-else" statements).&lt;/li&gt;
&lt;li&gt;The concept of a blockchain is great, but 99% of the things you want to use blockchains for don't need a blockchain in the first place.&lt;/li&gt;
&lt;li&gt;No-code is a dangerous buzzword. If you want to do anything even slightly different (which is most things when you get into the details), you have to use code.&lt;/li&gt;
&lt;li&gt;After spending a copious amount of time convincing myself that NFTs are actually useful, I have concluded that they are worthless and anybody telling you otherwise just wants to make quick money and disappear.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tech for developers
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Bundle your "admin" frontend with your normal user-side code. Creating a separate project means you probably won't maintain it properly.&lt;/li&gt;
&lt;li&gt;Brand new frameworks and libraries will fail you by virtue of being less tested or documented. Test them out in a sandbox for your use case first.&lt;/li&gt;
&lt;li&gt;Authentication on the web is a rabbit hole. Use cookies set by the server with httpOnly if you're confused.&lt;/li&gt;
&lt;li&gt;The Safari browser is the new Internet Explorer (at least for developers) due to poor support for modern CSS and JS features.&lt;/li&gt;
&lt;li&gt;The AWS documentation and UX needs a massive revamp. Also, avoid using AWS if you can.&lt;/li&gt;
&lt;li&gt;Utility frameworks (like Tailwind) are surprisingly good, but it's okay if you don't like them. Each to his/her own.&lt;/li&gt;
&lt;li&gt;The command line is a beautiful gift and you should definitely use it more if you don't already. Try it out for common tasks, stick to it for a few days, you won't feel like giving up the convenience.&lt;/li&gt;
&lt;li&gt;It helps to know at least one frontend framework, one backend framework, and one database. You'll be able to associate other "new" things with the existing ones if you need to later on.&lt;/li&gt;
&lt;li&gt;You "know" a framework when you deploy at least two projects to production and maintain them for a few months with 100+ monthly active users.&lt;/li&gt;
&lt;li&gt;If you don't want to stress out about there being a bug in your production, then, well... don't stress out about it. If there's a bug, it'll be reported eventually, and you will fix it eventually. Worry about it then.&lt;/li&gt;
&lt;li&gt;Most new bugs are introduced when fixing old bugs in a hurry. So test thoroughly and save yourself time later on.&lt;/li&gt;
&lt;li&gt;Backups. Always. Have. Backups. Especially if you're not quick on your feet. Doesn't matter where you are, who you are. Make it a part of your thinking process. Also, know how to restore those backups. Backups are restored rarely, but also in time-critical situations. So keep the steps written down somewhere you can find them later on.&lt;/li&gt;
&lt;li&gt;Serverless doesn't seem to be the future because of database, job scheduling, and management constraints.&lt;/li&gt;
&lt;li&gt;Coding slowly allows you to finish tasks faster than coding "fast" which just causes issues to crop up later and consumes more time overall.&lt;/li&gt;
&lt;li&gt;The less code you have in your codebase, the easier it will be to debug.&lt;/li&gt;
&lt;li&gt;Don't start coding a new module until you have a bird's eye view and the next 3 steps you're going to take and you fully understand the side effects they will have on the existing system.&lt;/li&gt;
&lt;li&gt;Note down crucial decisions in a README that is version controlled and update it every time you have discussions. We've tried saving crucial decisions in emails, in Confluence, in ClickUp, on Jira. None of these things work. Keep the decisions with your code. They will always be accessible.&lt;/li&gt;
&lt;li&gt;Try to figure out what's different between your development, staging, and production environments to avoid issues with deployments.&lt;/li&gt;
&lt;li&gt;Set release cycles for your products. E.g. every alternate Wednesday. Never deploy immediately before a vacation or a weekend.&lt;/li&gt;
&lt;li&gt;Replicate the prod database locally to test things out in a "real way"&lt;/li&gt;
&lt;li&gt;If you're coding in a hurry, you'll end up sacrificing on security since it's easy to overlook. Make sure you come back to do a security check later&lt;/li&gt;
&lt;li&gt;End-to-end encryption is complicated and causes lots of user experience issues, backup and restore issues, and maintenance headaches in general. If you don't need end-to-end encryption, don't use it.&lt;/li&gt;
&lt;li&gt;Don't buy SSL certificates unless there's a very good reason to do so. Free Let's Encrypt certificates are enough for most use cases.&lt;/li&gt;
&lt;li&gt;All frontend frameworks are pretty much similar in performance. Use what's convenient and what works for you.&lt;/li&gt;
&lt;li&gt;Event-based systems are easier to handle than implicit update systems (e.g. computed properties in Vue). Emit and consume events wherever possible to make your system easier to trace, predict, and debug. This is very useful with complex systems where computed or watched properties can end up in infinite loops.&lt;/li&gt;
&lt;li&gt;Debouncing is very useful when dealing with scroll effects or multiple simultaneous event updates. It allows the interface to update while delaying the execution of the tasks by a reasonable time.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;I know this was a long read! Feel free to leave your thoughts on the list, especially if you strongly agree or disagree with something.&lt;/p&gt;

</description>
      <category>knowledge</category>
      <category>devjournal</category>
    </item>
    <item>
      <title>How to add Supabase to Nuxt.js</title>
      <dc:creator>Saunved</dc:creator>
      <pubDate>Sun, 02 May 2021 11:36:34 +0000</pubDate>
      <link>https://dev.to/saunved/how-to-add-supabase-to-nuxt-js-2bgb</link>
      <guid>https://dev.to/saunved/how-to-add-supabase-to-nuxt-js-2bgb</guid>
      <description>&lt;p&gt;Yesterday, I tried Supabase for the first time. Within about 30 minutes, I had social login and password-based authentication set up. There was almost zero friction during the whole process and I was super impressed, especially after my horrible developer experience with AWS Cognito and Amplify Auth.&lt;/p&gt;

&lt;p&gt;This is a quick guide on how you can add Supabase to a Nuxt.js application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;(1) You have a Nuxt.js application created using &lt;em&gt;npx create-nuxt-app&lt;/em&gt; or through another method&lt;br&gt;
(2) You have created a Supabase project and the Supabase key, Supabase URL&lt;/p&gt;
&lt;h2&gt;
  
  
  How to add Supabase to Nuxt
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;(1) Install Supabase&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;yarn add @supabase/supabase-js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(2) Add Supabase to plugins&lt;/strong&gt;&lt;br&gt;
In the plugins folder&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a file

&lt;code&gt;supabase.client.js&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;ul&gt;
&lt;li&gt;Add the following code snippet (replace the key, url with your own)
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@supabase/supabase-js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SUPABASE_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;YOUR-KEY&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="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="nx"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;supabaseUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;YOUR-URL&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;supabaseKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;SUPABASE_KEY&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;supabaseUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;supabaseKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nx"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;supabase&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This will inject Supabase to our Nuxt project, and will be available as &lt;em&gt;this.$supabase&lt;/em&gt; for us to use&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(3) Add the plugins file to nuxt.config.js&lt;/strong&gt;&lt;br&gt;
In nuxt.config.js, add the following to plugins&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;// ...&lt;/span&gt;
  &lt;span class="nx"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/plugins/supabase.client.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also use the alternative syntax&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;// ...&lt;/span&gt;
  &lt;span class="nx"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/plugins/supabase.client.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;ssr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;(4) Use Supabase on any page&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="c1"&gt;//...&lt;/span&gt;
&lt;span class="nx"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;signIn&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signIn&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it!&lt;/p&gt;




&lt;p&gt;I'm really excited to see where &lt;a class="mentioned-user" href="https://dev.to/supabase_io"&gt;@supabase_io&lt;/a&gt; goes in the coming weeks and months! I hope it keeps growing and adding more useful features.&lt;/p&gt;

</description>
      <category>supabase</category>
      <category>nuxt</category>
      <category>firebase</category>
    </item>
    <item>
      <title>isfastnet: a tiny script to find out if your user's internet is fast or slow</title>
      <dc:creator>Saunved</dc:creator>
      <pubDate>Sun, 15 Nov 2020 15:01:50 +0000</pubDate>
      <link>https://dev.to/saunved/isfastnet-a-tiny-script-to-find-out-if-your-user-s-internet-is-fast-or-slow-4h84</link>
      <guid>https://dev.to/saunved/isfastnet-a-tiny-script-to-find-out-if-your-user-s-internet-is-fast-or-slow-4h84</guid>
      <description>&lt;p&gt;As web developers, we usually write code on systems with good internet speeds. The bulk of our time is spent with the subconscious assumption that "other people should have similar speeds".&lt;/p&gt;

&lt;p&gt;Many browsers offer network throttling to test how your application will perform on slower network speeds and we do test for these, but we don't particularly worry about it unless our use case calls for it.&lt;/p&gt;

&lt;p&gt;We are working on a food delivery webapp at my company, and being located in India, with some of the most unreliable cellular data, this is a HUGE problem for us. When we run the application on our devices, things work just fine. But on devices with 3G, and devices with poor connectivity, things get a lot worse. Network calls take more than 5s to complete, and that's a massive nightmare for any user.&lt;/p&gt;

&lt;p&gt;So we had a use case. Optimizing for poor internet speeds. The first part of the problem is - can we detect if a user's internet is slow and show them some sort of a message / reduce network calls if that is the case?&lt;/p&gt;

&lt;p&gt;Below, I outline two solutions, and finally a tiny package I made using one of the solutions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can check out the demo page &lt;a href="https://saunved.github.io/isfastnet" rel="noopener noreferrer"&gt;here&lt;/a&gt; and if you want to test it out, you can download the package directly from npm and start using it: &lt;br&gt;
&lt;a href="https://www.npmjs.com/package/isfastnet" rel="noopener noreferrer"&gt;npm link&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;The Network Information API&lt;/strong&gt;&lt;br&gt;
Easily the best and most useful solution. An API that can tell you exactly how good your user's internet speed is. The problem?&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%2Fi%2Fxiwc6ec0854o9icb8hmm.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%2Fi%2Fxiwc6ec0854o9icb8hmm.png" alt="Network Information API CanIUse"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Partial support on Chromium browsers and no support on Safari and Firefox.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Client-side solutions&lt;/strong&gt;&lt;br&gt;
As any sane developer would do, I looked up the problem on Stack Overflow. This is one of the most popular questions on the topic: &lt;a href="https://stackoverflow.com/questions/5529718/how-to-detect-internet-speed-in-javascript" rel="noopener noreferrer"&gt;Stack Overflow post&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The most upvoted and "marked as correct" answer suggests downloading a large image and checking the total time it takes, and dividing the size of the image by the time taken to determine speed. That does answer the question correctly - but in a real system, it might not be the most pragmatic approach.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If a user's internet is already slow, do you really want to download a large image to check &lt;em&gt;how slow&lt;/em&gt; it really is?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The larger problem at hand is that you cannot periodically check if the user's internet is slow because it will hog bandwidth for already slow networks.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In most cases, we just want to know if our user's internet is fast or slow.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A little below on the same question, you can find &lt;a href="https://stackoverflow.com/a/21372151/6513036" rel="noopener noreferrer"&gt;this answer&lt;/a&gt;. It suggests downloading a very tiny image multiple times, generating the average download speed, and determining if the internet is fast or slow.&lt;/p&gt;

&lt;p&gt;Now we're talking!&lt;/p&gt;

&lt;p&gt;Basically, we can set a "threshold" value. If the image is taking (on average) longer than "threshold" milliseconds to download, then the internet must be slow. Sounds great, and it doesn't hog bandwidth either.&lt;/p&gt;

&lt;p&gt;However, if you test this out in Chrome DevTools, you will see that this test takes more than 10 seconds to end on slow networks. That's too much waiting to find out if the internet is actually slow.&lt;/p&gt;

&lt;p&gt;To get past this issue, one can write a setTimeout inside the recursive function. This setTimeout should force exit the function if the image wasn't downloaded in &lt;strong&gt;threshold*3&lt;/strong&gt; ms. The 3 is arbitrary, but it should work for most cases. So I edited the script to make those changes.&lt;/p&gt;

&lt;p&gt;You can test out how the script works by copy-pasting this and running it with throttling turned on.&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;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/npm/isfastnet"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="nf"&gt;isFastNet&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
         &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Internet is fast&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="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;Internet is slow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
&lt;span class="na"&gt;timesToTest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// optional, number of times to load the image, default is 5&lt;/span&gt;
&lt;span class="na"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// optional, threshold in ms after which internet speed is considered slow&lt;/span&gt;
&lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://www.google.com/images/phd/px.gif&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//  optional, url of the tiny image to load&lt;/span&gt;
&lt;span class="na"&gt;allowEarlyExit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;// optional, if the first request takes greater than threshold*3 ms then the function exits with false&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Fast internet on Wifi&lt;/strong&gt;&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%2Fi%2F6i1x6ue3sv518dh2nfz4.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%2Fi%2F6i1x6ue3sv518dh2nfz4.png" alt="Shows fast internet on Wifi"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Slow internet on throttling&lt;/strong&gt;&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%2Fi%2Fg4vw6l38iyujf9b3oktb.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%2Fi%2Fg4vw6l38iyujf9b3oktb.png" alt="Shows slow internet on throttling"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The project is open source and I am looking for contributors. Feel free to open issues or fork the project!&lt;br&gt;
&lt;a href="https://github.com/Saunved/isfastnet" rel="noopener noreferrer"&gt;Github&lt;/a&gt; / &lt;a href="https://www.npmjs.com/package/isfastnet" rel="noopener noreferrer"&gt;npm link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And do leave a "star" if this helps you :)&lt;br&gt;
The stars have no real value, but they make me happy!&lt;/p&gt;

</description>
      <category>network</category>
      <category>speed</category>
      <category>javascript</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Vue and Nuxt tips for everyone</title>
      <dc:creator>Saunved</dc:creator>
      <pubDate>Wed, 04 Nov 2020 09:03:00 +0000</pubDate>
      <link>https://dev.to/saunved/vue-and-nuxt-tips-for-everyone-1a8a</link>
      <guid>https://dev.to/saunved/vue-and-nuxt-tips-for-everyone-1a8a</guid>
      <description>&lt;p&gt;I started playing with Vue in June of this year and got into Nuxt within a few weeks. These are general tips that should help both beginners and slightly more experienced developers. I've tried to link the tips to the relevant part of the Vue / Nuxt docs.&lt;br&gt;
Please feel free to add more tips in the comments!&lt;/p&gt;
&lt;h2&gt;
  
  
  General Vue tips
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Pass data using props from parent to child components&lt;/strong&gt;&lt;br&gt;
One of the first things you'll learn is that parent-child data-binding is &lt;em&gt;not&lt;/em&gt; two-way and any changes you make to data inside the child component will either throw a warning (or error if using Vuex the wrong way) and result in some massive confusion. So use &lt;a href="https://vuejs.org/v2/guide/components-props.html#One-Way-Data-Flow"&gt;props&lt;/a&gt; instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Always emit events to pass events + data from the child to parent components&lt;/strong&gt;&lt;br&gt;
Child components talk to the parent using events. That's how you can propagate clicks, inputs, as well as data back to the parent if required. &lt;a href="https://vuejs.org/v2/guide/components.html#Listening-to-Child-Components-Events"&gt;Vue docs link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Use the .sync modifier for two-way data binding between parent and child&lt;/strong&gt;&lt;br&gt;
Well, yeah - you can technically have two-way data binding between parent and child components. Good use cases for this would be to open or close modals using just one variable synced between the parent and child. The &lt;a href="https://vuejs.org/v2/guide/components-custom-events.html#sync-Modifier"&gt;.sync modifier&lt;/a&gt; to your rescue. You can find many instances of this used in &lt;a href="https://buefy.org/documentation/modal"&gt;Buefy&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Use v-key to force reload a component's state&lt;/strong&gt;&lt;br&gt;
Due to how Vue's reactivity works, you might end up in a situation where you want to reload a component so that it shows the latest data available instead of some previous data. There are some awesome articles online about how to do this. One of the best ways, is to use the v-key attribute.&lt;/p&gt;

&lt;p&gt;This is especially useful when your data is deeply nested or schema-less and Vue is not "reactive" to it.&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;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;some-component&lt;/span&gt; &lt;span class="na"&gt;:data=&lt;/span&gt;&lt;span class="s"&gt;"someData"&lt;/span&gt; &lt;span class="na"&gt;:key=&lt;/span&gt;&lt;span class="s"&gt;"reloadKey"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/some-component&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;someData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
      &lt;span class="na"&gt;reloadKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="c1"&gt;// Imagine this method is called by some external JS &lt;/span&gt;
&lt;span class="c1"&gt;// in the callback and now the data needs to be reflected &lt;/span&gt;
&lt;span class="c1"&gt;// in the component&lt;/span&gt;
    &lt;span class="nx"&gt;someCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;someData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reloadKey&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://michaelnthiessen.com/force-re-render/"&gt;The article where I learned this from.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Use computed properties to access Vuex stores&lt;/strong&gt;&lt;br&gt;
Instead of writing long and arduous lines of text whenever dealing with Vuex, simply use computed properties to get the data instead.&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;computed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;projects&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;projects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&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;And you can simply use these as &lt;strong&gt;this.users&lt;/strong&gt; or &lt;strong&gt;this.projects&lt;/strong&gt; like you normally would for data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Use vuex-persist or localforage to persist data across browser reloads / closes&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://www.npmjs.com/package/vuex-persist"&gt;vuex-persist&lt;/a&gt; lets you keep your Vuex store data on browser reloads (acting as a cache of sorts). It also has a localforage option that lets you persist data to IndexedDB using &lt;a href="https://www.npmjs.com/package/localforage"&gt;localforage&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. Use the built-in transition tag&lt;/strong&gt;&lt;br&gt;
Vue has &lt;a href="https://vuejs.org/v2/guide/transitions.html"&gt;really good transition support&lt;/a&gt;. Before you try out a custom solution, play with the transition system that Vue gives you out of the box (along with a library like &lt;a href="https://animate.style/"&gt;animate.css&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. Don't create components for every little thing&lt;/strong&gt;&lt;br&gt;
This is more of an opinion rather than a tip.&lt;br&gt;
Vue's component system is really nice and it's super tempting to create components for every "standalone block" of code you find, but DRY is only useful when you are actually repeating yourself. If the "component" you are making is only going to be present in one place...don't make it a component.&lt;/p&gt;

&lt;h2&gt;
  
  
  General Nuxt tips
&lt;/h2&gt;

&lt;p&gt;I absolutely love Nuxt. It handles routing out of the box, provides a flexible but effective structure to a project, lets you generate SSR as well as static sites, and comes with a lot of good support from the community.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. nuxt.config.js is awesome&lt;/strong&gt;&lt;br&gt;
The nuxt.config.js file can do A LOT of things. Read the docs to understand its uses properly first before trying any configurations independently&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Understand Nuxt routing&lt;/strong&gt;&lt;br&gt;
Nuxt routing with pages &amp;gt; route-name.vue is quite easy to understand, but there are ways to extend routes using your own data too. Check out &lt;a href="https://nuxtjs.org/docs/2.x/configuration-glossary/configuration-router#extendroutes"&gt;this Nuxt doc page&lt;/a&gt;. Psst... the configuration is done in nuxt.config.js!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. The base template&lt;/strong&gt;&lt;br&gt;
Nuxt loads all your layouts+pages into a file called app.template.html (look for it in .nuxt &amp;gt; views). You can override this file (e.g. to add Netlify forms which are populated before the build step) by adding an app.html file to the root folder. You can basically copy .nuxt &amp;gt; views &amp;gt; app.template.html, paste it as app.html to the &lt;strong&gt;root&lt;/strong&gt; of your project, and edit it to add anything that you want to load to the project irrespective of the application state. &lt;a href="https://nuxtjs.org/docs/2.x/directory-structure/store"&gt;Nuxt doc link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Understand the various Nuxt folders&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;layouts&lt;/strong&gt;&lt;br&gt;
Layouts are the high-level templates of your pages. You can use this to create unique user experiences, or optimize data fetching by layout. &lt;a href="https://nuxtjs.org/docs/2.x/concepts/views"&gt;Read this Nuxt doc&lt;/a&gt; to understand how Nuxt views are structured.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;plugins&lt;/strong&gt;&lt;br&gt;
The plugins folder allows you to load JS code into the application globally. You can use this to create anything from global axios error handlers to adding persistence to your vuex store to loading any libraries that you require across the application. &lt;a href="https://nuxtjs.org/docs/2.x/directory-structure/plugins"&gt;Nuxt docs link&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;middleware&lt;/strong&gt;&lt;br&gt;
The middleware folder is used to store code that runs before a page is loaded. Use it to add auth guards, redirects, etc. You can add middleware to nuxt.config.js, or to any layout or to any page.  &lt;a href="https://nuxtjs.org/docs/2.x/directory-structure/middleware"&gt;Nuxt doc link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;store&lt;/strong&gt;&lt;br&gt;
The “store” folder requires an index.js file to be enabled. It allows you to use vuex stores across your application. You can create a separate js file for each store with each file containing its own mutations, getters, etc. &lt;a href="https://nuxtjs.org/docs/2.x/directory-structure/store"&gt;Nuxt doc link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These are some of the most used folders. There are other folders which you can read about in the &lt;a href="https://nuxtjs.org/docs/2.x/directory-structure/nuxt"&gt;directory structure&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. this.$nuxt.$emit is awesome&lt;/strong&gt;&lt;br&gt;
Sometimes you need to emit an event from (say) a layout or a plugin and listen to it on certain pages. Think of scroll handlers, websocket pings, or error handling from global plugins. The usual parent-child event passing paradigm doesn't apply here. In this case, you can use the event bus that Nuxt injects into Vue during initialization.&lt;/p&gt;

&lt;p&gt;Pass events from anywhere to anywhere else using &lt;strong&gt;this.$nuxt.$emit('event', data)&lt;/strong&gt; and listen to these like &lt;strong&gt;this.$nuxt.$on('event', this.doSomething)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/@aneesshameed/event-bus-in-nuxt-7728315e81b6"&gt;This article explains more.&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;So yeah, that's about it. I would love to read more tips in the comments from other Vue/Nuxt developers! Also feel free to correct me if I've made an error somewhere :)&lt;/p&gt;

</description>
      <category>vue</category>
      <category>nuxt</category>
    </item>
    <item>
      <title>How to add an SSH key to an existing DigitalOcean droplet</title>
      <dc:creator>Saunved</dc:creator>
      <pubDate>Wed, 02 Sep 2020 14:10:21 +0000</pubDate>
      <link>https://dev.to/saunved/how-to-add-an-ssh-key-to-an-existing-digitalocean-droplet-2mob</link>
      <guid>https://dev.to/saunved/how-to-add-an-ssh-key-to-an-existing-digitalocean-droplet-2mob</guid>
      <description>&lt;p&gt;This is a quick and easy method to &lt;strong&gt;add the SSH key of your current machine to an existing droplet.&lt;/strong&gt;&lt;br&gt;
This tutorial is written for Linux users, but you can map the terminal commands to Windows or MacOS commands easily.&lt;/p&gt;


&lt;h3&gt;
  
  
  (1) Retrieve and save your current &lt;strong&gt;public&lt;/strong&gt; key to a text file
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;(a) Generate keypair&lt;/strong&gt; (OPTIONAL)&lt;br&gt;
&lt;strong&gt;In case your RSA keypair is not generated yet&lt;/strong&gt; or you want to generate new keys, simply enter this and follow the instructions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; rsa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;(b) Save SSH key to a separate file&lt;/strong&gt;&lt;br&gt;
Enter the following commands in your terminal:&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;cd&lt;/span&gt; ~
&lt;span class="nb"&gt;cat&lt;/span&gt; ~/.ssh/id_rsa.pub &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; key.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  (2) Upload the SSH key to a file sharing service
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://bashupload.com/key.txt &lt;span class="nt"&gt;--data-binary&lt;/span&gt; @key.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will give you a link that you can use to download the key. Copy the link and keep it somewhere safe. &lt;/p&gt;

&lt;h3&gt;
  
  
  (3) Reset your droplet's password
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;(a) Reset droplet password&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you don't have your droplet's password (which will be the case if you kept SSH as the default access mechanism) then you can reset it.&lt;/p&gt;

&lt;p&gt;Sign in to DigitalOcean &amp;gt; Open the droplet &amp;gt; Click Access &amp;gt; Reset root password&lt;/p&gt;

&lt;p&gt;Your password will be mailed to you. Keep the email open so you can look at the password and type it in on the next step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(b) Set a new password&lt;/strong&gt;&lt;br&gt;
Click on "Console" on the top right to open the droplet's console. Enter "root" in the terminal, and then carefully type in the password specified in the email. The DigitalOcean console does not allow you to copy-paste so this operation is a little annoying.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Follow the instructions in the terminal to set a new UNIX password (and keep this password somewhere safe).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  (4) Add SSH key to droplet
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;(a) Run commands as specific user&lt;/strong&gt; (OPTIONAL)&lt;br&gt;
If you want to add the SSH key for a specific user, you will have to type in the following to execute commands as that user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;su - &amp;lt;username&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;(b) Append SSH key to droplet&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You will need the link obtained in &lt;strong&gt;Step 2&lt;/strong&gt; now.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/.ssh
wget &amp;lt;link-from-step-2&amp;gt;
&lt;span class="nb"&gt;cat &lt;/span&gt;key.txt &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; authorized_keys
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure you use &lt;strong&gt;&amp;gt;&amp;gt;&lt;/strong&gt; so the new key is appended to the authorized_keys file.&lt;/p&gt;




&lt;p&gt;You can now open your terminal and type in&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &amp;lt;user&amp;gt;@&amp;lt;ip&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and you should be able to access your DigitalOcean droplet normally.&lt;/p&gt;




&lt;p&gt;I faced this issue because I switched to a new laptop recently and forgot to add the new key using the old laptop. It's even more annoying because I have like 7 droplets running on DigitalOcean and I have to do these steps for all of them. C'est la vie!&lt;/p&gt;

</description>
      <category>ssh</category>
      <category>digitalocean</category>
      <category>tutorial</category>
      <category>droplet</category>
    </item>
    <item>
      <title>lemme-know: a server monitor that lets you know when your websites are down</title>
      <dc:creator>Saunved</dc:creator>
      <pubDate>Thu, 11 Jun 2020 14:49:39 +0000</pubDate>
      <link>https://dev.to/saunved/lemme-know-a-server-monitor-that-lets-you-know-when-your-websites-are-down-154o</link>
      <guid>https://dev.to/saunved/lemme-know-a-server-monitor-that-lets-you-know-when-your-websites-are-down-154o</guid>
      <description>&lt;h2&gt;
  
  
  Table of contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Stuff nobody will read&lt;/li&gt;
&lt;li&gt;Installation&lt;/li&gt;
&lt;li&gt;
Usage

&lt;ul&gt;
&lt;li&gt;Run locally&lt;/li&gt;
&lt;li&gt;Receive emails&lt;/li&gt;
&lt;li&gt;Change the frequency of tracking&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;More information&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;I started freelancing as a web developer last year. When people talk about web development, it is usually a lot about how to gather requirements from clients, how to code, how to make good websites, etc.&lt;/p&gt;

&lt;p&gt;But what happens post delivery is not discussed as much, especially if you are a solo developer making relatively low traffic websites.&lt;/p&gt;

&lt;p&gt;Well, bad things can happen post-delivery.&lt;br&gt;
Sites go down, SSL certificates expire, domains expire, plugins become outdated, libraries get major updates, or your host obliterates your server during a regular maintenance... Phew!&lt;/p&gt;

&lt;p&gt;If you have 1 website, you can open it in a browser to test if it is online. But when you're taking care of 10 websites or you have to keep track of microservices, you quickly run into issues. Plus, how long can you even stay up and test if your site is up?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/LTYT5GTIiAMBa/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/LTYT5GTIiAMBa/giphy.gif" alt="So sleepy" width="200" height="132"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's not fun to get calls from clients telling you that their site is down. To solve this "site is down" issue, I made "lemme-know". It's a CLI tool that can run locally as well as in the cloud and uses nodemailer to send emails.&lt;/p&gt;

&lt;p&gt;Yes, there are plenty of sophisticated monitoring tools out there, but I wanted something minimal with no frills. No complex dashboards, no visitor tracking, nothing. It's a simple script that sends you an email (or a notification) if your site is down and it's free.&lt;/p&gt;

&lt;p&gt;A CLI tool that lets you do this per website, called &lt;a href="https://www.npmjs.com/package/is-up"&gt;is-up&lt;/a&gt; already exists. &lt;strong&gt;lemme-know consumes the is-up API and extends it&lt;/strong&gt; to monitor multiple sites and send emails if one is down.&lt;/p&gt;

&lt;p&gt;Let's dig in!&lt;/p&gt;
&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;Make sure you have the latest stable version of Node.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i lemme-know &lt;span class="nt"&gt;-g&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;p&gt;Your list of websites and email settings are supplied via a json file. Feel free to copy the file below and edit it:&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;"websites"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"https://test.example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"http://example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"http://another.example.com"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"mail"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"host"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"smtp.example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//could&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;smtp.gmail.com&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"port"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;587&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"secure"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"auth"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"you@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;could&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;your&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;gmail&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;username&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"pass"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"supersecretstuff"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;could&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;your&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;gmail&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;password&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"subject"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Website(s) may be down!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"sender"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"you@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"receiver"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"you@example.com, yourdev@example.com"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You might have to add an app password to Google to run this on a server. Basically Google generates a different password for your account. Just follow the first step over &lt;a href="https://support.google.com/domains/answer/9437157?hl=en"&gt;here&lt;/a&gt; if you need to.&lt;/p&gt;

&lt;h3&gt;
  
  
  Run locally
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lemme-know settings.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You won't receive any emails in this mode. You'll be able to see the status of your websites directly in the terminal like this:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--x2KTXfOy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/px2v0xh2iitgwoyjl1nh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--x2KTXfOy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/px2v0xh2iitgwoyjl1nh.png" alt="Screenshot of output" width="596" height="213"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Stay informed via email
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lemme-know &lt;span class="nt"&gt;-e&lt;/span&gt; settings.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--10nlX7Rj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/spvm8zsbkkytja4fj16t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--10nlX7Rj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/spvm8zsbkkytja4fj16t.png" alt="Screenshot from Gmail" width="579" height="229"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The -e flag asks lemme-know to send an email&lt;br&gt;
You can use the "-s" flag to run lemme-know in silent mode&lt;br&gt;
If you are running this on a server, you might want to use "screen" to keep the process running even if you logout of the session. You can &lt;a href="https://www.ostechnix.com/4-ways-keep-command-running-log-ssh-session/"&gt;refer to this article&lt;/a&gt; to learn how you can do that.&lt;br&gt;
If you want to kill the process, just find and use the process ID:&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;kill&lt;/span&gt; &lt;span class="nt"&gt;-9&lt;/span&gt; &amp;lt;pid&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I suggest using Gmail SMTP. Gmail has a generous email sending limit. You could create a new Gmail account for the sole purpose of doing this if you want. That way you don't compromise on security. You are free to use any service you have available, of course. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you just want to test if the email part works, you can run the code in test mode instead.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lemme-know &lt;span class="nt"&gt;--test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will output a preview URL where you can see the email that would have been sent to you if a site was down.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WTDyCuIP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6w89p0ng382u974cu28r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WTDyCuIP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6w89p0ng382u974cu28r.png" alt="Example email screenshot" width="501" height="225"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important note&lt;/strong&gt;: I have not tested this on Windows. Feel free to open an issue on Github or open a PR to support Windows.&lt;/p&gt;
&lt;h3&gt;
  
  
  Change the frequency
&lt;/h3&gt;

&lt;p&gt;By default, lemme-know checks every 30 minutes if a site is down. That should work for most low traffic websites.&lt;/p&gt;

&lt;p&gt;However, if you need to up the frequency of checks, you can do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lemme-know &lt;span class="nt"&gt;-es&lt;/span&gt; settings.json &lt;span class="nt"&gt;-r&lt;/span&gt; 10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The -r flag sets the time in minutes between checks. Now the check will happen every 10 minutes.&lt;/p&gt;

&lt;h1&gt;
  
  
  More information
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;This tool is not intended for high traffic websites.&lt;/strong&gt; It's intended for freelancers or small agencies who are managing low traffic websites.&lt;/p&gt;

&lt;p&gt;I also highly suggest that you don't ping websites you don't own. Most good sites have DoS checks in place and your IP will get blacklisted.&lt;/p&gt;

&lt;p&gt;If your site has DoS checks in place then whitelist the IP you are running the tool on. You can then increase the frequency too.&lt;/p&gt;

&lt;h3&gt;
  
  
  What if your monitoring server goes down?
&lt;/h3&gt;

&lt;p&gt;It's probably the first thing you think of after you go through the post. To tackle this problem, we &lt;em&gt;could&lt;/em&gt; work on a distributed lemme-know. Basically, you could setup a chain of fallback servers in case the primary monitoring server goes down. If the primary server fails, the 2nd in the chain gets activated. If the 2nd one fails, the third server gets activated, and so on.&lt;/p&gt;

&lt;p&gt;The cool part about this is that you can make any of your existing servers run lemme-know in the background. No need to spin up extra servers for this.&lt;/p&gt;

&lt;h3&gt;
  
  
  What next?
&lt;/h3&gt;

&lt;p&gt;The tool currently works on Linux and I haven't tested it on Windows (or Windows servers for that matter).&lt;/p&gt;

&lt;p&gt;There most definitely are bugs lurking around. This is just an alpha version. Feel free to fork the code and make it better.&lt;/p&gt;

&lt;p&gt;Enjoyed the article? High five!&lt;br&gt;
&lt;a href="https://i.giphy.com/media/fm4WhPMzu9hRK/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/fm4WhPMzu9hRK/giphy.gif" alt="High five" width="250" height="141"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or you could, you know, drop me a star on Github.&lt;br&gt;
Check out the Github repo &lt;a href="https://github.com/Saunved/lemme-know"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>server</category>
      <category>monitor</category>
      <category>backend</category>
      <category>tracker</category>
    </item>
    <item>
      <title>Supporting HTML tags, components, and IDs to create CSS grids in the CLI</title>
      <dc:creator>Saunved</dc:creator>
      <pubDate>Mon, 01 Jun 2020 10:25:16 +0000</pubDate>
      <link>https://dev.to/saunved/updates-to-get-grid-and-its-query-format-4n29</link>
      <guid>https://dev.to/saunved/updates-to-get-grid-and-its-query-format-4n29</guid>
      <description>&lt;p&gt;A few days ago, I wrote about &lt;a href="https://dev.to/saunved/a-cli-tool-for-creating-css-grid-layouts-2aj4"&gt;get-grid: a CLI tool for creating CSS grid layouts&lt;/a&gt;. A lot of people liked the idea and I got some good suggestions in the comments and on Github.&lt;/p&gt;

&lt;p&gt;This post outlines the updates to the query format of get-grid.&lt;/p&gt;

&lt;h1&gt;
  
  
  Table of contents
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;The problem&lt;/li&gt;
&lt;li&gt;The solution&lt;/li&gt;
&lt;li&gt;The new format&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I will try to outline problems with the previous query format and show you how the new changes will solve these. If you want to code along, you can install the development version of get-grid:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i get-grid@next &lt;span class="nt"&gt;-g&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  The problem
&lt;/h1&gt;

&lt;p&gt;The previous query format looked 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;get-grid --class "container" --query "header/sidebar-content-content/footer"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and gave us this output:&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%2Fi%2Fumvwe2x41i2rj2tq22vv.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%2Fi%2Fumvwe2x41i2rj2tq22vv.png" alt="Dynamically generated layout"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The "/"s indicate a new row and the "-"s indicate a new column. This creates some interesting problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We cannot specify classes with a "-"&lt;/li&gt;
&lt;li&gt;We cannot write a query that contains custom HTML tags (e.g. web components) or semantic HTML&lt;/li&gt;
&lt;li&gt;We can define a container "class", but not an ID or a custom selector&lt;/li&gt;
&lt;li&gt;A default margin, padding, background color is being added which many people will ultimately end up removing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short, &lt;strong&gt;the majority of the problems concern the fact that the query defaults to classes as selectors&lt;/strong&gt;. This can be solved by removing "-" as the separator for columns and by using a little "emmet" magic.&lt;/p&gt;

&lt;p&gt;Thanks to &lt;a href="https://github.com/Saunved/get-grid/issues/1#issue-627991556" rel="noopener noreferrer"&gt;the Github issue by taneltm&lt;/a&gt; for the suggestions that led to the improvements.&lt;/p&gt;
&lt;h1&gt;
  
  
  The solution
&lt;/h1&gt;

&lt;p&gt;Let's get rid of the main blocker: the "-" and replace it with a comma. We now end up with this query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;get-grid &lt;span class="nt"&gt;--query&lt;/span&gt; header/aside,content,content,content/footer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once that's done, let's use our standard CSS selectors instead of assuming that everything is a class.&lt;br&gt;
So, we can do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;get-grid &lt;span class="nt"&gt;--query&lt;/span&gt; header/aside,.content,.content,.content/footer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also use #ids, and classes with a "-" or web components if you wanted to. The query will pick up your code and generate the HTML and CSS correctly.&lt;/p&gt;

&lt;p&gt;Let's give it a try, shall we?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;get-grid &lt;span class="nt"&gt;--container&lt;/span&gt; &lt;span class="s2"&gt;"body.desktop-site"&lt;/span&gt; &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s2"&gt;"header/#sidebar,.content,.content/.footer-left,.footer-middle,.footer-right"&lt;/span&gt; &lt;span class="nt"&gt;-dH&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the &lt;strong&gt;-d flag&lt;/strong&gt; requests get-grid to &lt;strong&gt;add a default margin, padding&lt;/strong&gt;&lt;br&gt;
the &lt;strong&gt;-H flag&lt;/strong&gt; request get-grid to &lt;strong&gt;add a background color and to name the areas&lt;/strong&gt; in HTML&lt;/p&gt;

&lt;p&gt;This is the code spit out:&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;body&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"desktop-site"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;header&amp;gt;&lt;/span&gt;header&lt;span class="nt"&gt;&amp;lt;/header&amp;gt;&lt;/span&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;"sidebar"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;#sidebar&lt;span class="nt"&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;"content"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;.content&lt;span class="nt"&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;"footer-left"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;.footer-left&lt;span class="nt"&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;"footer-middle"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;.footer-middle&lt;span class="nt"&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;"footer-right"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;.footer-right&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/body&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="nt"&gt;body&lt;/span&gt;&lt;span class="nc"&gt;.desktop-site&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;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;grid-template-rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="py"&gt;grid-gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;header&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;grid-column&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;grid-row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#eaeaea&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;#sidebar&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;grid-column&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;grid-row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#eaeaea&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nc"&gt;.content&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;grid-column&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;grid-row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#eaeaea&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nc"&gt;.footer-left&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;grid-column&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;grid-row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#eaeaea&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nc"&gt;.footer-middle&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;grid-column&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;grid-row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#eaeaea&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nc"&gt;.footer-right&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;grid-column&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;grid-row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#eaeaea&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;And this is what we get when we paste it to HTML:&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%2Fi%2Fswm4zuee4nt5f65p84rj.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%2Fi%2Fswm4zuee4nt5f65p84rj.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And yes, the generated HTML respects the selectors and generates code the way emmet would (because the emmet library is being used to generate the HTML!).&lt;/p&gt;
&lt;h1&gt;
  
  
  The new format
&lt;/h1&gt;

&lt;p&gt;I feel like the query format is slightly more "complete" now. In case you need a quick reference:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;/ to indicate a new row&lt;/li&gt;
&lt;li&gt;, to indicate a new column ( previously '-' )&lt;/li&gt;
&lt;li&gt;selectors must be specified explicitly (i.e ".class" instead of "class"). You can specify IDs and HTML tags the way you would while writing CSS selectors.&lt;/li&gt;
&lt;li&gt;The container is specified using --container (or -C) instead of --class. You can specify any valid CSS selector for the container&lt;/li&gt;
&lt;li&gt;The default padding/margin and colors are removed. You need to use the -d and -H flags to get those in your CSS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can read the help provided along with the tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;get-grid &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It outlines some other flags that allow you to get only the style, or only the HTML, or print output to the terminal, etc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How much less code are we writing?&lt;/strong&gt;&lt;br&gt;
If we look at the query above, it consists of 129 characters. It generates a layout with 1132 characters of code. That's &lt;strong&gt;8.7 times less code to write&lt;/strong&gt;!&lt;/p&gt;




&lt;p&gt;There are some other enhancements that can be made to the query format (such as being able to specify heights and widths for rows and columns). I will be working on this in the coming weeks.&lt;/p&gt;




&lt;p&gt;The next stage would be to write a basic test suite and to find out other problems with the query format. Check out &lt;a href="https://github.com/Saunved/get-grid" rel="noopener noreferrer"&gt;the Github repo here&lt;/a&gt;. I'd love to work on more enhancements and to fix any existing bugs. Feel free to fork and create pull requests and don't forget to mention if you are working on something! &lt;/p&gt;

&lt;p&gt;Do leave a star if the tool helps you :)&lt;/p&gt;

</description>
      <category>css</category>
      <category>getgrid</category>
      <category>autogenerate</category>
      <category>cli</category>
    </item>
    <item>
      <title>A CLI tool for creating CSS Grid layouts</title>
      <dc:creator>Saunved</dc:creator>
      <pubDate>Fri, 29 May 2020 10:02:43 +0000</pubDate>
      <link>https://dev.to/saunved/a-cli-tool-for-creating-css-grid-layouts-2aj4</link>
      <guid>https://dev.to/saunved/a-cli-tool-for-creating-css-grid-layouts-2aj4</guid>
      <description>&lt;p&gt;CSS Grid is awesome for creating all sorts of HTML layouts without having to rely on any external libraries. It supports 95.49% of major browsers according to &lt;a href="https://caniuse.com/#feat=css-grid" rel="noopener noreferrer"&gt;caniuse&lt;/a&gt; (my condolences if you need to support IE).&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Update!&lt;/li&gt;
&lt;li&gt;Quick introduction&lt;/li&gt;
&lt;li&gt;
Benchmarking |
Creating columns and rows dynamically&lt;/li&gt;
&lt;li&gt;
Getting an upgrade |
Hardcoding common layout presets&lt;/li&gt;
&lt;li&gt;
We need to go deeper |
&lt;em&gt;The thing I want you to see the most...Dynamically generating CSS grids&lt;/em&gt; &lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Update
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Updated on 1 June&lt;/strong&gt;&lt;br&gt;
Based on the suggestions and comments to this post as well as &lt;a href="https://github.com/Saunved/get-grid/issues/1" rel="noopener noreferrer"&gt;this Github issue&lt;/a&gt;, get-grid@next is under development. A lot of important fixes have been made to the query format to accommodate for HTML tags, web components and IDs.&lt;/p&gt;

&lt;p&gt;Please read the 2nd post of the series &lt;a href="https://dev.to/saunved/updates-to-get-grid-and-its-query-format-4n29"&gt;here&lt;/a&gt; to understand the new format.&lt;/p&gt;

&lt;p&gt;These changes primarily affect the query format that is explained in the last section of this post.&lt;/p&gt;
&lt;h1&gt;
  
  
  Quick introduction
&lt;/h1&gt;

&lt;p&gt;Creating layouts with CSS grid is pretty simple, but it's always good to write less repetitive code &lt;em&gt;(I can hear a collective yes)&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I started looking for ways in which I could generate CSS grids quickly. &lt;br&gt;
I found a few generators online. This list on &lt;a href="https://www.sitepoint.com/css-grid-generators/" rel="noopener noreferrer"&gt;SitePoint&lt;/a&gt; covers many of them.  I also found articles that gave you the code of some common layouts (like the Holy Grail), that you could copy-paste.&lt;/p&gt;

&lt;p&gt;The drag-and-drop grid generators are great, but I was looking for something a little more ...dynamic.&lt;br&gt;
What if you could create a CSS grid layout using the CLI? One that was very easy to read - so easy that you could probably use it to generate layouts dynamically and inject them at runtime?&lt;/p&gt;

&lt;p&gt;The applications of this are pretty fun to think of.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can create a basic grid with 90% of the code pre-written in your command line itself&lt;/li&gt;
&lt;li&gt;Writing media queries will be a breeze&lt;/li&gt;
&lt;li&gt;(And if we are day-dreaming)... You could write a natural language processor that plugs into the underlying code. So someone could say, "Create a header that spans the full width. Now add a sidebar below that by making it a quarter width. Fill the rest of the row with the content..." and the words would be transpiled to a command that generates the code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But I am getting a little too ahead of myself here.&lt;/p&gt;

&lt;p&gt;Let's start off simple and understand how the CLI works. To create the CLI, I am using &lt;a href="https://www.npmjs.com/package/commander" rel="noopener noreferrer"&gt;commander.js&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you want to code-along, you can install the package from npm using&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-g&lt;/span&gt; get-grid
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The most basic command you can try is:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;The tool copies the grid to your clipboard, but in case this doesn't work, just use the &lt;strong&gt;--output&lt;/strong&gt; flag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;get-grid &lt;span class="nt"&gt;--output&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you can just do&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;get-grid &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;for some quick help&lt;/p&gt;




&lt;h1&gt;
  
  
  Level 1 - benchmarking
&lt;/h1&gt;

&lt;p&gt;I started off simple:&lt;br&gt;
The user should be able to specify the number of rows and columns they want, along with the parent container class.&lt;/p&gt;

&lt;p&gt;So, to create a 2-column, 2-row layout, one would simply do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;get-grid &lt;span class="nt"&gt;-c2&lt;/span&gt; &lt;span class="nt"&gt;-r2&lt;/span&gt; &lt;span class="nt"&gt;--class&lt;/span&gt; grid-holder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And voila! The generator spits out this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"grid-holder"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;1&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;2&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;3&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;4&lt;span class="nt"&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;.grid-holder&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;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="py"&gt;grid-template-rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="py"&gt;grid-gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1em&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;Some properties are set by default as you will notice. &lt;br&gt;
It's pretty basic, pretty rudimentary. It's still faster than typing it out by hand though, and it's faster than drag-and-drop too.&lt;/p&gt;

&lt;p&gt;Time to turn it up a notch.&lt;br&gt;
For the next level, I wanted to be able to type out the layout I wanted in the simplest way possible.&lt;/p&gt;


&lt;h1&gt;
  
  
  Level 2 - getting an upgrade
&lt;/h1&gt;

&lt;p&gt;Creating common layouts quickly is very handy. I hard-coded a few common layouts and plugged them into a switch case. It's nothing innovative or great, but it generates the common layouts nonetheless.&lt;/p&gt;

&lt;p&gt;So you can just do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;get-grid &lt;span class="nt"&gt;--template&lt;/span&gt; holy-grail
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and you get this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"grid-container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;header&amp;gt;&lt;/span&gt;
          Header
        &lt;span class="nt"&gt;&amp;lt;/header&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;aside&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"sidebar-left"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          Left Sidebar
        &lt;span class="nt"&gt;&amp;lt;/aside&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;article&amp;gt;&lt;/span&gt;
          Article
        &lt;span class="nt"&gt;&amp;lt;/article&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;aside&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"sidebar-right"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          Right Sidebar
        &lt;span class="nt"&gt;&amp;lt;/aside&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;footer&amp;gt;&lt;/span&gt;
          Footer
        &lt;span class="nt"&gt;&amp;lt;/footer&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;.grid-container&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;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;150px&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt; &lt;span class="m"&gt;150px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="py"&gt;grid-template-rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="py"&gt;grid-gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="nt"&gt;header&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="nt"&gt;aside&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="nt"&gt;article&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="nt"&gt;footer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#eaeaea&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="nt"&gt;header&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;footer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;grid-column&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;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;p&gt;Which gives us this layout:&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%2Fi%2Fhxup6xtbdv7f0rs3e5is.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%2Fi%2Fhxup6xtbdv7f0rs3e5is.png" alt="Holy grail layout"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have taken this layout directly from &lt;a href="https://codepen.io/geoffgraham/pen/rjrLXB" rel="noopener noreferrer"&gt;Codepen&lt;/a&gt;.&lt;br&gt;
I haven't created many pre-defined layouts, but I am thinking of interesting ways in which one can create presets and name them for use later on. &lt;/p&gt;

&lt;p&gt;As the screenshot suggests, the tool was supposed to be called "grid-this", but I like "get-grid" better.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This was still not the "dynamic-ness" that I was looking for.&lt;/strong&gt; I wanted to be able to specify how the layout looked (via the CLI) and the code would be generated dynamically.&lt;/p&gt;


&lt;h1&gt;
  
  
  Level 3 - We need to go deeper
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;&lt;br&gt;
The query format has been changed slightly to take care of IDs and semantic HTML as well as web components. You can check the 2nd post of this series to understand the changes &lt;a href="https://dev.to/saunved/updates-to-get-grid-and-its-query-format-4n29"&gt;here&lt;/a&gt;.&lt;/p&gt;



&lt;p&gt;For this step, I had to devise a query notation of sorts; one that was concise; did not take a lot of time to think up, and could be taught quickly.&lt;/p&gt;

&lt;p&gt;Here's what I came up with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;header/sidebar-content-content-content/footer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The "/" indicates a new row and the "-" indicates a new column. If an entire row is taken up by the same area, there is no need to specify it again.&lt;/p&gt;

&lt;p&gt;So, what do we get out of this?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;get-grid &lt;span class="nt"&gt;--query&lt;/span&gt; header/sidebar-content-content/footer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code being spit out:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"grid-container"&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;"header"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;header&lt;span class="nt"&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;"sidebar"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;sidebar&lt;span class="nt"&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;"content"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;content&lt;span class="nt"&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;"footer"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;footer&lt;span class="nt"&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;.grid-container&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;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="py"&gt;grid-template-rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="py"&gt;grid-gap&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="p"&gt;}&lt;/span&gt;

         &lt;span class="nc"&gt;.header&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="nl"&gt;grid-column&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="nl"&gt;grid-row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;1&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="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#444&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#eee&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
              &lt;span class="p"&gt;}&lt;/span&gt;

          &lt;span class="nc"&gt;.sidebar&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="nl"&gt;grid-column&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="nl"&gt;grid-row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;2&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="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#444&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#eee&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;

           &lt;span class="nc"&gt;.content&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="nl"&gt;grid-column&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="nl"&gt;grid-row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;2&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="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#444&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#eee&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
             &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="nc"&gt;.footer&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="nl"&gt;grid-column&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="nl"&gt;grid-row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;3&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="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#444&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#eee&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 paste it to an HTML file, you get:&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%2Fi%2Fumvwe2x41i2rj2tq22vv.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%2Fi%2Fumvwe2x41i2rj2tq22vv.png" alt="Dynamically generated layout"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And this really is dynamically generating this layout. The code is parsing your query (twice) and generating the grid-column and grid-row properties. The query reads like a natural language, so creating simple layouts dynamically should be possible in theory. &lt;/p&gt;

&lt;p&gt;So using this query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;get-grid &lt;span class="nt"&gt;--query&lt;/span&gt;
header/sidebar1-content-content-content-sidebar2/
footer1-footer1-footer2-footer2-footer3-footer3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can get 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%2Fi%2Ftz0jm631a50z2ikga9c7.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%2Fi%2Ftz0jm631a50z2ikga9c7.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It works, and it's simple, and it's dynamic! Yay!&lt;br&gt;
But let's not get ahead of ourselves. This is a prototype, something I cooked up in a few hours (and I am still fixing bugs while writing this article). It has A LOT of things missing (some that I might not even be aware of).&lt;/p&gt;

&lt;p&gt;I have a few ideas for how certain things could be improved. I will try to explain them in a Q&amp;amp;A format:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1) How to specify a custom height for a row?&lt;/strong&gt;&lt;br&gt;
For specifying height, the query could contain a ":" operator. Hypothetically speaking, it could be something like this:&lt;br&gt;
header:60px/sidebar-content-content-content:auto/footer:200px&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2) What if only a specific row or column repeats? What if a class spans across rows (rather than columns)?&lt;/strong&gt;&lt;br&gt;
To handle repeats, we could use a variation of "-" along with a "*" and "#" operator.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We could do header/sidebar-content-3/footer to repeat the entire row thrice, increasing the row-height to 3fr (the "-3" is not detected as a class since CSS classes cannot start with a number).&lt;/li&gt;
&lt;li&gt;And header/sidebar-content*3/footer to repeat ONLY the "content" column thrice (keeping the row height 1fr)&lt;/li&gt;
&lt;li&gt;Or header/widgeta#2-content#3/widgetb/footer to keep the widgeta height to 2fr but increasing the content height to 3fr. "widgetb" will then fill up the 1fr space.&lt;/li&gt;
&lt;li&gt;We can also change the grid-auto-flow property by setting a flag.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3) What happens if an area is empty?&lt;/strong&gt;&lt;br&gt;
If we wanted to have a blank area where widgetb is, we could use a "." operator, by doing header/widgeta#2-content#3/./footer&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4) What happens if you want to write classes with a "-"?&lt;/strong&gt;&lt;br&gt;
I tried using an operator other than "-" for separating the columns, but it drastically reduces readability and becomes much less intuitive in a reading. To get around this issue, we could use an escape character like "\" to specify -'s that are not a part of the query itself.&lt;/p&gt;




&lt;p&gt;I have not thought of all the possible cases and the above ideas are hypothetical. I will be working on these as the days pass. In the meanwhile, you can check out the &lt;a href="https://github.com/Saunved/get-grid" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt;. Do drop me a star if this tool helps you :)&lt;/p&gt;

&lt;p&gt;Looking forward to comments, ideas, suggestions, and criticism!&lt;/p&gt;

</description>
      <category>css</category>
      <category>cli</category>
      <category>cssgrid</category>
      <category>autogenerate</category>
    </item>
    <item>
      <title>The better web developer</title>
      <dc:creator>Saunved</dc:creator>
      <pubDate>Thu, 16 Apr 2020 14:33:54 +0000</pubDate>
      <link>https://dev.to/saunved/general-observations-on-becoming-a-better-web-developer-5424</link>
      <guid>https://dev.to/saunved/general-observations-on-becoming-a-better-web-developer-5424</guid>
      <description>&lt;p&gt;When I first got into web development in 2017, the epitome of being a good developer (for me) was understanding jQuery and being able to use it efficiently. Little did I know that jQuery was almost "dead" back then, as &lt;a href="https://flaviocopes.com/jquery/"&gt;this article shows&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After dabbling in WordPress for a while, I wanted more control over the inner workings of the website. I wanted to make good, dynamic websites. I was taken towards the framework road - and to be precise - down the Angular path. I didn't quite understand WHY a framework was needed back then.&lt;br&gt;
"I can just do it with jQuery, no?" was a question I asked a lot.&lt;/p&gt;

&lt;p&gt;The first "burnt" experience I had with jQuery was when I had to make a webpage with multiple forms that updated asynchronously and whose updates changed multiple parts of the DOM.&lt;/p&gt;

&lt;p&gt;After a week of struggling with the code (and managing 20-25 element IDs and their linking in jQuery), I turned to my co-developer and said, "Let's use Angular please."&lt;/p&gt;

&lt;p&gt;That was my first, important lesson towards becoming a better developer.&lt;/p&gt;

&lt;h3&gt;
  
  
  #1 Knowing something doesn't mean that it's the solution
&lt;/h3&gt;

&lt;p&gt;The migration to Angular took a few hours and the form updates were effortless. We never needed jQuery. What we really needed was two-way binding.&lt;/p&gt;

&lt;p&gt;The lesson hadn't quite sunk in though. Now that I understood the basics of Angular, I wanted to use it everywhere. jQuery wasn't really required, so what? Angular was the one-stop-shop. It could do &lt;strong&gt;everything!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;My love of frameworks and the "magic" that they could do would be questioned soon. We had made a single page application with Angular. It had two forms and some lists that came on and off the page based on some conditions. The use-case was not really complex. We made the frontend using Angular but looking back at that project, I can see an important lesson in it.&lt;/p&gt;

&lt;h3&gt;
  
  
  #2 Vanilla JS is good enough for a LOT of things
&lt;/h3&gt;

&lt;p&gt;Sure, Angular handled the 2-way binding and made form handling easier. But there were just &lt;strong&gt;two&lt;/strong&gt; forms which weren't even dynamic. Just because Angular was available and we knew it, didn't mean that we had to use it. It may have sped up the process, but we could have tried a vanilla JS approach and it would have worked fine.&lt;/p&gt;

&lt;p&gt;Over the past few months, I have spent a lot of time making tiny projects and learning from experience. Here are a few other lessons that are helping me become a better developer:&lt;/p&gt;

&lt;h3&gt;
  
  
  #3 Never underestimate the power of good naming
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;There are only two hard things in Computer Science: cache invalidation and naming things.&lt;/p&gt;

&lt;p&gt;-- Phil Karlton&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Writing&lt;br&gt;
&lt;br&gt;
 &lt;code&gt;var ch&lt;/code&gt;&lt;br&gt;
&lt;br&gt;
 as&lt;br&gt;
&lt;br&gt;
 &lt;code&gt;var clickHandler&lt;/code&gt;&lt;br&gt;
&lt;br&gt;
 can save you minutes, if not hours of going back and forth to understand your own code in the future. Keeping a habit of reviewing your code and &lt;em&gt;assuming&lt;/em&gt; that you can improve it often helps in actually improving it.&lt;/p&gt;

&lt;h3&gt;
  
  
  #4 Learn Vanilla JS properly before diving into frameworks
&lt;/h3&gt;

&lt;p&gt;More often than not, it helps to imagine how vanilla JS could play out instead of just jumping into a React, Angular or Vue project. Especially if you are just starting out - don't jump into a framework. Learn Vanilla JS first - it's very powerful all by itself, and even if you have made the wrong decision picking it for a project, it will help you appreciate why we need frameworks!&lt;/p&gt;

&lt;h3&gt;
  
  
  #5 Cut your veggies for later
&lt;/h3&gt;

&lt;p&gt;It's a good idea to have a system in place. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you know you're going to keep spinning up servers for MEAN projects, save an OS image on the cloud with all your pre-configured settings&lt;/li&gt;
&lt;li&gt;It helps to create code snippets and store them in a folder called "snippets" (very creative, I know). This can include stuff like database initialization, complex database queries, HTML templates, login, signup flows, CRUD operations, common CSS rules, etc. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I used to keep opening old projects and copy-pasting from them. Whenever you have to do that, just make a file in your "snippets" folder, &lt;em&gt;name it appropriately&lt;/em&gt; and look there the next time!&lt;br&gt;
This is just the &lt;a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself"&gt;DRY principle&lt;/a&gt; put in use across projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  #6 Reading open source code helps. A lot
&lt;/h3&gt;

&lt;p&gt;Many times we tend to get locked into our own world and our own code. It's cool to open some libraries we use and check out how the code has been written and organized. That can spark ideas, and even make us better coders in the long run. &lt;br&gt;
For example, the often-used "_" before function or variable names in projects used to bother me immensely until I read up on &lt;a href="https://softwareengineering.stackexchange.com/questions/280300/why-is-it-common-to-put-an-underscore-before-a-method-in-javascript"&gt;what it meant&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;We learn new things every day. For example, I learned this recently: &lt;a href="https://developers.google.com/web/updates/2013/12/300ms-tap-delay-gone-away"&gt;The 300ms problem&lt;/a&gt;, where on small devices, the screen waits for 300ms before passing the event to the click handler. This was to wait and check if the event was a double-tap to zoom!&lt;/p&gt;

&lt;p&gt;Although the article above says that the problem was solved, I could still see this 300ms wait behavior on button clicks when I resized my browser to less than 364px! The meta tag didn't help either, so I had to go with the html-manipulation trick from the same article. I'm still not sure why 364px was the barrier for this bug (and I'd love to have a discussion on it if you guys can reproduce the error).&lt;/p&gt;

&lt;p&gt;I'd love to hear about something new that you guys have learned recently. Feel free to leave a comment below!&lt;/p&gt;

</description>
      <category>developer</category>
      <category>improvement</category>
      <category>newbie</category>
      <category>learning</category>
    </item>
  </channel>
</rss>
