<?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: Lukas Hermann</title>
    <description>The latest articles on DEV Community by Lukas Hermann (@lhermann).</description>
    <link>https://dev.to/lhermann</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%2F115853%2Fcd956670-d517-4ecc-a6af-331406f0308f.jpeg</url>
      <title>DEV Community: Lukas Hermann</title>
      <link>https://dev.to/lhermann</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lhermann"/>
    <language>en</language>
    <item>
      <title>June 2021: Launching my first app</title>
      <dc:creator>Lukas Hermann</dc:creator>
      <pubDate>Mon, 12 Jul 2021 15:38:17 +0000</pubDate>
      <link>https://dev.to/lhermann/june-2021-launching-my-first-app-b59</link>
      <guid>https://dev.to/lhermann/june-2021-launching-my-first-app-b59</guid>
      <description>&lt;p&gt;Taking inspiration from &lt;a href="https://www.alexwest.co/"&gt;Alex West&lt;/a&gt; I am starting to write monthly updates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Launching a paid plan for stagetimer.io
&lt;/h2&gt;

&lt;p&gt;Stagetimer was born on November 1, 2020, after I visited a friend's studio. He had to run back and forth to an old laptop to start and stop a simple timer app. I was sure someone made a simple cloud-synced timer app. You know, those .io/.so/.to mini-apps. But no, nobody made it. So I started to build that very evening.&lt;/p&gt;

&lt;p&gt;I posted it on &lt;a href="https://www.reddit.com/r/CommercialAV/comments/jx3j8i/advice_for_presentation_timer_app_in_the_making/"&gt;Reddit&lt;/a&gt; on November 19 for feedback and got (for my standards) a lot of positive responses. There were even some suggestions for paid features. So I continued building more features.&lt;/p&gt;

&lt;p&gt;Finally, on June 13 I did what I never planned or even considered. I launched a paid plan for stagetimer.io. That very evening, to my utter amazement, I got my first subscriber. At the end of the month, I had six customers.&lt;/p&gt;


&lt;blockquote class="ltag__twitter-tweet"&gt;
      &lt;div class="ltag__twitter-tweet__media"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DBZhPMvO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/media/E5DM3cDXIAAn52h.jpg" alt="unknown tweet media content"&gt;
      &lt;/div&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--7WmLNtY3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/804675774045421568/JdP0WNO9_normal.jpg" alt="Lukas Hermann profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Lukas Hermann
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        @_lhermann
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ir1kO05j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      Got my 6th customer for &lt;a href="https://t.co/Bubno59r4i"&gt;stagetimer.io&lt;/a&gt; 😍&lt;br&gt;&lt;br&gt;&lt;a href="https://twitter.com/hashtag/buildinpublic"&gt;#buildinpublic&lt;/a&gt; 
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      17:31 PM - 29 Jun 2021
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1409927392701734919" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fFnoeFxk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1409927392701734919" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k6dcrOn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1409927392701734919" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SRQc9lOp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;p&gt;For the first time in my life, I can post MMR (monthly recurring revenue) numbers. For the uninitiated, MMR is the holy grail for solo entrepreneurs. MMR is like a salary without the cons of being an employee. MMR means freedom, future, self-fulfillment, independence, flexibility, no more 9-to-5 grind, and no more advanced notice for vacations only to stay in the hotel the entire week due to rain. But it also comes with customer support, marketing, taxes, and the nagging feeling to always use your time productively.&lt;/p&gt;

&lt;p&gt;Just to be clear, I have a full-time job with &lt;a href="https://laserhub.com/"&gt;Laserhub&lt;/a&gt;. Stagetimer is my side project. But for me, it is also the beginning of a brighter future.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stats
&lt;/h2&gt;

&lt;p&gt;Stagetimer &lt;strong&gt;↗&lt;/strong&gt; €52 MMR&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Aller Anfang ist schwer.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;– German Proverb "Every beginning is hard"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>monthly</category>
      <category>buildinpublic</category>
    </item>
    <item>
      <title>Schedule Script Execution in a Node.js Docker Image with Cron</title>
      <dc:creator>Lukas Hermann</dc:creator>
      <pubDate>Fri, 23 Apr 2021 04:37:36 +0000</pubDate>
      <link>https://dev.to/lhermann/schedule-script-execution-in-a-node-js-docker-image-with-cron-5cga</link>
      <guid>https://dev.to/lhermann/schedule-script-execution-in-a-node-js-docker-image-with-cron-5cga</guid>
      <description>&lt;p&gt;Cron is a popular tool to schedule tasks, it comes pre-installed on almost any Linux image such as Debian or Ubuntu. Cron can execute any command at a predefined time like 4:30 AM or every 2 minutes. For this reason, it is the first choice of developers for scheduled script execution.&lt;/p&gt;

&lt;p&gt;A docker image is nothing else than a stripped-down Linux operating system and comes with cron. Most answers on StackOverflow suggest installing extra packages or building a custom image, but neither approach is necessary. The vanilla Node.js Docker image has everything needed to schedule the execution of javascript files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example with Code
&lt;/h2&gt;

&lt;p&gt;I want to run a javascript file every 30 minutes inside my docker image. I want to use &lt;code&gt;docker-compose&lt;/code&gt;&lt;sup id="fnref1"&gt;1&lt;/sup&gt; to start and stop the docker container.&lt;/p&gt;

&lt;p&gt;Here's my docker compose file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.1"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;price-daemon&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node:14-alpine&lt;/span&gt;
    &lt;span class="na"&gt;working_dir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/home/node/app&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./:/home/node/app&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/usr/sbin/crond&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-f&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-l&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-c&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;/home/node/app/crontab&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-L&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;/var/log/cron.log"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I use the lightweight &lt;code&gt;node:14-alpine&lt;/code&gt;&lt;sup id="fnref2"&gt;2&lt;/sup&gt; image and mount my current working directory as volume.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;command&lt;/code&gt; starts the cron daemon and it will look for the file &lt;code&gt;/home/node/app/crontab/root&lt;/code&gt;. Remove &lt;code&gt;-l 0&lt;/code&gt; if you don't like a super verbose log. In my working directory I created the file &lt;code&gt;crontab/root&lt;/code&gt; with this contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# min hour day month weekday command&lt;/span&gt;
&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; /bin/date &lt;span class="nt"&gt;--rfc-2822&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; /var/log/cron.log
&lt;span class="k"&gt;*&lt;/span&gt;/30 &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; node /home/node/app/scheduled.js &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; /var/log/cron.log 2&amp;gt;&amp;amp;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second line is just a timestamp printed into the log file for debugging purposes. The third line executes the &lt;code&gt;scheduled.js&lt;/code&gt; file and logs its output into &lt;code&gt;/var/log/cron.log&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And that's it. Pretty simple right?&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;&lt;a href="https://docs.docker.com/compose/"&gt;https://docs.docker.com/compose/&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;&lt;a href="https://hub.docker.com/_/node"&gt;https://hub.docker.com/_/node&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>docker</category>
      <category>javascript</category>
      <category>node</category>
      <category>cron</category>
    </item>
    <item>
      <title>Why the iPhone Timer App displays a Fake Time</title>
      <dc:creator>Lukas Hermann</dc:creator>
      <pubDate>Mon, 28 Dec 2020 21:56:09 +0000</pubDate>
      <link>https://dev.to/lhermann/why-the-iphone-timer-app-displays-a-fake-time-34le</link>
      <guid>https://dev.to/lhermann/why-the-iphone-timer-app-displays-a-fake-time-34le</guid>
      <description>&lt;p&gt;While building my event timer app called &lt;a href="https://stagetimer.io"&gt;stagetimer.io&lt;/a&gt; I came across a peculiarity with displaying time found out that the iPhone timer addresses it by showing us a fake time. By definition, a countdown shows how much time is left. So if the countdown says 5s we assume there are 5 seconds left. But that's not the whole truth.&lt;/p&gt;

&lt;h1&gt;
  
  
  TL;DR
&lt;/h1&gt;

&lt;p&gt;The iPhone countdown timer doesn't strictly display the correct time but adds 500ms, or half a second, to the remaining time. It does this to make the reading of time more intuitive for humans. The alarm at the end of the countdown is not affected by this 500ms inaccuracy.&lt;/p&gt;

&lt;h1&gt;
  
  
  Countdowns are tricky
&lt;/h1&gt;

&lt;p&gt;Javascript likes to use milliseconds when dealing with time, 1000ms equals 1s. Here is an example of a 5s countdown that starts at 5000ms and uses the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval"&gt;setInterval()&lt;/a&gt; function to deduct 10ms every 10ms, simple enough. Milliseconds are converted to seconds by dividing by 1000 and rounding down like so: &lt;code&gt;Math.floor(milliseconds / 1000)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UFEpUz2i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hb4vl9gdbeemzeq2i7fp.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UFEpUz2i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hb4vl9gdbeemzeq2i7fp.gif" alt="5s countdown timer showing only seconds"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The timer jumps to 4s right when hitting start and once the timer switches to 0s there are still 1s to go. This makes a lot of sense when counting up, for example, 10:00 is displayed during the first minute of 10 AM, not 10:01, always rounding down. But for a countdown timer, this is counterintuitive. It is easier to understand if the timer has a fractional seconds display.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--A7OTLgnV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/udsceogxmtpn1dustvbi.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A7OTLgnV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/udsceogxmtpn1dustvbi.gif" alt="5s countdown timer showing seconds and its fractions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now the timer displays 0.9s seconds instead of 0s to show clearly that there is still time left on the clock. However, I didn't want to show fractional seconds for my timer.&lt;/p&gt;

&lt;h1&gt;
  
  
  Checking how the iPhone does it
&lt;/h1&gt;

&lt;p&gt;So now I was curious how my iPhone solves this conundrum. So I set my iPhone timer to 5s:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5RjVviAc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vs95kx8bnh432glaerl6.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5RjVviAc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vs95kx8bnh432glaerl6.gif" alt="5s countdown timer on the iPhone"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After I click "Start" the iPhone timer shows 5s, not 4s like in the example above. But it switches to 4s before a full second expired. It then counts proper seconds until it reaches 0s which, again, is not a full second. And if you tap "Pause" just after it jumped to 0s it will promptly jump back to 1s to show you that there is, in fact, still some time left on the countdown.&lt;/p&gt;

&lt;p&gt;I figured that the good folks at Apple add an extra fake 500ms to the actual time to start that countdown display at 5s instead of 4s. The timer ends and the phone beeps if the actual time hits 0s and the "fake" time hits 500ms. So they faced the same problem I did and came up with a practical solution. After all, if you start a 5s countdown, it should start at 5s right? For illustration, here is my simple timer doing the same trick.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mJIOId7e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vx2a5c00o5q56q63ec2e.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mJIOId7e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vx2a5c00o5q56q63ec2e.gif" alt="5s countdown timer showing fake seconds"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So there you have it, the iPhone timer is technically lying to you.&lt;/p&gt;

&lt;h1&gt;
  
  
  Edit: About rounding time
&lt;/h1&gt;

&lt;p&gt;Some have pointed out that the problem could be solved more easily by rounding to the nearest second or rounding up instead of rounding down. This is correct. Suppose we have &lt;code&gt;5459543ms&lt;/code&gt; that we want to bring into the traditional form &lt;code&gt;HH:mm:ss&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I first divided the number into hours, minutes, and seconds with the help of some modular arithmetic and applied the rounding afterward. Rounding down results in &lt;code&gt;01:30:59&lt;/code&gt;, which is correct, but rounding to the nearest integer or rounding up results in the impossible time &lt;code&gt;02:31:60&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5459543&lt;/span&gt;
&lt;span class="nx"&gt;seconds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="c1"&gt;// 1.517&lt;/span&gt;
&lt;span class="nx"&gt;minutes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;60000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="c1"&gt;// 30.992&lt;/span&gt;
&lt;span class="nx"&gt;hours&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;3600000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="c1"&gt;// 59.543&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, rounding the time to seconds first &lt;code&gt;5460000ms&lt;/code&gt;, and breaking it down afterward yields the same result as described above with adding 500ms, namely &lt;code&gt;01:31:00&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5460000&lt;/span&gt;
&lt;span class="nx"&gt;seconds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="c1"&gt;// 0.000&lt;/span&gt;
&lt;span class="nx"&gt;minutes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;60000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="c1"&gt;// 31.000&lt;/span&gt;
&lt;span class="nx"&gt;hours&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;3600000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="c1"&gt;// 1.517&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Edit 2: In an earlier version I messed up my rounding as described. Many helpful, as well as helpful and insulting, comments pointed out my error. So in addition to learning about counting time I also learned how it feels to be wrong on the internet 😅&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  References:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://codepen.io/lhermann/pen/wvzPxXj"&gt;The code from the animations in this article&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ios</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Lessons learned from over 10 years of writing CSS</title>
      <dc:creator>Lukas Hermann</dc:creator>
      <pubDate>Mon, 12 Oct 2020 07:16:49 +0000</pubDate>
      <link>https://dev.to/lhermann/writing-good-css-11-best-practices-h7o</link>
      <guid>https://dev.to/lhermann/writing-good-css-11-best-practices-h7o</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Through my years of using CSS, I have found some principles to stand the proof of time while others did cause me many headaches in the long run. I want to share with you the those that stood the test of time. If you have some good advice that is absent from this list please let me know, I am as much willing to learn as to share.&lt;/p&gt;

&lt;p&gt;CSS is curious in that it is very easy to learn but near impossible to master.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: The advice in this article is concerned with the developer experience of CSS, and not with design, performance, or accessibility (though these are important). The following points will especially be of value to you if you need to maintain and extend your CSS codebase over longer periods.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Keep specificity low&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;#id&lt;/code&gt; selectors are evil&lt;/li&gt;
&lt;li&gt;Treat &lt;code&gt;!important&lt;/code&gt; like raw eggs&lt;/li&gt;
&lt;li&gt;Avoid chaining (or nesting) of selectors&lt;/li&gt;
&lt;li&gt;Don't combine element and class selectors&lt;/li&gt;
&lt;li&gt;Organize your code by increasing specificity&lt;/li&gt;
&lt;li&gt;Use few properties per class&lt;/li&gt;
&lt;li&gt;Don't worry about sorting your properties&lt;/li&gt;
&lt;li&gt;Follow a naming convention like BEM&lt;/li&gt;
&lt;li&gt;Avoid using shorthands if possible&lt;/li&gt;
&lt;li&gt;Keep presentation (CSS), semantics (HTML) and behavior (JS) separate&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1. Keep specificity low
&lt;/h2&gt;

&lt;p&gt;It is really important to understand CSS specificity first, &lt;a href="https://dev.to/emmawedekind/css-specificity-1kca"&gt;here is an excellent article&lt;/a&gt;. In essence, whenever you want to overwrite styles applied by one selector, you need to exceed or at least match its specificity.&lt;/p&gt;

&lt;p&gt;🚫 Bad: specificity of first selector is too high&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nf"&gt;#main&lt;/span&gt; &lt;span class="nc"&gt;.nav&lt;/span&gt; &lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.nav&lt;/span&gt; &lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="nc"&gt;.is-active&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* dominated by #main */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;✅ Good: using as few selectors as possible&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.nav-item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.nav-item.is-active&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;p&gt;To avoid the specificity wars, you want to avoid adding selectors that are not necessary. Instead of &lt;code&gt;.nav ul li&lt;/code&gt; use only &lt;code&gt;.nav li&lt;/code&gt; or better just &lt;code&gt;.nav-item&lt;/code&gt;. Points 2. - 6. of this article are hands-on practices to help you to keep your specificity low.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. &lt;code&gt;#id&lt;/code&gt; selectors are evil
&lt;/h2&gt;

&lt;p&gt;Id selectors have the highest specificity. This means whenever you use one, you are forced to use it again every time you want to modify the element's style. This might work well when you write your code in the first place but causes a headache whenever you want to extend it. I recommend generally avoiding &lt;code&gt;#id&lt;/code&gt; selectors in your stylesheet.&lt;/p&gt;

&lt;p&gt;🚫 Bad: forced to use the #footer selector repeatedly&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nf"&gt;#footer&lt;/span&gt; &lt;span class="nc"&gt;.box&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#333&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;#footer&lt;/span&gt; &lt;span class="nc"&gt;.box&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#444&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;✅ Good: avoid using #id selectors in you stylesheet&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.box&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#333&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.box&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#444&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;p&gt;&lt;em&gt;Further Reading: This article of Harry Roberts shows how you can &lt;a href="https://csswizardry.com/2014/07/hacks-for-dealing-with-specificity/#low-specificity-ids"&gt;use ids without increasing specificity&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Treat &lt;code&gt;!important&lt;/code&gt; like raw eggs
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;!important&lt;/code&gt; is the ace of spades of CSS, it is the ultimate trump card, and it should be treated as such. If you use it to escape the frustration of dealing with specificity which has gotten out of hand, then you are using it wrong. Use it sparingly, with selectors that have a very narrow scope and where you are certain that you want it to overpower all other styles.&lt;/p&gt;

&lt;p&gt;🚫 Bad: using !important to deal with specificity frustration&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nf"&gt;#header&lt;/span&gt; &lt;span class="nc"&gt;.nav&lt;/span&gt; &lt;span class="nt"&gt;ul&lt;/span&gt; &lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;border-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="nb"&gt;transparent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.nav&lt;/span&gt; &lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;border-bottom-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;black&lt;/span&gt; &lt;span class="cp"&gt;!important&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;✅ Good: calculated use with narrow scope&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.text-center&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt; &lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;p&gt;&lt;em&gt;Note: If you want to customize a CSS framework like Bootstrap that sometimes uses selectors with high specificity you may not have a choice&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Avoid chaining (or nesting) of selectors
&lt;/h2&gt;

&lt;p&gt;Especially with pre-processors like Sass, it is very easy to nest selectors which, when compiled to actual CSS, will be chained like this: &lt;code&gt;.a .b .c .d { ... }&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This might seem attractive because it helps you to write very specific CSS, but it also leads to bloated CSS. Let's say you have a &lt;code&gt;.list&lt;/code&gt; class which is used inside &lt;code&gt;.header&lt;/code&gt; and also inside &lt;code&gt;.footer&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;🚫 Bad: selectors are unnecessarily chained&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.list&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;list-style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.list&lt;/span&gt; &lt;span class="nc"&gt;.list-item&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;inline-block&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="nc"&gt;.list&lt;/span&gt; &lt;span class="nc"&gt;.list-item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin-right&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="nc"&gt;.footer&lt;/span&gt; &lt;span class="nc"&gt;.list&lt;/span&gt; &lt;span class="nc"&gt;.list-item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bold&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;✅ Good: using as few selectors as possible&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.list&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;list-style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.list-item&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;inline-block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.list--spaced&lt;/span&gt; &lt;span class="nc"&gt;.list-item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin-right&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="nc"&gt;.list--bold&lt;/span&gt; &lt;span class="nc"&gt;.list-item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bold&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;There are two problems with this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;To style the &lt;code&gt;.list-item&lt;/code&gt;, the &lt;code&gt;.list&lt;/code&gt; has to be carried along to match specificity.&lt;/li&gt;
&lt;li&gt;After a while you may be afraid to touch &lt;code&gt;.list .list-item&lt;/code&gt; for fear that you break the &lt;code&gt;.list-item&lt;/code&gt; in &lt;code&gt;.header&lt;/code&gt; or &lt;code&gt;.footer&lt;/code&gt; and have to undo it. You will probably end up writing any changes in &lt;code&gt;.header .list .list-item&lt;/code&gt; or &lt;code&gt;.footer .list .list-item&lt;/code&gt; directly, thus bloating your CSS and making it harder to keep a good overview.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The solution is not to use chaining/nesting with &lt;code&gt;.header&lt;/code&gt; and &lt;code&gt;.footer&lt;/code&gt; but to add modifier classes which can be used in connection with the &lt;code&gt;.list&lt;/code&gt; class instead. Now you can write an element like this inside your &lt;code&gt;.footer&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ul&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"list list--bold"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"list-item"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="ni"&gt;&amp;amp;copy;&lt;/span&gt; Lukas Hermann&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Not only does this reduce specificity (why use &lt;code&gt;.list .list-item&lt;/code&gt; if you can just use &lt;code&gt;.list-item&lt;/code&gt;), it only introduces higher specificity where we want it: when using a modifier.&lt;/p&gt;

&lt;p&gt;A note concerning this specific example: In the case of lists it is probably easier to use &lt;code&gt;.list li&lt;/code&gt; (and &lt;code&gt;.list--bold li&lt;/code&gt; respectively) to save yourself some classes in your HTML markup, but I wanted to make an example which is easy to understand.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: This principle lies at the heart of naming conventions like BEM which will be addressed more specifically below.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Don't combine element and class selectors
&lt;/h2&gt;

&lt;p&gt;When you start writing CSS it seems intuitive to keep your classes very specific. We all have been burned by the cascading nature of CSS and it can be upsetting if you make a change in your CSS intended for one small part of your site only to discover that you messed up the design of five other places.&lt;/p&gt;

&lt;p&gt;With this background, it makes sense to write selectors like &lt;code&gt;div.card a.link&lt;/code&gt; because we want to make sure that &lt;strong&gt;only&lt;/strong&gt; anchor tags with &lt;code&gt;.link&lt;/code&gt; inside a div with &lt;code&gt;.card&lt;/code&gt; will receive this styling. But doing this is like fighting windmills, but CSS features are not our enemy. As a rule, don't combine element and class selectors, ever! If you want to modify the styling of an element in a particular place, use a modifier class instead.&lt;/p&gt;

&lt;p&gt;🚫 Bad: mixing element and class selectors&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="nc"&gt;.link&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="nc"&gt;.link&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;green&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;✅ Good: using a modifier class instead&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.link&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.link--green&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;green&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The advantages of modifier classes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The purpose of the modification is easy to understand&lt;/li&gt;
&lt;li&gt;It's easy to change or remove&lt;/li&gt;
&lt;li&gt;It's easy to find all the places in your code where this modifier is used by doing a simple search for &lt;code&gt;link--green&lt;/code&gt; in your whole project&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Note: A probable exception to this role might be a &lt;code&gt;.btn&lt;/code&gt; component. If you want to make sure that an anchor tag &lt;code&gt;a.btn&lt;/code&gt; looks identical to a button tag &lt;code&gt;button.btn&lt;/code&gt; because these two elements behave a little different in browsers. But even then you may just as well add all the necessary styling to &lt;code&gt;.btn&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Organize your code by increasing specificity
&lt;/h2&gt;

&lt;p&gt;If two selectors have the same specificity, the latter will be used. Therefore, to play to the strengths of the CSS specificity feature, it makes sense to organize your CSS file by increasing specificity. Put your resets and element selectors first, your normal classes afterward, and finish with your utility classes like &lt;code&gt;.text-center&lt;/code&gt; or &lt;code&gt;.nowrap&lt;/code&gt; where you can then safely use &lt;code&gt;!important&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;🚫 Bad: unordered styles makes it easy to miss overwrites&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.text-center&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt; &lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.btn&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;green&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.btn&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* overwrites green */&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&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;✅ Good: ordering your styles roughly by specificity&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Elements */&lt;/span&gt;
&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Components */&lt;/span&gt;
&lt;span class="nc"&gt;.btn&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;green&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.box&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0px&lt;/span&gt; &lt;span class="m"&gt;3px&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt; &lt;span class="no"&gt;black&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Utilities */&lt;/span&gt;
&lt;span class="nc"&gt;.text-center&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt; &lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The advantages of ordering styles roughly by specificity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You will always overwrite less important styles with more important ones&lt;/li&gt;
&lt;li&gt;You have a rough guideline for where your things go inside your CSS file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Note: This principle was introduced as ITCSS by &lt;a href="https://csswizardry.com"&gt;Harry Robers&lt;/a&gt;. It is a really useful CSS methodology to handle large-scale products. Here is the &lt;a href="https://www.creativebloq.com/web-design/manage-large-css-projects-itcss-101517528"&gt;article introducing ITCSS&lt;/a&gt;. Harry even created a &lt;a href="https://csswizardry.com/2018/11/itcss-and-skillshare/"&gt;course on Skillshare&lt;/a&gt; just recently.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Use few properties per class
&lt;/h2&gt;

&lt;p&gt;As a general rule, the more properties a class has, the less likely you are going to reuse it. Simply because of the fear that some of the many properties will not fit your other use case and you have to undo them, thus you might even end up writing another class with very similar properties.&lt;/p&gt;

&lt;p&gt;A good way to know if your classes are too bloated:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Simply observing yourself how many resets (like &lt;code&gt;margin: 0;&lt;/code&gt;) you are writing to undo other classes properties&lt;/li&gt;
&lt;li&gt;If you feel uncomfortable about reusing classes or if feel bad about adding another property to a class, it's a sign this class is too bloated&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Classes become bloated because many different concerns (aesthetics, spacing, typography) are packed together. A great way to improve this, even without dropping any properties, is to simply break it up into its different concerns.&lt;/p&gt;

&lt;p&gt;🚫 Bad: bloated, properties of different concerns are mixed&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;5px&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="no"&gt;black&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;2rem&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;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;14px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;line-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;small&gt;&lt;em&gt;Note: The bloated example is not overly bloated yet, but I think it brings the point across.&lt;/em&gt;&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;✅ Good: fewer properties keeps classes reusable&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3px&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;5px&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="no"&gt;black&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;2rem&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.spacer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.text-small&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;14px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;line-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the good example, the &lt;code&gt;.card&lt;/code&gt; class only contains the properties which specifically define its aesthetics. The aspects of spacing and typography are outsourced into their own classes. Having broken up the class like this you can easily see how to reuse each of those classes and even extend them and add more classes like &lt;code&gt;.spacer-large&lt;/code&gt; or &lt;code&gt;.text-tiny&lt;/code&gt; which will be very useful.&lt;/p&gt;

&lt;p&gt;Yes, this means that you have to add more classes in your HTML like so &lt;code&gt;&amp;lt;div class="card spacer text-small"&amp;gt;&lt;/code&gt;, and that's okay. It is much more comfortable, especially in the long run, to use such classes.&lt;/p&gt;

&lt;p&gt;Some classes need a lot of properties, for example, a &lt;code&gt;.button&lt;/code&gt; class has to unset many user agent (browser) styles for both, the &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; and the &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; tag. Therefore this rule should not be followed religiously for every case.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Tipp: Most CSS frameworks come equipped with a good set of reusable utility classes, &lt;a href="https://tailwindcss.com/docs/spacing/"&gt;watch&lt;/a&gt; &lt;a href="https://getbootstrap.com/docs/4.3/utilities/spacing/"&gt;out&lt;/a&gt; &lt;a href="https://foundation.zurb.com/sites/docs/prototyping-utilities.html#margin-helpers"&gt;for&lt;/a&gt; &lt;a href="https://getuikit.com/docs/margin"&gt;them&lt;/a&gt; and use them!&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Don't worry about sorting your properties
&lt;/h2&gt;

&lt;p&gt;This one is a bit opinionated. Brad Frost did a survey on twitter how people order their CSS properties:&lt;/p&gt;


&lt;blockquote class="ltag__twitter-tweet"&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--anNBL6Tn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/907811115459125248/i8AzK6gR_normal.jpg" alt="Brad Frost profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Brad Frost
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        @brad_frost
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P4t6ys1m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      Having fun debating different clustering of CSS properties. How do you do it? Alphabetical? Clustered by type (box model, positioning, typography, etc)? Train wreck?
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      14:20 PM - 05 Feb 2019
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1092790155700781056" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-reply-action.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1092790155700781056" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-retweet-action.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      13
      &lt;a href="https://twitter.com/intent/like?tweet_id=1092790155700781056" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-like-action.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
      140
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;p&gt;Most people answered that they are grouping properties by some common traits like positioning, display, or color. Some may be OCD about it and sort it alphabetically. Personally, I have tried these different methods and haven't found any of them particularly useful in the long run. I basically always do scrambled egg ... or how Brad Frost put it, "train wreck".&lt;/p&gt;

&lt;p&gt;If your classes have many properties some sorting rules usually become imperative to maintain an overview. But if you keep your classes slim, like suggested in point 7, it is really not necessary. Simply abide by some simple rules (like layout first, aesthetics last), and don't worry too much about the order otherwise.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Follow a naming convention like BEM
&lt;/h2&gt;

&lt;p&gt;Some of the code examples in this article are using the BEM naming convention. I found it to be very helpful and recommend it wholeheartedly. It's easy to learn! Quickly head to &lt;a href="http://getbem.com/naming/"&gt;this small introduction with good code examples of the BEM naming convention&lt;/a&gt; to get the idea.&lt;/p&gt;

&lt;p&gt;Here are two points I struggled with at the beginning with BEM.&lt;/p&gt;

&lt;h3&gt;
  
  
  Don't nest elements
&lt;/h3&gt;

&lt;p&gt;If you have a title within a header within a card, only "nest" maximum one level deep like so:&lt;/p&gt;

&lt;p&gt;🚫 Nesting BEM selector produces ugly classes&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="nc"&gt;.card__header&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="nc"&gt;.card__header__title&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;✅ Nesting BEM only one level deep is better&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="nc"&gt;.card__header&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="nc"&gt;.card__title&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  It's best to use modifiers only on root elements
&lt;/h3&gt;

&lt;p&gt;Modifiers on children can be used, but they make it hard to remember which child has which modifier. If possible, apply the modifier to the root element, this will keep your HTML markup and your CSS cleaner and therefore easier to see which modifiers are used or available.&lt;/p&gt;

&lt;p&gt;🚫 Using BEM modifiers on children get's messy&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.card__header--large&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;2em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.card__content--large&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;0&lt;/span&gt; &lt;span class="m"&gt;2em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.card__footer--large&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;2em&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;✅ Restricting BEM modifiers to root elements is cleaner&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.card--large&lt;/span&gt; &lt;span class="nc"&gt;.card__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;2em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.card--large&lt;/span&gt; &lt;span class="nc"&gt;.card__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;0&lt;/span&gt; &lt;span class="m"&gt;2em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.card--large&lt;/span&gt; &lt;span class="nc"&gt;.card__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;2em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  10. Avoid using shorthands if possible
&lt;/h2&gt;

&lt;p&gt;When defining a background color it is very common to just use shorthands like &lt;code&gt;background: gray;&lt;/code&gt;. It is important to know, however, that this shorthand reset's all other background properties, like &lt;code&gt;background-position&lt;/code&gt; and so on, to &lt;code&gt;initial&lt;/code&gt;. Similar case with other shorthands like &lt;code&gt;border&lt;/code&gt; and &lt;code&gt;margin&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This causes problems only in the rarest of cases, but if it does, it will be very hard to debug. It is therefore best practice to &lt;strong&gt;only change as little as necessary&lt;/strong&gt;. Be safe and use &lt;code&gt;background-color&lt;/code&gt; etc., the prevented headache is worth the extra characters.&lt;/p&gt;

&lt;p&gt;🚫 Using shorthands can have unintended side effects&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.card&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="n"&gt;lightgray&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;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;2rem&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;✅ Using verbose properties helps prevent side effects&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;lightgray&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin-left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin-right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;p&gt;&lt;em&gt;Further reading: Harry Roberts makes a great case for this in &lt;a href="https://csswizardry.com/2016/12/css-shorthand-syntax-considered-an-anti-pattern/"&gt;CSS Shorthand Syntax Considered an Anti-Pattern&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  11. Keep presentation (CSS), semantics (HTML) and behavior (JS) separate
&lt;/h2&gt;

&lt;p&gt;I often see styling tied to ids or elements (like &lt;code&gt;#nav&lt;/code&gt; or &lt;code&gt;.nav ul li&lt;/code&gt;), or javascript behavior tied to a class (like &lt;code&gt;document.getElementsByClassName(".nav")&lt;/code&gt;). However, if you do this you rob yourself of the flexibility to keep presentation (CSS), semantics (HTML), and behavior (JS) separate. You want to be able to style something as a button, regardless if it is an &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; (note that the latter is not good for accessibility). Or if you create a navbar, you want to be able to use &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt;-tags or &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;-tags depending on the necessary semantics, without losing your styling or have to change the CSS.&lt;/p&gt;

&lt;p&gt;To achieve this use ids for javascript (as originally intended), or better, &lt;code&gt;data&lt;/code&gt;-attributes like so: &lt;code&gt;document.querySelectorAll('[data-nav]');&lt;/code&gt; and don't mingle the &lt;code&gt;button&lt;/code&gt; element selector with your styles. This gives you the freedom to change either semantics, presentation, or behavior independently without having to worry about the other two.&lt;/p&gt;

&lt;p&gt;🚫 Bad: mixing presentation and behavior&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn btn-login"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Login&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementsByClassName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.btn-login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&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="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
  &lt;span class="nc"&gt;.btn-login&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;green&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;/style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;✅ Good: presentation and behavior are kept separate&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn btn-green"&lt;/span&gt; &lt;span class="na"&gt;data-login&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Login&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[data-login]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&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="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
  &lt;span class="nc"&gt;.btn-green&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;green&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;/style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Exception: There are reasons to use element selectors for styling. For example, if you intentionally set global presets, like a reset or change the default link color. But be careful not to set presets that you find yourself overwriting all the time.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>css</category>
    </item>
    <item>
      <title>404 Error Page and Redirect with Nuxt</title>
      <dc:creator>Lukas Hermann</dc:creator>
      <pubDate>Mon, 28 Sep 2020 05:58:28 +0000</pubDate>
      <link>https://dev.to/lhermann/404-error-page-and-redirect-with-nuxt-1c05</link>
      <guid>https://dev.to/lhermann/404-error-page-and-redirect-with-nuxt-1c05</guid>
      <description>&lt;p&gt;404 Error pages are very easy with Nuxt, but it took me long enough to find a how-to guide that I decided to write my own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom 404 Error Page
&lt;/h2&gt;

&lt;p&gt;The default Nuxt error page, that you probably have seen already, looks like this.&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%2Fcv30vlyhqaz26o41dojg.jpg" 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%2Fcv30vlyhqaz26o41dojg.jpg" alt="Nuxt default error page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To write your custom error page simply create the file &lt;code&gt;layouts/error.vue&lt;/code&gt;. Here is an example:&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;section&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;404 Page not Found&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Use the documentation of &lt;a href="https://nuxtjs.org/guide/views#error-page" rel="noopener noreferrer"&gt;error pages&lt;/a&gt; and the source code of the &lt;a href="https://github.com/nuxt/nuxt.js/blob/dev/packages/vue-app/template/components/nuxt-error.vue" rel="noopener noreferrer"&gt;default error page&lt;/a&gt; as reference.&lt;/p&gt;

&lt;h2&gt;
  
  
  404 Redirect
&lt;/h2&gt;

&lt;p&gt;The above works nicely for routes that don't exist, but sometimes we want to redirect to the 404 page from another page programmatically.&lt;/p&gt;

&lt;p&gt;In this example from my personal site Vue checks if the &lt;code&gt;404-error-page-and-redirect-with-nuxt.md&lt;/code&gt; file exists to display the article. If no markdown file is found the user is redirected to the 404 page.&lt;/p&gt;

&lt;p&gt;To achieve this I import the &lt;code&gt;error&lt;/code&gt; function in my &lt;code&gt;asyncData&lt;/code&gt; hook. If the server cannot find the file it forwards to the 404 page with &lt;code&gt;error({ statusCode: 404 })&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&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="err"&gt;\\&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;asyncData &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;params&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="k"&gt;try&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;await&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`~/writing/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.md`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Article not found&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="err"&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;Use the documentation for &lt;a href="https://nuxtjs.org/guide/async-data#handling-errors" rel="noopener noreferrer"&gt;Handling Errors&lt;/a&gt; in &lt;code&gt;asyncData&lt;/code&gt; as reference.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>vue</category>
      <category>nuxt</category>
    </item>
    <item>
      <title>How to use Async/Await with Vue.js Components</title>
      <dc:creator>Lukas Hermann</dc:creator>
      <pubDate>Tue, 22 Sep 2020 19:22:10 +0000</pubDate>
      <link>https://dev.to/lhermann/how-to-use-async-await-with-vue-js-components-2j4k</link>
      <guid>https://dev.to/lhermann/how-to-use-async-await-with-vue-js-components-2j4k</guid>
      <description>&lt;p&gt;In the beginning, it can be confusing to handle Vue's opinionated single file templates and how to use the javascript functions you know and love. But fear not, it is very easy.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Created Hook
&lt;/h1&gt;

&lt;p&gt;The created hook is a &lt;a href="https://vuejs.org/v2/guide/instance.html#Lifecycle-Diagram"&gt;lifecycle hook&lt;/a&gt;, a method that is called when the template is created for the first time, but before it is mounted.&lt;/p&gt;

&lt;p&gt;We can simply declare the &lt;code&gt;created ()&lt;/code&gt; method as &lt;code&gt;async&lt;/code&gt; and perform our asynchronous actions inside. In this example, we are loading a list of users.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Don't forget to handle the &lt;code&gt;null&lt;/code&gt; state of users until the data is available. Use &lt;code&gt;v-if="users"&lt;/code&gt; in your template or better, add a loading animation&lt;/em&gt;{.text-gray-600}&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&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="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;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;created&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://reqres.in/api/users&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&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="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&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;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;users&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;h1&gt;
  
  
  The Mounted Hook
&lt;/h1&gt;

&lt;p&gt;The mounted hook is almost identical to the created hook but fires after the component was mounted (added to the DOM). The created hook is generally preferred for API calls.&lt;/p&gt;

&lt;p&gt;Just like above, we can simply make the &lt;code&gt;mounted ()&lt;/code&gt; method async.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&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="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;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;mounted&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://reqres.in/api/users&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&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="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&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;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;users&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;h1&gt;
  
  
  Methods
&lt;/h1&gt;

&lt;p&gt;Vue allows any method to be an async method. Here is an example with data requested per click on a button.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click=&lt;/span&gt;&lt;span class="s"&gt;"loadUsers"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Load Users&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;v-if=&lt;/span&gt;&lt;span class="s"&gt;"users"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ users }}&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"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&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="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;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="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="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;loadUsers&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://reqres.in/api/users&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&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="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&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;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;users&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;h1&gt;
  
  
  Computed Properties
&lt;/h1&gt;

&lt;p&gt;Computed properties are the exception, Vue does not allow them to be async. There are ways to get around this restriction like the &lt;a href="https://www.npmjs.com/package/vue-async-computed"&gt;vue-async-computed&lt;/a&gt; plugin, but this is not a good practice.&lt;/p&gt;

&lt;p&gt;If you need an async computed property, then you probably made an architectural mistake in your component. With some experience, it becomes natural to handle computed properties as purely synchronous functions. All async operations should be done in methods.&lt;/p&gt;

&lt;p&gt;If you still find yourself needing an async computed property then try using a watcher instead.&lt;/p&gt;




&lt;h1&gt;
  
  
  Watchers
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://vuejs.org/v2/guide/computed.html#Watchers"&gt;Watchers&lt;/a&gt; can perform async operations when they detect changes in the data. Therefore watchers can cause computed properties to update with asynchronously.&lt;/p&gt;

&lt;p&gt;Here is an example where the computed prop returns a count of users. The watcher reloads the user list as soon as the &lt;code&gt;userRoles&lt;/code&gt; filter changes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&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="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;userRoles&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;admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;users&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;watch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;userRoles&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newRoles&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newRoles&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://reqres.in/api/users?roles=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&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="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&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;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&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;userCount&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&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;length&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;h1&gt;
  
  
  Nuxt &amp;amp; asyncData
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://nuxtjs.org/"&gt;Nuxt&lt;/a&gt; is a framework on top of Vue that makes the development of server-side rendered applications easier.&lt;/p&gt;

&lt;p&gt;Nuxt has a special method called &lt;code&gt;asyncData ()&lt;/code&gt; that is called before the component is created. This allows the server to pre-render the component before sending it to the client and it allows the client to pre-fetch data before the new component is shown to the user. This is especially interesting with page-level components where data can be fetched before the user even clicks on the next link creating the experience, similar to a mobile app, of instant page navigation.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Be aware that &lt;code&gt;asyncData ()&lt;/code&gt; doesn't have access to the component's instance and &lt;code&gt;this&lt;/code&gt; context, therefore the data must be returned instead.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&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="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;asyncData&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://reqres.in/api/users&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&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="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&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="nx"&gt;users&lt;/span&gt; &lt;span class="p"&gt;}&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;






&lt;p&gt;&lt;em&gt;I would love to hear from you if you liked the article or have any questions&lt;br&gt;
&lt;a href="https://twitter.com/_lhermann"&gt;Twitter&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>vue</category>
      <category>async</category>
    </item>
    <item>
      <title>Fixing the ERR_TOO_MANY_REDIRECTS error with Wordpress</title>
      <dc:creator>Lukas Hermann</dc:creator>
      <pubDate>Sat, 09 May 2020 23:04:06 +0000</pubDate>
      <link>https://dev.to/lhermann/fixing-the-errtoomanyredirects-error-with-wordpress-2h33</link>
      <guid>https://dev.to/lhermann/fixing-the-errtoomanyredirects-error-with-wordpress-2h33</guid>
      <description>&lt;p&gt;Every Wordpress developer sooner or later faces the ERR_TOO_MANY_REDIRECTS problem. You navigate to the correct URL but instead of the Wordpress page you are greeted with an error like this (or a similar depending on the browser):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Kcob_9td--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/h6m6i586w5tm0aid8ooz.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Kcob_9td--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/h6m6i586w5tm0aid8ooz.jpg" alt="Chrome browser with redirect error"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  The Problem
&lt;/h1&gt;

&lt;p&gt;(Jump to the solution)&lt;/p&gt;

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

&lt;p&gt;Basically, a miscommunication is happening between your browser and Wordpress that goes something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sJu1i4xg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/93epk0effrn19wmfh7d0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sJu1i4xg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/93epk0effrn19wmfh7d0.png" alt="Simplified chat between browser and web server"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see this unfold in the network tab of your developer console. In Chrome, hit ⌘ + alt + I (F12 or Ctrl + Shift + I on Windows) to open the dev tools panel. Go to the "Network" tab, make sure "Preserve log" and "Disable cache" are checked, and then reload the page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EKDTcnt7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2e43bemwpl3tgh9yl5u8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EKDTcnt7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2e43bemwpl3tgh9yl5u8.jpg" alt="Developer Tools network tab with redirects"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will see that your browser requests the page as instructed but gets a response with status 301 which stands for "permanent redirect" telling your browser that the page you are looking for is actually somewhere else. Let's open one of the entries in the list and check for the &lt;code&gt;location&lt;/code&gt; response header.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_bbAXp_T--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/62iusis0x4phs8f7a04q.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_bbAXp_T--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/62iusis0x4phs8f7a04q.jpg" alt="Developer Tools network tab showing details about a single redirect"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see that the &lt;code&gt;location: http://localhost:8081&lt;/code&gt; here is identical to the &lt;code&gt;Request URL: http://localhost:8081&lt;/code&gt;. Essentially the browser is asking for &lt;code&gt;http://localhost:8081&lt;/code&gt; but the server is not responding with the page but telling the browser to look in another location. So the browser doesn't know any better than to ask for the page in this "other" location, which is really the same URL all along. This is called a redirect loop. Eventually, your browser gets tired and gives up with a &lt;code&gt;TOO_MANY_REDIRECTS&lt;/code&gt; error.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note that &lt;code&gt;http://localhost:8081&lt;/code&gt; is a development server on my local computer which I use to reproduce the problem. In your case, it may be &lt;code&gt;https://phaserbeam-computers.com&lt;/code&gt; or so.&lt;/em&gt;{.text-gray-600}&lt;/p&gt;

&lt;h2&gt;
  
  
  So why does the server give this response?
&lt;/h2&gt;

&lt;p&gt;In 9 out of 10 cases this problem is caused by a reverse proxy. A reverse proxy is a server that sits in between your browser and Wordpress. This may have a variety of reasons, in my case, it is a webpack dev server, in your case, your hoster may use Nginx as a webserver for its ease and speed but reverse proxy the request to an Apache server so Wordpress can make use of the familiar &lt;code&gt;.htaccess&lt;/code&gt; file and the &lt;code&gt;mod_rewrite&lt;/code&gt; module.&lt;/p&gt;

&lt;p&gt;Whatever the setup, in reality, the above conversation looks more like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---nlSs_4h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/kwthtz8henb6ozb91td0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---nlSs_4h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/kwthtz8henb6ozb91td0.png" alt="Simplified chat between browser and webserver with proxy in between"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By asking for &lt;code&gt;https://example.com&lt;/code&gt; your browser is actually talking to a middleman (the reverse proxy) who then, in turn, asks for the server with Wordpress at another location. Wordpress usually deals with this very well except if the middleman changes the port, then Wordpress seems to panic.&lt;/p&gt;

&lt;p&gt;Log in to your webserver via SSH or FTP and add the following lines to your &lt;code&gt;wp-config.php&lt;/code&gt; file somewhere above the &lt;code&gt;/* That's all, stop editing! Happy publishing. */&lt;/code&gt; line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nb"&gt;print_r&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;die&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With these two lines, we instruct the server to print the &lt;code&gt;$_SERVER&lt;/code&gt; variable and then stop any further execution. When you now reload the page you should see some gibberish on the screen that looks like this:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: without the &lt;code&gt;die();&lt;/code&gt; the server continues execution of Wordpress' PHP files and the gibberish we want to see gets drowned by other stuff. By using it we only get the variable dumped on the screen.&lt;/em&gt;{.text-gray-600}&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Array
(
    [HTTP_X_FORWARDED_HOST] =&amp;gt; example.com
    [HTTP_X_FORWARDED_PROTO] =&amp;gt; https
    [HTTP_X_FORWARDED_PORT] =&amp;gt; 443
    [HTTP_X_FORWARDED_FOR] =&amp;gt; 93.184.216.34
    ...
    [HTTP_HOST] =&amp;gt; localhost:8000
    [REQUEST_SCHEME] =&amp;gt; http
    [SERVER_PORT] =&amp;gt; 8000
    [SERVER_ADDR] =&amp;gt; 127.0.0.1
    ...
)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this fictional case, the example.com wordpress site sits behind a reverse proxy. Originally the browser asked for &lt;code&gt;https://example.com&lt;/code&gt; on port &lt;code&gt;443&lt;/code&gt; (the default port for &lt;code&gt;https&lt;/code&gt; is &lt;code&gt;443&lt;/code&gt; and for &lt;code&gt;http&lt;/code&gt; is &lt;code&gt;80&lt;/code&gt;). But the reverse proxy forwards the request to some internal server on &lt;code&gt;localhost&lt;/code&gt; with port &lt;code&gt;8000&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Wordpress usually ignores the discrepancy between &lt;code&gt;example.com&lt;/code&gt; and &lt;code&gt;localhost&lt;/code&gt; but it gets really worked up on the port &lt;code&gt;8000&lt;/code&gt;. See, if Wordpress wants to serve its page securely over HTTPS, something every modern page should do, it will expect &lt;code&gt;https&lt;/code&gt; as request scheme and &lt;code&gt;443&lt;/code&gt; as the port. But it got &lt;code&gt;http&lt;/code&gt; and &lt;code&gt;8000&lt;/code&gt;. Thus it thinks the browser did a request for &lt;code&gt;http://example.com&lt;/code&gt; and will respond with a "301 Moved Permanently" to &lt;code&gt;https://example.com&lt;/code&gt; (note the &lt;code&gt;s&lt;/code&gt; in &lt;code&gt;https&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;But for your browser, this is exactly the same URL he just asked for.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Solution
&lt;/h1&gt;

&lt;p&gt;We must tell Wordpress he facts of the original request from the browser before the reverse proxy middleman messed things up for us.&lt;/p&gt;

&lt;p&gt;Fortunately, with the &lt;code&gt;HTTP_X_FORWARDED&lt;/code&gt; headers, the reverse proxy is kind enough to tell Wordpress what the browser originally asked for. We can look for these headers and then clear things up for Wordpress.&lt;/p&gt;

&lt;p&gt;If you have the common problem that you get the redirect error because you want to use the secure HTTPS instead of the insecure HTTP, then add these lines to your &lt;code&gt;wp-config.php&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'HTTP_X_FORWARDED_PROTO'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'HTTP_X_FORWARDED_PROTO'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;'https'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'HTTPS'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'on'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note: The &lt;code&gt;wp-config.php&lt;/code&gt; should be in your Wordpress root directory. Add the PHP snipped somewhere above the &lt;code&gt;/* That's all, stop editing! Happy publishing. */&lt;/code&gt; line&lt;/em&gt;{.text-gray-600}&lt;/p&gt;

&lt;p&gt;If, however, you are like me and get the error because you are using a webpack dev server or some other more complex setup, this snipped should do the trick:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'HTTP_X_FORWARDED_HOST'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'HTTP_X_FORWARDED_PORT'&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'HTTP_HOST'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"HTTP_X_FORWARDED_HOST"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'SERVER_PORT'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"HTTP_X_FORWARDED_PORT"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In any case, it is important to specify exactly at what URL Wordpress is available. You can do this inside the Wordpress settings, but I usually prefer to add these two lines to my &lt;code&gt;wp-config.php&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nb"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'WP_SITEURL'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'https://example.com'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'WP_HOME'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="s1"&gt;'https://example.com'&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 debug and test solutions regarding 301 permanent redirects make sure to clear your browser cache or keep the developer tools open with the "Network" tab and "Disable cache" checked.&lt;/p&gt;

&lt;p&gt;And with that, you should be good to go.&lt;/p&gt;

&lt;h1&gt;
  
  
  Your Solution doesn't work for me
&lt;/h1&gt;

&lt;p&gt;Then your problem is not a reverse proxy or you have an additional misunderstanding within Wordpress. I have seen cases where the redirect loop alternated between &lt;code&gt;https://example.com/&lt;/code&gt; and &lt;code&gt;https://example.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Check your plugins and your &lt;code&gt;.htaccess&lt;/code&gt; file. To troubleshoot I usually deactivate all plugins and if the error goes away reactivate them one by one until the troublemaker is found.&lt;/p&gt;

&lt;p&gt;Read the Let's diagnose part and check the networks tab of your developer tools to see precisely which redirects the server responds with. Among the response headers, there is also a &lt;code&gt;Server&lt;/code&gt; entry that often helps to identify which part of your web server is responsible for the redirect. For example, it may be your "Yoast" plugin.&lt;/p&gt;

</description>
      <category>php</category>
      <category>wordpress</category>
      <category>reverseproxy</category>
      <category>errors</category>
    </item>
    <item>
      <title>Vue.js Pattern for Async Requests: Using Renderless Components</title>
      <dc:creator>Lukas Hermann</dc:creator>
      <pubDate>Sun, 04 Aug 2019 19:32:04 +0000</pubDate>
      <link>https://dev.to/lhermann/vue-js-pattern-for-async-requests-using-renderless-components-3gd</link>
      <guid>https://dev.to/lhermann/vue-js-pattern-for-async-requests-using-renderless-components-3gd</guid>
      <description>&lt;p&gt;Most Vue apps need asynchronous HTTP requests and there are many ways to realize them: in the &lt;code&gt;mounted()&lt;/code&gt; lifecycle hook, in a method triggered by a button, within the store (when using &lt;a href="https://vuex.vuejs.org/"&gt;vuex&lt;/a&gt;) or in the &lt;code&gt;asyncData()&lt;/code&gt; and &lt;code&gt;fetch()&lt;/code&gt; methods (with &lt;a href="https://nuxtjs.org/"&gt;Nuxt&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;While a simple request is very easy with axios, we usually want to cover at least two additional states:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Show something to the user while the request is pending&lt;/li&gt;
&lt;li&gt;Handle errors gracefully&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Handling these states adds additional code and can quickly lead to code-duplication when having to implement many different requests.&lt;/p&gt;

&lt;h1&gt;
  
  
  Contents
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;Origin of the Idea&lt;/li&gt;
&lt;li&gt;HTTP requests: A typical example&lt;/li&gt;
&lt;li&gt;
The Async Renderless Component

&lt;ul&gt;
&lt;li&gt;Why not a mixin or directive?&lt;/li&gt;
&lt;li&gt;An applied example&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To cut right to the meat, jump to The Async Renderless Component.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Axios is used to make HTTP requests in this example, but it works just as well with any other library for AJAX requests. Also, this example uses this wonderful free Dog API: &lt;a href=""&gt;https://dog.ceo/dog-api/&lt;/a&gt; 🐶.&lt;/p&gt;

&lt;h1&gt;
  
  
  Origin of the Idea
&lt;/h1&gt;

&lt;p&gt;The idea is not my own, but borrowed from Vue.js creator Evan You &lt;a href="https://twitter.com/youyuxi"&gt;@youyuxi&lt;/a&gt; who voiced it secondarily while talking about Advanced Vue Components with Adam Whatan on the &lt;a href="http://www.fullstackradio.com/"&gt;Full Stack Radio&lt;/a&gt; Podcast during &lt;a href="http://www.fullstackradio.com/81"&gt;Episode 81&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  HTTP request in Vue Components: A typical example
&lt;/h1&gt;

&lt;p&gt;Let's start with a minimal example to request a random dog image. The &lt;code&gt;mounted()&lt;/code&gt; hook contains the axios call which populates the &lt;code&gt;image&lt;/code&gt; variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;example&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;el&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#example&lt;/span&gt;&lt;span class="dl"&gt;"&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;mounted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;axios&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://dog.ceo/api/breeds/image/random&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&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;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&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;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Simple enough. However, we want to show a loading animation and handle request errors. So in addition to the &lt;code&gt;image&lt;/code&gt; variable &lt;code&gt;pending: false&lt;/code&gt; and &lt;code&gt;error: null&lt;/code&gt; are added. The &lt;code&gt;mounted()&lt;/code&gt; hook then looks as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;example&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="nx"&gt;mounted&lt;/span&gt;&lt;span class="p"&gt;()&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;pending&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;axios&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://dog.ceo/api/breeds/image/random&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&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;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&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="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&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="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&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;pending&lt;/span&gt; &lt;span class="o"&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now a loading indicator can be shown for &lt;code&gt;pending === true&lt;/code&gt; and a basic error message can be displayed if &lt;code&gt;error !== null&lt;/code&gt;. It's really simple, but it can get tedious to implement this pending/success/error behavior repeatedly. Besides, if the request contains parameters that can be changed by the user, e.g. filters or sorting options, then the request has to move to a method which has to be called, whenever the parameters changes, to reload the data.&lt;/p&gt;

&lt;p&gt;One easy and effective way to abstract away this simple behavior and make it reusable is ...&lt;/p&gt;

&lt;h1&gt;
  
  
  The Async Renderless Component
&lt;/h1&gt;

&lt;p&gt;This component makes use of the incredibly versatile &lt;a href="https://vuejs.org/v2/guide/components-slots.html#Scoped-Slots"&gt;Scoped Slot feature&lt;/a&gt;. A slot is any piece of HTML that can be passed to a component, telling the component: "Here, render this somewhere". With scoped slots the component which receives the HTML snipped answers: "Awesome, I will put your HTML right there. And here is some data you can use with your snipped if you like".&lt;/p&gt;

&lt;p&gt;The Async Renderless component is just such a component that receives a snippet of HTML, a URL and parameters and answers: "Hey look, I am requesting this data for you, here is &lt;code&gt;data&lt;/code&gt;, &lt;code&gt;pending&lt;/code&gt; and &lt;code&gt;error&lt;/code&gt; for you to use."&lt;/p&gt;

&lt;p&gt;The Async Renderless Component in full:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;async&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="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;data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;pending&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;error&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="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="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;requestData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;()&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;requestData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;deep&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;mounted&lt;/span&gt;&lt;span class="p"&gt;()&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;requestData&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="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;requestData&lt;/span&gt;&lt;span class="p"&gt;()&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;pending&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;try&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;data&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="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&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;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;params&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;params&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;data&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;error&lt;/span&gt; &lt;span class="o"&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="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&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;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;;&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;pending&lt;/span&gt; &lt;span class="o"&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="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$scopedSlots&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;pending&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;pending&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;error&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;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&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;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;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt; I am using some javascript magic here: &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions"&gt;Arrow Functions&lt;/a&gt;, &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function"&gt;Async/Await&lt;/a&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch"&gt;try...catch&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The "renderless" happens in the &lt;code&gt;render()&lt;/code&gt; tag. Instead of an HTML tag, these components only renders the HTML snippet it receives in its slot as scoped slot, passing three data points to it: &lt;code&gt;pending&lt;/code&gt;, &lt;code&gt;error&lt;/code&gt; and &lt;code&gt;data&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;watch&lt;/code&gt; functions make sure that the data is reloaded whenever either &lt;code&gt;url&lt;/code&gt; or &lt;code&gt;params&lt;/code&gt; change.&lt;/p&gt;

&lt;p&gt;We use the async component inside our template like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;async&lt;/span&gt; &lt;span class="na"&gt;url=&lt;/span&gt;&lt;span class="s"&gt;"https://dog.ceo/api/breed/husky/images"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;v-slot:default=&lt;/span&gt;&lt;span class="s"&gt;"{ pending, error, data }"&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;v-if=&lt;/span&gt;&lt;span class="s"&gt;"pending"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Loading ...&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;v-else-if=&lt;/span&gt;&lt;span class="s"&gt;"error"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ error }}&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;v-else&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ data }}&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;/async&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Why a renderless component and not a mixin or directive?
&lt;/h2&gt;

&lt;p&gt;Components are not the only way to reuse code in Vue, another way is to use a &lt;a href="https://vuejs.org/v2/guide/mixins.html"&gt;Mixin&lt;/a&gt; or a &lt;a href="https://vuejs.org/v2/guide/custom-directive.html"&gt;Custom Directive&lt;/a&gt;. Both are fine ways to solve this problem. Renderless components utilizing scoped slots are operating the way Vue wants to work, it can be imported when needed just like you are used to with any other component. Thus it's a very explicit way to reuse code as opposed to mixins or directives which don't have to be included separately. In the end, it comes down to preference.&lt;/p&gt;

&lt;h2&gt;
  
  
  An applied example
&lt;/h2&gt;

&lt;p&gt;I constantly find myself implementing lists when working with APIs which usually feature things like pagination, filters, sorting and search. So I decided to put together a "real-life" example which renders a simple list of dog images with a very simple filter option for some different breeds (and a wrong API call to see the error state):&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/lhermann/embed/jgGxyQ?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Whenever one of the filter buttons is clicked the URL, which is passed to the async component, is updated with the appropriate breed. The async component takes care of the HTTP request. No more HTTP request logic is needed in the parent component, separation of concerns is obeyed, our minds are freed and the universe is in harmony 😄.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>vue</category>
      <category>async</category>
      <category>axios</category>
    </item>
  </channel>
</rss>
