<?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: Kenton Vizdos</title>
    <description>The latest articles on DEV Community by Kenton Vizdos (@kvizdos).</description>
    <link>https://dev.to/kvizdos</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%2F427990%2Ff110154f-c235-4e02-999d-48037fe653eb.jpeg</url>
      <title>DEV Community: Kenton Vizdos</title>
      <link>https://dev.to/kvizdos</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kvizdos"/>
    <language>en</language>
    <item>
      <title>How to deploy a static site for free</title>
      <dc:creator>Kenton Vizdos</dc:creator>
      <pubDate>Fri, 10 Jul 2020 16:55:00 +0000</pubDate>
      <link>https://dev.to/kvizdos/how-to-deploy-a-static-site-for-free-4ncc</link>
      <guid>https://dev.to/kvizdos/how-to-deploy-a-static-site-for-free-4ncc</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1ZF-Eh5B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/deploy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1ZF-Eh5B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/deploy.png" alt="How to deploy a static site for free"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every so often, I need to launch a quick landing page. Nothing too fancy, it's usually just a static site connected to a Google Forms (&lt;a href="https://blog.kentonvizdos.com/til-1-automated-google-forms/"&gt;learn how to add responses to a Google Forms from HTML&lt;/a&gt;), but I never want to spend too much time setting up SSL certs or DNS stuff.&lt;/p&gt;

&lt;h2&gt;
  
  
  Way #1- GitHub Pages
&lt;/h2&gt;

&lt;p&gt;GitHub Pages is a great way to publish your static website! It allows you to rapidly setup a page @ .github.io/. You can even set your portfolio page under .github.io if you create a repo called &lt;code&gt;&amp;lt;username&amp;gt;.github.io&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to setup GitHub Pages
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qa6Rfbmw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/image-23.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qa6Rfbmw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/image-23.png" alt="How to deploy a static site for free"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, you'll want to go to your repositories settings. Once you are there, scroll to the bottom until you see the "GitHub Pages" section. Now, it's as simple as selecting whether or not you want to use the entire &lt;code&gt;master&lt;/code&gt; branch, or if you just want to use the &lt;code&gt;/docs&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use master:&lt;/strong&gt; I use the entire master branch only when the repo is &lt;em&gt;just&lt;/em&gt; the website. If I have any dynamic content (or a mix of things in one repo), I opt to use the &lt;code&gt;/docs&lt;/code&gt; directory&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use /docs:&lt;/strong&gt; Mainly, &lt;code&gt;/docs&lt;/code&gt; is nice because it separates the dev code from production code. Also, if you are using something like JSDocs to automatically generate HTML doc pages (&lt;a href="https://blog.kentonvizdos.com/up-your-javascript-autocomplete-game-using-jsdocs/"&gt;learn how to do that here&lt;/a&gt;), having the /docs directory open is the only one you need!&lt;/p&gt;

&lt;p&gt;Also, if you don't want to use a github.io URL, you can specify a custom domain!&lt;/p&gt;

&lt;h2&gt;
  
  
  Way #2- PRAUXY
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gbovnTry--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/image-24.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gbovnTry--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/image-24.png" alt="How to deploy a static site for free"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you host a PRAUXY instance, launching a static site is as easy as filling out the GitHub repo URL! The nice part about using PRAUXY is that you can have certain sites that &lt;strong&gt;require&lt;/strong&gt; authentication to view.&lt;/p&gt;

&lt;p&gt;Once you fill out the form, it'll automatically start up a secure static server. Like GitHub Pages, you can also provide a custom URL to listen on. Unlike GitHub, you can specify a path to serve instead of just &lt;code&gt;/&lt;/code&gt; or &lt;code&gt;/docs&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Learn how to setup a PRAUXY instance:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;[&lt;/p&gt;

&lt;p&gt;kvizdos/PRAUXY&lt;/p&gt;

&lt;p&gt;PRAUXY is an open source web proxy with authentication baked in. Built with SendGrid, Termius, and GitHub Pro (provided by GitHub Education Pack!) - kvizdos/PRAUXY&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uPIa4SpL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.githubassets.com/favicons/favicon.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uPIa4SpL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.githubassets.com/favicons/favicon.svg" alt="How to deploy a static site for free"&gt;&lt;/a&gt;kvizdosGitHub&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--R723cTve--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://avatars2.githubusercontent.com/u/7881286%3Fs%3D400%26v%3D4" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--R723cTve--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://avatars2.githubusercontent.com/u/7881286%3Fs%3D400%26v%3D4" alt="How to deploy a static site for free"&gt;&lt;/a&gt;&lt;br&gt;
](&lt;a href="https://github.com/kvizdos/PRAUXY"&gt;https://github.com/kvizdos/PRAUXY&lt;/a&gt;)&lt;/p&gt;

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

&lt;p&gt;I use both of these methods. Personally, I prefer PRAUXY because I can add authentication and do a few more things than GitHub, but that may be a little bias, so choose whichever seems right for you! In the end, all either method is doing is providing a place to host a website.&lt;/p&gt;

&lt;p&gt;I hope I helped you learn a little bit about serving your websites to the world!&lt;/p&gt;

</description>
      <category>guides</category>
      <category>todayilearned</category>
    </item>
    <item>
      <title>Up your JavaScript autocomplete game using JSDocs</title>
      <dc:creator>Kenton Vizdos</dc:creator>
      <pubDate>Mon, 06 Jul 2020 16:55:00 +0000</pubDate>
      <link>https://dev.to/kvizdos/up-your-javascript-autocomplete-game-using-jsdocs-2a76</link>
      <guid>https://dev.to/kvizdos/up-your-javascript-autocomplete-game-using-jsdocs-2a76</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0Hzj_REw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/JSDocs.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0Hzj_REw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/JSDocs.jpg" alt="Up your JavaScript autocomplete game using JSDocs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note: I realize now that ${!isInSchool &amp;amp;&amp;amp; "not"} will return "false" in some cases and not "" like I expected (I've been writing a lot of React Native code lately).. I swear I tested it and it didn't show false, but I just reran it and it did. O well, too many screenshots to fix it.&lt;/p&gt;

&lt;p&gt;JavaScript is a great language, but it definitely has it's downfalls. One of the biggest complaints is that there is no strict-type checking, and that really starts to be noticed when autocomplete in systems like Intellisense have no idea what to suggest to you (especially in terms of writing functions with parameters).&lt;/p&gt;

&lt;p&gt;Let's take a look at some code to understand the problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  THE PROBLEM.
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--D96goBGV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/image.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--D96goBGV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/image.png" alt="Up your JavaScript autocomplete game using JSDocs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this code above, let's see what happens when we type in the function name.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5BkHZ_Zm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/image-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5BkHZ_Zm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/image-1.png" alt="Up your JavaScript autocomplete game using JSDocs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice how the Intellisense is saying the type for all of these parameters are "any"? While it's not a huge deal while typing in params, let's see what happens when we try to use a string function on the name param.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vZiTYWTV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/image-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vZiTYWTV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/image-2.png" alt="Up your JavaScript autocomplete game using JSDocs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thaaat.... doesn't help at all. Notice how there are no default string functions showing (things like toUpperCase, toLowerCase, etc). This is where JSDocs come in handy.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are JSDocs?
&lt;/h2&gt;

&lt;p&gt;JSDocs uses comments to annotate JavaScript. You can also add in extra descriptions and parameters (with types) to have Intellisense (or really any IDE) autocomplete.&lt;/p&gt;

&lt;p&gt;JSDocs support is built into most IDEs such as VSCode, but if they aren't inherently supported there are 3rd party plugins to make it work.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I use JSDocs?
&lt;/h2&gt;

&lt;p&gt;Writing JSDocs is as easy as pie! First, start the JSDocs syntax with &lt;code&gt;/**&lt;/code&gt; and end it with &lt;code&gt;*/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jUIMjgxK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/image-4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jUIMjgxK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/image-4.png" alt="Up your JavaScript autocomplete game using JSDocs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The basic syntax goes as such:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/**
 * Description of function
 *
 * &amp;lt;tags&amp;gt;
 */
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Make sure that the bullets after the first starting &lt;code&gt;/**&lt;/code&gt; have a space before them! Now that we know how to write the basic form of them, let's explore tag types.&lt;/p&gt;

&lt;p&gt;In the most basic form, JSDocs tags are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;@author&lt;/code&gt; - Developer's name&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@constructor&lt;/code&gt; - Marks a function as a constructor&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@deprecated&lt;/code&gt; - Marks a method as deprecated&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@exception&lt;/code&gt; - Synonym for &lt;code&gt;@throws&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@module&lt;/code&gt; - Identifies a member that is exported by the module&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@param&lt;/code&gt; - Documents a method parameter; a datatype indicator can be added between curly braces&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@private&lt;/code&gt; - Signifies that a member is private&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@returns&lt;/code&gt; - Documents a return value&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@return&lt;/code&gt; - Synonym for &lt;code&gt;@returns&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@see&lt;/code&gt; - Documents an association to another object&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@todo&lt;/code&gt; - Documents something that is missing/open&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@this&lt;/code&gt; - Specifies the type of the object to which the keyword &lt;code&gt;this&lt;/code&gt; refers within a function.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@throws&lt;/code&gt; - Documents an exception thrown by a method&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@version&lt;/code&gt; - Provides the version number of a library&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/JSDoc"&gt;Source&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's a ton of information. In the end, the most useful ones will be &lt;a class="comment-mentioned-user" href="https://dev.to/param"&gt;@param&lt;/a&gt;
, @return(s), and sometimes @module.&lt;/p&gt;

&lt;p&gt;By adding  an &lt;a class="comment-mentioned-user" href="https://dev.to/param"&gt;@param&lt;/a&gt;
 tag, we are telling the IDE which &lt;em&gt;type&lt;/em&gt; the variable &lt;em&gt;should&lt;/em&gt; be (however do note: this is not doing actual strong type checking. It is just used for auto complete and docs). It can come in handy quite a bit, however, since it lets you choose from type methods.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OeS3L764--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/image-5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OeS3L764--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/image-5.png" alt="Up your JavaScript autocomplete game using JSDocs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With basic params setup, let's check out what &lt;code&gt;name.&lt;/code&gt; will show now:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uR-hP51m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/image-6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uR-hP51m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/image-6.png" alt="Up your JavaScript autocomplete game using JSDocs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ahh, so much better! Instead of just random things, the IDE shows useful methods for the parameter type. Rather nice.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--E8MLEI98--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/image-7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--E8MLEI98--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/image-7.png" alt="Up your JavaScript autocomplete game using JSDocs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you start writing the function, the IDE will also show you the types (wahoo!) and the description of the function.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ADgZ1tKQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/image-8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ADgZ1tKQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/image-8.png" alt="Up your JavaScript autocomplete game using JSDocs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For documentation purposes, having &lt;code&gt;@returns void&lt;/code&gt; is good to know so you don't try and return it.&lt;/p&gt;

&lt;p&gt;It's almost like TypeScript.. but in normal JS 😲&lt;/p&gt;

&lt;p&gt;You may have noticed there is an &lt;code&gt;@author&lt;/code&gt; tag. In my opinion, with how good git blames are, it's not totally necessary, but I totally see why a big team would use them for quick on-the-fly knowledge of who wrote what. For me, they don't add enough value to enforce.&lt;/p&gt;

&lt;p&gt;Fun Fact: if you need to use an array as a param, you can use [] after the param name and it'll recommend array methods instead.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;@param {string[]} stringList&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Auto generating docs
&lt;/h2&gt;

&lt;p&gt;You're probably thinking, "well, it seems pretty helpful, but what else can it do?" Well, if you install the npm package for jsdoc using &lt;code&gt;npm install -g jsdoc&lt;/code&gt;, you can auto generate interactive HTML docs for your code!&lt;/p&gt;

&lt;p&gt;Once you've installed the jsdoc npm package, you can run the command &lt;code&gt;jsdoc test.js&lt;/code&gt; (or &lt;code&gt;jsdoc -r .&lt;/code&gt; to create all files) and get a beautiful output in the &lt;code&gt;out/&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YpnL02Vd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/image-9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YpnL02Vd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/image-9.png" alt="Up your JavaScript autocomplete game using JSDocs"&gt;&lt;/a&gt;Auto generated output&lt;/p&gt;

&lt;p&gt;If you go to the index.html page, you should see something that looks like the above, and if you click onto the "printInfo" section under "Global," you'll see something even cooler.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KKtRqFg8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/image-16.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KKtRqFg8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/image-16.png" alt="Up your JavaScript autocomplete game using JSDocs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wow! It shows the function, it's description, the parameters, types (along with description, if you put them &lt;code&gt;@param {type} name - description&lt;/code&gt;), source, and expected return.&lt;/p&gt;

&lt;p&gt;However, with this, there is a downside. If you are writing these for NodeJS and are using module.exports to export a function, it will still appear under "Global" even though it isn't. To fix this problem, let's add &lt;code&gt;/** @module helpers */&lt;/code&gt; to your file and rerun the command.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Y-CgAsLw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/image-17.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Y-CgAsLw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/image-17.png" alt="Up your JavaScript autocomplete game using JSDocs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VKsjk5wy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/image-18.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VKsjk5wy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/image-18.png" alt="Up your JavaScript autocomplete game using JSDocs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With that one module line, it now properly specifies where the functions belong. This is nice to know when you have multiple functions like in the example below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--I7iOH98o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/image-19.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--I7iOH98o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/image-19.png" alt="Up your JavaScript autocomplete game using JSDocs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A note on node_modules (or other directories you'd like to ignore)
&lt;/h2&gt;

&lt;p&gt;If you had the pleasure of running &lt;code&gt;jsdoc -r .&lt;/code&gt;, you'd quickly realize it was trying to build all of the docs for node_modules as well. We don't want that (usually). There is an easy fix: creating a jsdocs config file.&lt;/p&gt;

&lt;p&gt;First, create a .jsdoc.js file and fill it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;'use strict';

module.exports = {
    "source": {
        "exclude": ["node_modules"],
        "includePattern": ".+\\.js(doc|x)?$"
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, rerun the jsdoc command except as: &lt;code&gt;jsdoc -r . -c .jsdoc.js&lt;/code&gt;. There we go, no more node modules :)&lt;/p&gt;

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

&lt;p&gt;I just recently learned about JSDocs, but they'll definitely be in my back pocket from now on. In my opinion, the auto complete and extra detail you can provide is very useful as the readability is much better (also, being able to know which type a variable is meant to be is rather nice). If you want to become a JSDocs super user, you can also add ESLinting requirements to make sure they are written for everything. I have yet to make an ESLint config for it, but I probably will for some of my open source projects!&lt;/p&gt;

</description>
      <category>guides</category>
    </item>
    <item>
      <title>How to make your website look amazing when posted on social media</title>
      <dc:creator>Kenton Vizdos</dc:creator>
      <pubDate>Thu, 02 Jul 2020 06:23:33 +0000</pubDate>
      <link>https://dev.to/kvizdos/how-to-make-your-website-look-amazing-when-posted-on-social-media-3pdo</link>
      <guid>https://dev.to/kvizdos/how-to-make-your-website-look-amazing-when-posted-on-social-media-3pdo</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eftlNOrV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/2681C691-534F-413C-A870-D1D38D61ABBC.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eftlNOrV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/07/2681C691-534F-413C-A870-D1D38D61ABBC.png" alt="How to make your website look amazing when posted on social media"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ever wonder how websites get rich content working automatically when posted to social media?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Want to &lt;a href="https://twitter.com/hashtag/supercharge?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#supercharge&lt;/a&gt; your &lt;a href="https://twitter.com/hashtag/JavaScript?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#JavaScript&lt;/a&gt; debugging game? Check out my latest blog post to up your console.log() game to 💯&lt;a href="https://twitter.com/hashtag/100DaysOfCode?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#100DaysOfCode&lt;/a&gt; &lt;a href="https://t.co/FcjkSORmLF"&gt;https://t.co/FcjkSORmLF&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;— Kenton (&lt;a class="comment-mentioned-user" href="https://dev.to/kvizdos"&gt;@kvizdos&lt;/a&gt;
) &lt;a href="https://twitter.com/KVizdos/status/1277658960028413957?ref_src=twsrc%5Etfw"&gt;June 29, 2020&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Thanks to some fun meta tags, we can do this level of integration seamlessly. Also, some platforms (like Ghost, my blog platform of choice) have the ability to show different images based on the social media platform it is posted on (different for Twitter, Facebook, etc). Let's learn how to get these setup!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Basics: how does it work?
&lt;/h2&gt;

&lt;p&gt;Rich social media integration is based on Facebook's "Open Graph" meta tags. Normally, the tags are placed between the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; tag with any other meta tags.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use og tags?
&lt;/h2&gt;

&lt;p&gt;Mainly, og tags help increase your click through rate when posted online. Let's use an example: which one of these would you rather click?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I've been doing some research into &lt;a href="https://twitter.com/hashtag/SEO?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#SEO&lt;/a&gt; to improve my &lt;a href="https://twitter.com/hashtag/webdev?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#webdev&lt;/a&gt;. Over the course of my research, I've been writing a blog post.   &lt;/p&gt;

&lt;p&gt;If u want to learn the basics of SEO, my blog post covers most of the higher level stuff for getting into it! &lt;a href="https://t.co/JcXPk3aGEz"&gt;https://t.co/JcXPk3aGEz&lt;/a&gt;&lt;a href="https://twitter.com/hashtag/100DaysOfCode?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#100DaysOfCode&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;— Kenton (&lt;a class="comment-mentioned-user" href="https://dev.to/kvizdos"&gt;@kvizdos&lt;/a&gt;
) &lt;a href="https://twitter.com/KVizdos/status/1278372801230123009?ref_src=twsrc%5Etfw"&gt;July 1, 2020&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Or&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Want to &lt;a href="https://twitter.com/hashtag/supercharge?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#supercharge&lt;/a&gt; your &lt;a href="https://twitter.com/hashtag/JavaScript?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#JavaScript&lt;/a&gt; debugging game? Check out my latest blog post to up your console.log() game to 💯&lt;a href="https://twitter.com/hashtag/100DaysOfCode?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#100DaysOfCode&lt;/a&gt; &lt;a href="https://t.co/FcjkSORmLF"&gt;https://t.co/FcjkSORmLF&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;— Kenton (&lt;a class="comment-mentioned-user" href="https://dev.to/kvizdos"&gt;@kvizdos&lt;/a&gt;
) &lt;a href="https://twitter.com/KVizdos/status/1277658960028413957?ref_src=twsrc%5Etfw"&gt;June 29, 2020&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Using this data, we can pretty well estimate that almost everyone would select the second choice as it is more eye catching. Also, in my opinion, it helps show &lt;em&gt;what&lt;/em&gt; the website is actually trying to show you. You can even make your cards brand associated like Netlify:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Have you heard about our Build Plugins? Here's a great intro or re-introduction if you're familiar: &lt;a href="https://t.co/L9pdDsrV9s"&gt;https://t.co/L9pdDsrV9s&lt;/a&gt; &lt;a href="https://t.co/UDBCxMw3A3"&gt;pic.twitter.com/UDBCxMw3A3&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;— Netlify (@Netlify) &lt;a href="https://twitter.com/Netlify/status/1278441506832089088?ref_src=twsrc%5Etfw"&gt;July 1, 2020&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
&lt;p&gt;Think your large, e-commerce site won't work on the Jamstack? Well think again, and check out this post on how &lt;a href="https://twitter.com/bhavana1110?ref_src=twsrc%5Etfw"&gt;@bhavana1110&lt;/a&gt; breaks down the process: &lt;a href="https://t.co/fIHQYKOkhV"&gt;https://t.co/fIHQYKOkhV&lt;/a&gt; &lt;a href="https://t.co/aQyciYji9p"&gt;pic.twitter.com/aQyciYji9p&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;— Netlify (@Netlify) &lt;a href="https://twitter.com/Netlify/status/1278375328201744384?ref_src=twsrc%5Etfw"&gt;July 1, 2020&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;See how both of these follow strict branding with the left and an eye catching illustration on the right? Someone definitely got paid the big bucks to figure that one out.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I use these?
&lt;/h2&gt;

&lt;p&gt;In the most basic form, you can use these meta tags:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;og:title - This allows you to change the title to something different than the real page title. This is helpful if your website's proper title is something like "Kenton Vizdos Blog - how to make your website look amazing when posted on social media," but for simplicities sake you only want it to show the stuff after "Kenton Vizdos Blog -"&lt;/li&gt;
&lt;li&gt;og:site_name - This changes the displayed URL below the title&lt;/li&gt;
&lt;li&gt;og:description - Create a brief snippet of text to show when applicable. Instead of having the browser automatically try and parse it, you can make something truly custom to each site.&lt;/li&gt;
&lt;li&gt;og:image - Notice how in the tweet I posted above, the image had an orange background while the actual post had a white background? That would be thanks to og image tags. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once you choose the types of tags you want to use, you simply put them into a meta tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;html&amp;gt;
    &amp;lt;head&amp;gt;
        &amp;lt;title&amp;gt;Hello&amp;lt;/title&amp;gt;
        &amp;lt;meta property="og:title" content="My personal blog!" /&amp;gt;
        &amp;lt;meta property="og:description" content="How cool is this??" /&amp;gt;
    &amp;lt;/head&amp;gt;
    &amp;lt;body&amp;gt;
        &amp;lt;p&amp;gt;My awesome website&amp;lt;/p&amp;gt;
    &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Congrats! You now know the absolute basics of og tags, now it's time to go make your websites even better when posted online. But wait! There's more...&lt;/p&gt;

&lt;h2&gt;
  
  
  How to create platform specific og tags
&lt;/h2&gt;

&lt;p&gt;Most of the time, og tags will work on any platform that supports them, but if you want to create different images to match color schemes better, you can do so.&lt;/p&gt;

&lt;p&gt;Overall, Twitter has the best custom tags, so lets take a look. Remember, however, that if you use &lt;em&gt;twitter&lt;/em&gt; specific tags, it won't appear anywhere else. Having an extra "catch all" og tag may be good.&lt;/p&gt;

&lt;p&gt;Twitter was nice when they created these tags. Most of the tags listed above will work perfectly if you replace "og" with "twitter," however there are some good new ones you should know about. Mainly, &lt;code&gt;twitter:image:alt&lt;/code&gt; will let you specify an alt text for the card image. Having good acccessibility is always good!&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I validate these?
&lt;/h2&gt;

&lt;p&gt;Before posting on social media, it's important to double check your work. The good news is that platforms understand the need, so they provide platform specific tools to test them. Here's a list of the top 3:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://cards-dev.twitter.com/validator"&gt;Twitter Card validator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://blog.kentonvizdos.com/how-to-make-your-website-look-amazing-when-posted-on-social-media/"&gt;Facebook validator&lt;/a&gt; - Note: you must be logged in to use this for some reason&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/post-inspector/"&gt;Linkedin validator&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Overall, I hope next time you are making a website you will remember that a little bit more effort can make a website look 10x better when posted on social media.&lt;/p&gt;

&lt;p&gt;I hope I helped you learn something in this article, if you did, please share it along to your friends or click the "clap" button below.&lt;/p&gt;

</description>
      <category>guides</category>
      <category>technical</category>
    </item>
    <item>
      <title>What is SEO?</title>
      <dc:creator>Kenton Vizdos</dc:creator>
      <pubDate>Wed, 01 Jul 2020 17:36:00 +0000</pubDate>
      <link>https://dev.to/kvizdos/what-is-seo-5073</link>
      <guid>https://dev.to/kvizdos/what-is-seo-5073</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kYkRu15d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/06/6FAFE466-CEFF-4F2B-B3CD-970FB2D938EB.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kYkRu15d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/06/6FAFE466-CEFF-4F2B-B3CD-970FB2D938EB.png" alt="What is SEO?"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Search Engine Optimization, more commonly known as SEO, is the act of gaining more users  through organic and paid traffic.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the difference between paid and organic traffic?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Organic traffic is experienced through natural occurrences such as non-ad based Google Searches and other &lt;strong&gt;Search Engine Result Pages (SERPs)&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Paid traffic is traffic gained through paid ads or endorsements (Google AdSense, Twitter Ads, Facebook Ads, etc)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both have pros and cons to growing a website however paid traffic can get expensive fast, though it usually creates good conversion rates as it is much more targeted traffic, but you do lose out on initial click-through rates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why should you care about SEO?
&lt;/h2&gt;

&lt;p&gt;While you can pay for ads to display your page on more SERPs, they have quite a few downsides such as being expensive and they have a very low click-through rate being at only 2.8%. On the other end of paid traffic, organic traffic, it is much harder to grow on the rankings, but it is possible with good SEO techniques. Luckily, nowadays modern solutions such as the Alexa Page Rankings exist to show how you can market your site better. Meanwhile, there are two sides to SEO marketing, white and black hating.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;White hat SEO uses techniques and best practices to gain search engine rankings to provide more traffic&lt;/li&gt;
&lt;li&gt;Black hat SEO attempts to fool SERPs to provide your page instead of others, even though other sources may be more credible. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--thavOza3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/03/image.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--thavOza3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/03/image.png" alt="What is SEO?"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How do search engines work?
&lt;/h2&gt;

&lt;p&gt;While crawlers (spiders) provide valuable traffic, they also provide information on how easy the site is to navigate. Mainly, they use three main sources for their results:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Crawling- this is the act of going to websites and automatically finding links to visit which get added to queues to be later crawled again (it is a recursive function). Finally, once a page gets added to the queue, the spider will view a pages robots.txt which provides information on which pages the site owner would like to be in SERPs (though the spider does not need to follow the directions, but most do)&lt;/li&gt;
&lt;li&gt;Index- crawling provides a source of index, and there are tons of factors to how your site gets indexed, such as back-links, average viewership, bounce rate, session duration, and more.&lt;/li&gt;
&lt;li&gt;Rank- this is based on the index and is the final determination of where your page lands in the SERPs&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How to tell spiders where to crawl
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Robots.txt&lt;/li&gt;
&lt;li&gt;Meta tags in HTML (index/noindex, follow/nofollow, noarchive, etc)&lt;/li&gt;
&lt;li&gt;HTTP Headers&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What do SERPs want to see in a page?
&lt;/h2&gt;

&lt;p&gt;There is no magic way of getting a high index, but they do like promoting sites with content that is easy to find and easily "cardable" (aka when Google shows information from a site without the user actually needing to visit the site). Also, there are recommended page lengths per page. Finally, you can repeat words that you want to be promoted more. This is known as keyword stuffing and can sometimes add value to your index, but Google and other SERPs are taking action against this gray-area of SEO so tread with caution if you choose route.  &lt;/p&gt;

&lt;h2&gt;
  
  
  How do I get feedback on my site?
&lt;/h2&gt;

&lt;p&gt;Visit the Alexa rankings, the worlds most popular ranking and competition scouting site @ &lt;a href="http://alexa.com/"&gt;https://alexa.com/&lt;/a&gt;. For a more direct way, Google Analytics provide highly valuable information that gives very good information about your website and where traffic originates from. Also, the Alexa site is used to find search terms to market for and it'll also find what your competitors keywords are so you can launch targeted ads in their space to grow your business even faster. &lt;a href="https://trends.google.com/trends/?geo=US"&gt;Google Trends&lt;/a&gt; is also a nice site to see what is trending around the world, giving a site publisher valuable access in whats hot and trendy, so if you are a viral company, knowing that information is very important to understand what will go viral next.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optimizations you can make to your page
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Header tags- this allows a crawler to know what your site is about. It is very important to have hierarchical header tags, so keep h1s down and keep h2s for subcontent. &lt;/li&gt;
&lt;li&gt;Image optimization- load speeds are very important for who stays and who goes on your site, so if you have huge images on your site, people will leave as the page will not load in time. &lt;/li&gt;
&lt;li&gt;Alt text- the more alt text there is, the more SERPs see your page as being  which helps you get a higher rank.&lt;/li&gt;
&lt;li&gt;Upload a custom sitemap just for your page directly to SERPs- this will make sure all the pages you want to be added are added!&lt;/li&gt;
&lt;li&gt;Font size &amp;amp; other accessibility settings&lt;/li&gt;
&lt;li&gt;Clear URL name schemes and organization &lt;/li&gt;
&lt;li&gt;Use HTTPS when possible (and always.)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Test your site with Lightsail and Google Search Console
&lt;/h2&gt;

&lt;p&gt;Google Search Engine is a valuable resource to test the integrity, availability, and mobile usability of sites. Below is a test I did on my blog website and it gives you an automatic screenshot for different sized devices. The next image is a screenshot of the availability checklist&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--usR3HzqY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/03/image-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--usR3HzqY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/03/image-1.png" alt="What is SEO?"&gt;&lt;/a&gt;Mobile screenshot from Google Search Console&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MO5lfna_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/03/image-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MO5lfna_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/03/image-2.png" alt="What is SEO?"&gt;&lt;/a&gt;Availability screenshot&lt;/p&gt;

&lt;p&gt;After you run Google Search Console, you can run a Lightsail audit to test performance, best practices, accessibility, SEO, and more. On my blog, I scored quite a good score being above 90% for everything (except accessibility which I plan to fix)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zUHzyTOf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/03/image-4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zUHzyTOf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/03/image-4.png" alt="What is SEO?"&gt;&lt;/a&gt;Lightsail Performance Results&lt;/p&gt;

&lt;h2&gt;
  
  
  The last step: Link Authority
&lt;/h2&gt;

&lt;p&gt;Link Authority is a major step in being well-suited for SEO success. Link authority means that you are a "trusted" source which means that many sites have linked back to you and/ or that you've gotten a lot of social media traffic.&lt;/p&gt;

&lt;h2&gt;
  
  
  What did I learn from this experience?
&lt;/h2&gt;

&lt;p&gt;I learned that SEO is a difficult thing to master, however once you do, you will be much more suited to succeed, so it is worth it to take the time to properly learn the values of SEO.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Supercharging your JavaScript debugging with console methods</title>
      <dc:creator>Kenton Vizdos</dc:creator>
      <pubDate>Mon, 29 Jun 2020 17:35:00 +0000</pubDate>
      <link>https://dev.to/kvizdos/supercharging-your-javascript-debugging-with-console-methods-2a3a</link>
      <guid>https://dev.to/kvizdos/supercharging-your-javascript-debugging-with-console-methods-2a3a</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--r93qDdu0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/06/carbon-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--r93qDdu0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/06/carbon-2.png" alt="Supercharging your JavaScript debugging with console methods"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we all know, the &lt;strong&gt;only&lt;/strong&gt; way to debug JavaScript code is with console.log(), but do you know how you can supercharge your debug game with other console methods? Let’s take a look at all of the console logging methods!&lt;/p&gt;

&lt;h2&gt;
  
  
  General console.log()
&lt;/h2&gt;

&lt;p&gt;In the most basic form, console.log() will simply output a string of text to the JavaScript debug console which is present in most browsers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Warn and error logging
&lt;/h2&gt;

&lt;p&gt;To add extra zest to your logging, you can use console.warn() and console.error() to change the output color of your message (it works in most browsers to show a red or yellow background!)&lt;/p&gt;

&lt;h2&gt;
  
  
  Timing functions!
&lt;/h2&gt;

&lt;p&gt;Ever wanted to see how fast or slow a function evaluates in? Well, you could use some hacky things where you create some date variables at the beginning and end of a function, but there are NEW ways of doing things.&lt;/p&gt;

&lt;p&gt;Introducing..... console.time() and console.timeEnd()! Using these two functions, you can evaluate and output the duration of a method automatically.&lt;/p&gt;

&lt;p&gt;Also, if you want to add extra/multiple time functions inside of one method, you can use console.time(label) and console.timeEnd(label) which will let you nest timings as long as the labels are unique.&lt;/p&gt;

&lt;h2&gt;
  
  
  Asserting with console.assert()
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;console.assert(&amp;lt;expected true value&amp;gt;, &amp;lt;error message here&amp;gt;)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Asserting with the console is one of the coolest things you can do. If you normally write outputs of variables to see if they evaluate to something, “console.log(x == 1)”, you can refactor that into a really nice output using assertions. With assertions, instead of printing when the value is true, it’ll only return if it is false, and you can even return a fancy output!&lt;/p&gt;

&lt;p&gt;&lt;code&gt;console.assert(true == false, “True does not equal false!”)&lt;/code&gt; will output “True does not equal false!” but if you change it to &lt;code&gt;console.assert(true == true, “True does not equal true!”)&lt;/code&gt; will return nothing as the statement is true.&lt;/p&gt;

&lt;h2&gt;
  
  
  Console grouping
&lt;/h2&gt;

&lt;p&gt;Grouping can be useful in some situations. If you want to keep track of a ton of different functions, you can use console groupings instead of function pretends (e.g. you don’t need to say “functionName: ”). You can even collapse certain groups to clean up your output :)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;console.group(name)&lt;/code&gt; creates a group, and &lt;code&gt;console.groupEnd(name)&lt;/code&gt; finalizes and outputs the group. Pretty neat stuff!&lt;/p&gt;

&lt;p&gt;Supercharging console.log() is a crucial step in creating beautiful outputs of logs, so I hope you learned something helpful in this article. If you learned something, please let me know by tweeting me, &lt;a class="comment-mentioned-user" href="https://dev.to/kvizdos"&gt;@kvizdos&lt;/a&gt;
!&lt;/p&gt;

</description>
      <category>testing</category>
    </item>
    <item>
      <title>TIL 2: How to add a transparent video to a web page</title>
      <dc:creator>Kenton Vizdos</dc:creator>
      <pubDate>Tue, 16 Jun 2020 01:27:20 +0000</pubDate>
      <link>https://dev.to/kvizdos/til-2-how-to-add-a-transparent-video-to-a-web-page-1g2h</link>
      <guid>https://dev.to/kvizdos/til-2-how-to-add-a-transparent-video-to-a-web-page-1g2h</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TtsZsaIH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/06/carbon--1-.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TtsZsaIH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/06/carbon--1-.png" alt="TIL 2: How to add a transparent video to a web page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Today, I released the &lt;a href="https://go.prauxy.app"&gt;PRAUXY GO&lt;/a&gt; launch page. For history's sake, here is a screenshot:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oIg2V1cB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/06/image-7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oIg2V1cB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/06/image-7.png" alt="TIL 2: How to add a transparent video to a web page"&gt;&lt;/a&gt;PRAUXY GO Launch Page&lt;/p&gt;

&lt;p&gt;This time, I decided to try something new. While making the launch video, I was creating a word cloud and thought: how could I put this word cloud in the header of the launch page? In my opinion, it'd make the page pop a little bit more than usual. For those of you who haven't seen the PRAUXY GO launch video, here it is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Interested in &lt;a href="https://twitter.com/hashtag/coding?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#coding&lt;/a&gt; on your iPad?&lt;br&gt;&lt;br&gt;
Today, I'm opening the waiting list for &lt;a href="https://twitter.com/hashtag/PRAUXYGO?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#PRAUXYGO&lt;/a&gt;, a revolutionary iPad IDE for &lt;a href="https://twitter.com/hashtag/developers?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#developers&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;This &lt;a href="https://twitter.com/hashtag/IDE?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#IDE&lt;/a&gt; currently supports &lt;a href="https://twitter.com/hashtag/NodeJS?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#NodeJS&lt;/a&gt; and most things &lt;a href="https://twitter.com/hashtag/webdev?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#webdev&lt;/a&gt;, but the language support is growing 🔥&lt;a href="https://twitter.com/hashtag/code?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#code&lt;/a&gt; on an &lt;a href="https://twitter.com/hashtag/ipad?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#ipad&lt;/a&gt;&lt;a href="https://t.co/3GRTrDHTyj"&gt;https://t.co/3GRTrDHTyj&lt;/a&gt; &lt;a href="https://t.co/wxirJB7QqY"&gt;pic.twitter.com/wxirJB7QqY&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;— Kenton (&lt;a class="comment-mentioned-user" href="https://dev.to/kvizdos"&gt;@kvizdos&lt;/a&gt;
) &lt;a href="https://twitter.com/KVizdos/status/1272593854588497921?ref_src=twsrc%5Etfw"&gt;June 15, 2020&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;My first thought to creating a video in the header was to use an animated GIF, however I quickly learned that they do not support transparent backgrounds :(&lt;/p&gt;

&lt;p&gt;Feeling a little stumped, I took a break and came back after a little while. After remembering creating some transparent videos before for some OBS overlays, I took to Google and learned about transparent webm's using VP8 and VP9 encoding. There we go!&lt;/p&gt;

&lt;p&gt;After I learned about that, I downloaded a questionable extension for Adobe After Effects and exported a new transparent webm file. Wahooo! While looking over the docs, I did notice that the browser compatibility was a little lacking, but not horrible. Overall, it didn't have support for IE and Safari, but using the HTML video tag's poster attribute, I managed to create some workarounds.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yX9L-So1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/06/image-8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yX9L-So1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/06/image-8.png" alt="TIL 2: How to add a transparent video to a web page"&gt;&lt;/a&gt;Webm browser compatibility as of 6/15/2020&lt;/p&gt;

&lt;p&gt;So, once I exported my video and moved it into an assets directory, I started writing some video tags.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;video autoplay muted&amp;gt;
    &amp;lt;source src="assets/cloud.webm" type='video/webm'&amp;gt;
&amp;lt;/video&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Aaaaannnd when I checked the website... it didn't work. Nothing showed. I was rather confused. Turns out, you to add a few things to the &lt;code&gt;type&lt;/code&gt; attribute as of now because of compatibility. Without adding the codecs piece to the type attribute, it will not work.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;video autoplay muted&amp;gt;
    &amp;lt;source src="assets/cloud.webm" type='video/webm;codecs="vp8, vorbis"'&amp;gt;
&amp;lt;/video&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Nowwwwww, it still didn't work, but at least it displayed an initial frame. It would play if I added &lt;code&gt;controls&lt;/code&gt; to the video and manually played it, but as many of you know, Chrome is heavily restricting the amount of autoplay content out there.&lt;/p&gt;

&lt;p&gt;Now I was very stumped, so I did the only right thing to do: searched Google. I came across this answer on StackOverflow &lt;a href="https://stackoverflow.com/a/56972239/6457558"&gt;https://stackoverflow.com/a/56972239/6457558&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After changing up my code to reflect it, I got this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;video onloadedmetadata="this.muted = true" playsinline autoplay muted&amp;gt;
    &amp;lt;source src="assets/cloud.webm" type='video/webm;codecs="vp8, vorbis"'&amp;gt;
&amp;lt;/video&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It turns out, Chrome (and most browsers) do not play video until a page is interacted with (and more specifically, the exact element). The work around? Muted video. But, just adding &lt;code&gt;muted&lt;/code&gt; gets most browsers, but not all of them, so you need to manually set some object variables on the metadata load.&lt;/p&gt;

&lt;p&gt;If you do some testing now, you'll realize it works really well on &lt;em&gt;most&lt;/em&gt; browsers, but Safari and IE are still lacking behind. To fix this, I remembered that you can supply a &lt;code&gt;poster&lt;/code&gt; attribute to a &lt;code&gt;video&lt;/code&gt; tag. This allows the browser to fall back to a different image if the video fails to load and it'll also show before content plays as it loads the video (especially if you enable manual starting w/ &lt;code&gt;controls&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Oh, and as some of you are probably wondering: doesn't this add a ton of weight to a website? Well, not exactly. My video was simply 1.5 seconds at 24 fps @ 1280x720 (I chose 1280x720 because I knew it would never be displayed full screen. I'm sure I could reduce the size more if I needed to) with a grayscale coloring. In my use, the file ended up being 298 KB! Comparing that to a still frame I used as the poster which was 226 KB, I'd say it's not too horrible. You can always lazy load these or simply not display them on slow connections if you see fit. Als0, I feel like there is a very small use case for when to actually use videos, and when you do I really don't think it should be a long one, especially on a web page (unless your site is made for content delivery, most things can be done with CSS animations now adays. I was just lazy).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IFldlOn2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/06/cloudfallback.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IFldlOn2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/06/cloudfallback.png" alt="TIL 2: How to add a transparent video to a web page"&gt;&lt;/a&gt;Word cloud image for reference (226 KB)&lt;/p&gt;

&lt;p&gt;Pretty simple TIL today, but it's one of those things that I'm sure one day, for a very oddly specific need, I will need to come back to. And hopefully, I helped one of you!&lt;/p&gt;

&lt;p&gt;Any feedback is greatly appreciated, tweeting me, &lt;a class="comment-mentioned-user" href="https://dev.to/kvizdos"&gt;@kvizdos&lt;/a&gt;
, is the best way to do so!&lt;/p&gt;

&lt;p&gt;Thanks for reading &amp;amp; a share never hurts :)&lt;/p&gt;

</description>
      <category>todayilearned</category>
    </item>
    <item>
      <title>TIL 1: How to POST to a Google Form using HTML</title>
      <dc:creator>Kenton Vizdos</dc:creator>
      <pubDate>Mon, 15 Jun 2020 01:57:33 +0000</pubDate>
      <link>https://dev.to/kvizdos/til-1-how-to-post-to-a-google-form-using-html-10ia</link>
      <guid>https://dev.to/kvizdos/til-1-how-to-post-to-a-google-form-using-html-10ia</guid>
      <description>&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%2Fblog.kentonvizdos.com%2Fcontent%2Fimages%2F2020%2F06%2FTIL1Blog.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.kentonvizdos.com%2Fcontent%2Fimages%2F2020%2F06%2FTIL1Blog.png" alt="TIL 1: How to POST to a Google Form using HTML"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So today, I was creating an input section on a new website and I really wanted to automatically submit the responses to a Google Form. In the end, I wanted to do a basic HTML form with an action to Google, and luckily after a little testing I figured it out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And yes. I do know this probably isn't the safest way to do things, but it was the most efficient and easiest for a simple POC I am making.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;From the start, I tried to directly post to a Google Form with fields I assumed would work.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

POST /forms/d/e/&amp;lt;formID&amp;gt;? HTTP/1.1
Host: docs.google.com
Content-Type: application/json
{"name": "Kenton", "email": "test@test.com"}


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

&lt;/div&gt;

&lt;p&gt;However, I was quickly met with a 404 :( Nothing too scary though, lets see if adding view form would work.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

POST /forms/d/e/&amp;lt;formID&amp;gt;/viewform HTTP/1.1
Host: docs.google.com
Content-Type: application/json

{"name": "Kenton", "email": "test@test.com"}


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

&lt;/div&gt;

&lt;p&gt;Presumably, this fails. It sends a 405 HTTP code, meaning that the method wasn't allowed. This was caused by sending a POST request to a GET endpoint.&lt;br&gt;&lt;br&gt;
Stumped, I decided to go to Google. But, instead of just Googling things, lets learn &lt;em&gt;how&lt;/em&gt; to get the correct endpoint when you aren't exactly sure.&lt;/p&gt;

&lt;p&gt;As an example, here is a test form that I setup. It simply captures a name and email.&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%2Fblog.kentonvizdos.com%2Fcontent%2Fimages%2F2020%2F06%2Fimage.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.kentonvizdos.com%2Fcontent%2Fimages%2F2020%2F06%2Fimage.png" alt="TIL 1: How to POST to a Google Form using HTML"&gt;&lt;/a&gt;Test Form example&lt;/p&gt;

&lt;p&gt;Now that we have our form, let's open up the preview. After we have the preview open, open the Chrome Developer Tools and go to the network panel. Make sure you toggle "Preserve Log" from the top bar. This will let us see network traffic even after we've been redirected.&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%2Fblog.kentonvizdos.com%2Fcontent%2Fimages%2F2020%2F06%2Fimage-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.kentonvizdos.com%2Fcontent%2Fimages%2F2020%2F06%2Fimage-1.png" alt="TIL 1: How to POST to a Google Form using HTML"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Great! Now, lets type in some fake input (make sure you remember what you typed in, it will become useful later) and submit it. Once you do so, you will see your network panel blow up with requests. It should look similar to below:&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%2Fblog.kentonvizdos.com%2Fcontent%2Fimages%2F2020%2F06%2Fimage-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.kentonvizdos.com%2Fcontent%2Fimages%2F2020%2F06%2Fimage-2.png" alt="TIL 1: How to POST to a Google Form using HTML"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While it may seem daunting at first, fear not. The only thing you need to look at is at the very top of the list where it says  "formResponse"&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%2Fblog.kentonvizdos.com%2Fcontent%2Fimages%2F2020%2F06%2Fimage-3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.kentonvizdos.com%2Fcontent%2Fimages%2F2020%2F06%2Fimage-3.png" alt="TIL 1: How to POST to a Google Form using HTML"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you click in there, scroll to the very bottom of the Headers section until you find the Form Data section.  Now, you will notice some odd things. Mainly, the field names aren't exactly what one would first assume considering what I named "Name" is now &lt;code&gt;entry.3403608&lt;/code&gt; (expect that number to be different than yours). This is why submitting recognizable information in the previous section was important. This allows us to easily recognize which field goes where.&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%2Fblog.kentonvizdos.com%2Fcontent%2Fimages%2F2020%2F06%2Fimage-4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.kentonvizdos.com%2Fcontent%2Fimages%2F2020%2F06%2Fimage-4.png" alt="TIL 1: How to POST to a Google Form using HTML"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, to double check that Google isn't playing tricks, we &lt;em&gt;should&lt;/em&gt; do the submission process again, however I've discovered it doesn't change in between requests. Phew.&lt;/p&gt;

&lt;p&gt;Cool. Now, we discovered the correct endpoint, &lt;code&gt;https://docs.google.com/forms/d/e/&amp;lt;formID&amp;gt;/formResponse&lt;/code&gt;. Simple enough. Now, we just need to adjust our HTML input names to reflect the correct Form Data fields. To do this, simply add a &lt;code&gt;name=&amp;lt;ID&amp;gt;&lt;/code&gt; into your code. An example is below.&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%2Fblog.kentonvizdos.com%2Fcontent%2Fimages%2F2020%2F06%2Fimage-5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.kentonvizdos.com%2Fcontent%2Fimages%2F2020%2F06%2Fimage-5.png" alt="TIL 1: How to POST to a Google Form using HTML"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Boom! You now have a fully working form that submits directly to Google Forms.&lt;/p&gt;

&lt;p&gt;And again. The way this is setup has minimal security and spam protection, but it has about the same as a normal form due to the rate limiting and smartness of Google. If you would like to add a bit more security, you can enable "Collect email addresses" and/or "Limit to 1 response" however it will require the user to submit the form on Google Forms after they submit on your site.&lt;/p&gt;

&lt;p&gt;As an example, I setup Limit to 1 Response and got this warning once I clicked "Submit" on my locally hosted form:&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%2Fblog.kentonvizdos.com%2Fcontent%2Fimages%2F2020%2F06%2Fimage-6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.kentonvizdos.com%2Fcontent%2Fimages%2F2020%2F06%2Fimage-6.png" alt="TIL 1: How to POST to a Google Form using HTML"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, if you don't mind losing a little spam protection to create a basic form for your users, this will work. And, if you do want a little bit more spam protection, you can enable Limit to 1 Response or have it collect email addresses automatically (though an "email" input will &lt;em&gt;not&lt;/em&gt; auto fill a required email field, just fyi). For my needs, a non-limited and non-capturing form was plenty, and if I notice spam starts to happen I can seamlessly turn on single submissions.&lt;/p&gt;

&lt;p&gt;Soon, &lt;a href="https://prauxy.app" rel="noopener noreferrer"&gt;PRAUXY.app&lt;/a&gt; will include a Secure Google Forms middleman that will allow you to limit to one response without a secondary submission, but for now, that does not exist :)&lt;/p&gt;

&lt;p&gt;Let me know if you use this and I'd love to hear feedback if you have any!&lt;/p&gt;

</description>
      <category>todayilearned</category>
      <category>guides</category>
    </item>
    <item>
      <title>How to add a clap button to your blog</title>
      <dc:creator>Kenton Vizdos</dc:creator>
      <pubDate>Fri, 08 May 2020 18:21:00 +0000</pubDate>
      <link>https://dev.to/kvizdos/how-to-add-a-clap-button-to-your-blog-2h46</link>
      <guid>https://dev.to/kvizdos/how-to-add-a-clap-button-to-your-blog-2h46</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JnEVySjz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/05/How-to-add-claps.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JnEVySjz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/05/How-to-add-claps.png" alt="How to add a clap button to your blog"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's get the first question out of the way: why should you add a clap button to your site?&lt;/p&gt;

&lt;p&gt;In my opinion, it provides good analytics on which posts do well and which could use some work. Also, you can use Google Tag Manager to track the clicks overall in more depth, let me know if you would like a tutorial on how to do this, but as of now, it goes a little bit out scope.&lt;/p&gt;

&lt;p&gt;Also, ever since Medium integrated them, they are pretty much common place on blogs. Luckily, the great people at &lt;a href="https://applause-button.com/"&gt;https://applause-button.com/&lt;/a&gt; have done most of the heavy lifting for us!&lt;/p&gt;

&lt;h2&gt;
  
  
  Lets get started.
&lt;/h2&gt;

&lt;p&gt;First, pull up your post code. In my case, I'm using Ghost with a custom theme, so I will open my &lt;code&gt;post.hbs&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
            &amp;lt;article class="postauthor"&amp;gt;
                &amp;lt;article class="about"&amp;gt;
                    &amp;lt;img src="{{primary_author.profile_image}}"&amp;gt;
                    &amp;lt;article class="info"&amp;gt;
                        &amp;lt;article&amp;gt;
                            &amp;lt;p class="name"&amp;gt;{{primary_author.name}}&amp;lt;/p&amp;gt;
                            &amp;lt;p class="bio"&amp;gt;{{primary_author.bio}}&amp;lt;/p&amp;gt;
                        &amp;lt;/article&amp;gt;
                        &amp;lt;a href="https://twitter.com/{{primary_author.twitter}}" target="_blank" class="twitter"&amp;gt;&amp;lt;i class="fab fa-twitter"&amp;gt;&amp;lt;/i&amp;gt; {{primary_author.twitter}}&amp;lt;/a&amp;gt;
                    &amp;lt;/article&amp;gt;
                &amp;lt;/article&amp;gt;
                &amp;lt;article class="support"&amp;gt;
                    &amp;lt;a href="https://paypal.me/kentonv" target="_blank" alt="Support"&amp;gt;&amp;lt;i class="fas fa-donate"&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;
                &amp;lt;/article&amp;gt;
            &amp;lt;/article&amp;gt;
        &amp;lt;/article&amp;gt;

&amp;lt;/section&amp;gt;
{{/post}}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here, you can see the very bottom of the file. We simply need to make one small modification of adding the following code into the page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;section id="clapper"&amp;gt;
    &amp;lt;applause-button style="width: 58px; height: 58px" color="#3f9dff"&amp;gt;&amp;lt;/applause-button&amp;gt;
    &amp;lt;article&amp;gt;
        &amp;lt;h2&amp;gt;Enjoy the article?&amp;lt;/h2&amp;gt;
        &amp;lt;p&amp;gt;a clap is much appreciated if you enjoyed. No sign up or cost associated :)&amp;lt;/p&amp;gt;
    &amp;lt;/article&amp;gt;
&amp;lt;/section&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Overall, the bottom of my file now looks as such:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;            &amp;lt;section id="clapper"&amp;gt;
                &amp;lt;applause-button style="width: 58px; height: 58px" color="#3f9dff"&amp;gt;&amp;lt;/applause-button&amp;gt;
                &amp;lt;article&amp;gt;
                    &amp;lt;h2&amp;gt;Enjoy the article?&amp;lt;/h2&amp;gt;
                    &amp;lt;p&amp;gt;a clap is much appreciated if you enjoyed. No sign up or cost associated :)&amp;lt;/p&amp;gt;
                &amp;lt;/article&amp;gt;
            &amp;lt;/section&amp;gt;
            &amp;lt;article class="postauthor"&amp;gt;
                &amp;lt;article class="about"&amp;gt;
                    &amp;lt;img src="{{primary_author.profile_image}}"&amp;gt;
                    &amp;lt;article class="info"&amp;gt;
                        &amp;lt;article&amp;gt;
                            &amp;lt;p class="name"&amp;gt;{{primary_author.name}}&amp;lt;/p&amp;gt;
                            &amp;lt;p class="bio"&amp;gt;{{primary_author.bio}}&amp;lt;/p&amp;gt;
                        &amp;lt;/article&amp;gt;
                        &amp;lt;a href="https://twitter.com/{{primary_author.twitter}}" target="_blank" class="twitter"&amp;gt;&amp;lt;i class="fab fa-twitter"&amp;gt;&amp;lt;/i&amp;gt; {{primary_author.twitter}}&amp;lt;/a&amp;gt;
                    &amp;lt;/article&amp;gt;
                &amp;lt;/article&amp;gt;
                &amp;lt;article class="support"&amp;gt;
                    &amp;lt;a href="https://paypal.me/kentonv" target="_blank" alt="Support"&amp;gt;&amp;lt;i class="fas fa-donate"&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;
                &amp;lt;/article&amp;gt;
            &amp;lt;/article&amp;gt;
        &amp;lt;/article&amp;gt;

&amp;lt;/section&amp;gt;
{{/post}}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Wahoo! We're almost there. Now, we simply need to add the &lt;a href="https://applause-button.com/"&gt;Applause Button&lt;/a&gt; CDN into our header. Most blogging platforms have header injection options, so lets go look at our Ghost admin dashboard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2XyM7sGv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/05/image-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2XyM7sGv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/05/image-2.png" alt="How to add a clap button to your blog"&gt;&lt;/a&gt;Ghost Dashboard&lt;/p&gt;

&lt;p&gt;On the side, you can see "Code Injections." Let's check there first.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--boqyDiK7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/05/image-3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--boqyDiK7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/05/image-3.png" alt="How to add a clap button to your blog"&gt;&lt;/a&gt;Site Header Injection&lt;/p&gt;

&lt;p&gt;Perfect! A place we can simply place our CDN code. Let's give it a shot!&lt;/p&gt;

&lt;p&gt;Place the following in that textfield:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script src="https://unpkg.com/applause-button/dist/applause-button.js"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;link rel="stylesheet" href="https://unpkg.com/applause-button/dist/applause-button.css"&amp;gt;

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



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kJyhm4me--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/05/image-4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kJyhm4me--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/05/image-4.png" alt="How to add a clap button to your blog"&gt;&lt;/a&gt;Ghost Injections&lt;/p&gt;

&lt;p&gt;Yay! Now, if you go back to your ghost site, after restarting it, you should see the following at the bottom of your header:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CYNaTpQX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/05/image-5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CYNaTpQX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/05/image-5.png" alt="How to add a clap button to your blog"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cool, now, let's give it a shot by trying to hit the clap at the bottom of this page! You can also test it on your own site :)&lt;/p&gt;

&lt;p&gt;Make sure to make sure it still works by clicking on the clap below. Hopefully, I helped you learn something!&lt;/p&gt;

</description>
      <category>guides</category>
    </item>
    <item>
      <title>let vs const vs var: when to use which</title>
      <dc:creator>Kenton Vizdos</dc:creator>
      <pubDate>Fri, 08 May 2020 00:21:19 +0000</pubDate>
      <link>https://dev.to/kvizdos/let-vs-const-vs-var-when-to-use-which-1763</link>
      <guid>https://dev.to/kvizdos/let-vs-const-vs-var-when-to-use-which-1763</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vPvcIeBA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/05/Let-VS-Consf-VS-Var.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vPvcIeBA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/05/Let-VS-Consf-VS-Var.png" alt="let vs const vs var: when to use which"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Variable used to be the norm in JavaScript, but now there are better players on the playing field: let and const. The main difference? Scope.&lt;/p&gt;

&lt;p&gt;See, scope is &lt;em&gt;important&lt;/em&gt; in programming. In most cases, always using global variables isn't a great idea, but there are still some good uses for it if you look hard enough.&lt;/p&gt;

&lt;p&gt;First, lets go over the similarities and differences between let and const. Mainly, both are locally scoped so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const letsTest = () =&amp;gt; {
    let x = 5;
}

letsTest();

console.log(x) // this fails.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;But also, it is very useful in for loop scenarios:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var a = [];
(function () {
   'use strict';
   for (let i = 0; i &amp;lt; 5; i++) { // ***`let` works as expected***
     a.push( function() {return i;} );
   }
} ());
console.log(a.map( function(f) {return f();} ));
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As expected, a now equals [0,1,2,3,4], however if you make a small change by changing let to var, you'll notice things start getting gross as it would return [5,5,5,5,5]&lt;/p&gt;

&lt;p&gt;Source: &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Block_scope_with_let"&gt;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Block_scope_with_let&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As for a difference, const is a constant variable (woah), so it cannot be changed after initialization&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const x = 5;
x = 1; // Fails.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Other than that, let and const are pretty much the same. Better than var. As of ES6, var hardly ever should be used.&lt;/p&gt;

&lt;p&gt;While this is a short article, it is good to know the very small differences between the three. Best of luck with your variables!&lt;/p&gt;

</description>
      <category>technical</category>
      <category>guides</category>
    </item>
    <item>
      <title>The basics of fetch()</title>
      <dc:creator>Kenton Vizdos</dc:creator>
      <pubDate>Sat, 02 May 2020 03:36:15 +0000</pubDate>
      <link>https://dev.to/kvizdos/the-basics-of-fetch-22pi</link>
      <guid>https://dev.to/kvizdos/the-basics-of-fetch-22pi</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Sp0ysg0q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/05/tofetchornottofetch.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Sp0ysg0q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/05/tofetchornottofetch.png" alt="The basics of fetch()"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Are you sick and tired of writing huge XMLHTTPRequests in your JavaScript code?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Oh, you already stopped using those ages ago.. right..&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Well, somehow, fetch() never caught my attention until just recently so I've slowly started switching over to using it over alternatives as I think it is a beautiful built-in function baked directly into JavaScript!&lt;/p&gt;

&lt;h2&gt;
  
  
  Compatibility
&lt;/h2&gt;

&lt;p&gt;And sure, fetch() may not be the &lt;em&gt;best&lt;/em&gt; option for fetching API endpoints (cough cough THANKS INTERNET EXPLORER cough cough) and it is still unclear whether or not interviewers will care if you use it, but it sure is debated&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I’m conflicted. When I interview front-end candidates, most React devs pull in Axios for fetching JSON (instead of fetch), moment.js instead of Date objects, and want to use Bootstrap or a CSS framework instead of flexbox or grid. &lt;a href="https://t.co/Q3ITv7A0V5"&gt;https://t.co/Q3ITv7A0V5&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;— Marc Grabanski ✌️ (&lt;a class="comment-mentioned-user" href="https://dev.to/1marc"&gt;@1marc&lt;/a&gt;
) &lt;a href="https://twitter.com/1Marc/status/1251693961904783360?ref_src=twsrc%5Etfw"&gt;April 19, 2020&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Buuuut it is still fun to use. But first, we do need to clarify the Internet Explorer compatibility...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--I89Q8lhg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/05/image.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--I89Q8lhg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/05/image.png" alt="The basics of fetch()"&gt;&lt;/a&gt;Internet Explorer has no compatibility&lt;/p&gt;

&lt;p&gt;Yeahh, so it's &lt;em&gt;not&lt;/em&gt; perfect, but considering Edge has support, maybe you could just.. let IE slide and hope nobody uses a program that looks about a million years old..&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BEAkJfcm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/05/image-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BEAkJfcm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/05/image-1.png" alt="The basics of fetch()"&gt;&lt;/a&gt;Internet Explorer in 2020&lt;/p&gt;

&lt;p&gt;&lt;em&gt;While Internet Explorer IS ugly and not commonly used,&lt;/em&gt; it is still used by a couple of people, so if you are looking to support them, you should look into third party libraries such as Axios, or keep up with XMLHTTPRequests.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Good Stuff: how to use it to send a GET request
&lt;/h2&gt;

&lt;p&gt;So, you've made it this far. You've decided to leave Internet Explorer users in the dust. Let's get to some syntax.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fetch('https://www.reddit.com/.json?limit=1');
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Simply put, this will return you a Promise statement, so lets learn how to use that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fetch('https://www.reddit.com/.json?limit=1')
    .then(response =&amp;gt; response.json());
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, you've managed to parse your request into usable JSON, so lets go one step further:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fetch('https://www.reddit.com/.json?limit=1')
    .then(response =&amp;gt; response.json())
    .then(data =&amp;gt; console.log(data));
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
XMLHTTPRequest generated by Postman





&lt;p&gt;Kachow! You've successfully pulled the first result from the front page of Reddit and printed the result! Now, lets look at the XMLHTTPRequest for&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function() {
  if(this.readyState === 4) {
    this.responseText = JSON.parse(this.responseText);
    console.log(this.responseText);
  }
});

xhr.open("GET", "https://www.reddit.com/.json?limit=1");

xhr.send();
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
XMLHTTPRequest generated by Postman





&lt;p&gt;Ew. Why right 13 lines when you could simply write 3 (ssshhh about compatibility..)???&lt;/p&gt;

&lt;p&gt;It gets even better when you start doing other things, like POSTing&lt;/p&gt;

&lt;h2&gt;
  
  
  Sending a POST request using fetch()
&lt;/h2&gt;

&lt;p&gt;Do note: when using fetch(), you will not receive cross-site cookies and you won't send cookies unless you set the credentials option, which we will get to below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fetch('https://myawesomeapi.example/new', {
    method: 'POST', // or GET, PUT, DELETE, etc
    headers: {
        'Content-Type': 'application/json'
    },
    redirect: 'follow',
    body: JSON.stringify({
        name: "this post is 10/10"
    })
}).then(response =&amp;gt; response.json()).then(data =&amp;gt; console.log(data));
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Simple POST request complete! While it still isn't the prettiest, it's definitely better than whatever this is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var data = JSON.stringify({"name":"this post is 10/10"});

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function() {
  if(this.readyState === 4) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "https://myawesomeapi.example/new");
xhr.setRequestHeader("Content-Type", "application/json");

xhr.send(data);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Going back to sending with credentials (cookies), make sure you allow credentials on the API side in CORS. After that, you can simply add "credentials: 'include'" into the options above body (it doesn't really matter where, it just needs to be somewhere in the same object). Or, if you don't want to send credentials, you can use "credentials: 'omit'"&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap Up
&lt;/h2&gt;

&lt;p&gt;This was a very brief overview of the fetch() api. There is a lot more you can do with it, like uploading files, but that goes out of the basic scope of this article. If you are interested, send me a tweet &lt;a class="comment-mentioned-user" href="https://dev.to/kvizdos"&gt;@kvizdos&lt;/a&gt;
 and I'll write a more in depth post "All about fetch()" instead of "the basics." Overall, should you use fetch() over Axios or XMLHTTPRequests: it depends. Do you want to support IE? Then you need to use Axios or XMLHTTPRequest or one of the gazillion other options. If not, fetch() is a nice library built into JavaScript that requires 0 dependencies, so it can keep your code base a little bit smaller and a little bit cleaner if you care.&lt;/p&gt;

&lt;p&gt;I hope you learned something from this post!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>What is PRAUXY?</title>
      <dc:creator>Kenton Vizdos</dc:creator>
      <pubDate>Sun, 19 Apr 2020 15:00:08 +0000</pubDate>
      <link>https://dev.to/kvizdos/what-is-prauxy-hdj</link>
      <guid>https://dev.to/kvizdos/what-is-prauxy-hdj</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KQkgfWxE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/04/prauxypost.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KQkgfWxE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/04/prauxypost.png" alt="What is PRAUXY?"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hello everyone!&lt;/p&gt;

&lt;p&gt;I thought I'd finally share my pet project that I've been working on for a while now called "Prauxy." The main purpose of this app is to let me proxy my web applications easily while still having the ability to have SSL, authentication, custom domains, and static site hosting in one place.&lt;/p&gt;

&lt;p&gt;For those who don't know me already, I am a high school junior and have been developing websites for the greater portion of 4-5 years. It's been really fun and this is definitely one of my larger projects.&lt;/p&gt;

&lt;p&gt;If you are interested, I'd love it if you checked out the "launch" page for it at &lt;a href="https://prauxy.app"&gt;https://prauxy.app&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--if9YGiHx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/05/prauxy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--if9YGiHx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/05/prauxy.png" alt="What is PRAUXY?"&gt;&lt;/a&gt;Launch page sneak peek (I encourage you to look at it in the actual website though!)&lt;/p&gt;

&lt;p&gt;I'd love any feedback (either by tweeting me, &lt;a href="https://twitter.com/kvizdos"&gt;@kvizdos&lt;/a&gt;, or emailing me)! If you are interested in looking at the code, it is all open-sourced at &lt;a href="https://github.com/kvizdos/PRAUXY"&gt;https://github.com/kvizdos/PRAUXY&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kPSrkRQH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/04/image-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kPSrkRQH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/04/image-1.png" alt="What is PRAUXY?"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;WHY&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In short, I got annoyed at needing to create new nginx vhosts for every single application I created. I do a lot of remote development through a VSCode web interface and it got really annoying to need to setup a vhost if I were to access it from outside of my network. With this, I can create a secure development environment that I could give stakeholders access to on a need-to-access basis (stakeholders in my case being teachers, friends, etc who want to view a test site/homework assignment).&lt;/p&gt;

&lt;p&gt;Also, my school is a "specialty center" for IT/PM stuff and I've been talking with my CS teacher who wants to set up an in-house system that the App Development course students can use to host their websites on (mainly because we don't have the budget for anything else, but do have some servers that have been donated to us).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Main features include:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Advanced authentication system&lt;/li&gt;
&lt;li&gt;This also includes multi-factor support (more details below the screenshot)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This allows you to add authentication to apps that do not support it directly out of the box. I also like to use it for things that "have" authentication out of the box but require new credentials for it. This allows me to have one login for all sorts of applications.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Multi-user support&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For storing passwords, I decided to use bcrypt. Also, there is a basic permission scheme setup to allow certain users access to certain sites while not allowing others.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Proxy applications&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Instead of creating a vhost or whatever in Nginx/Apache, this will automatically route incoming requests properly.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Static site hosting&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I do a lot of testing / static coding for fun so I wanted a way to easily demo the items. With Proxy, I can link a GitHub repo to it and have it automatically pull new updates on any new push.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Full mobile support (PWA)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SSL support&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;While SSL support isn't where I want it (full SSL), it still works very well for my needs, however, you still need to manually create a certificate for non-wildcard domains (e.g. custom domains).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Plans:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Next year, for my high school senior capstone class, I plan on integrating a full mobile IDE that is made for tablets as there is a huge empty space in the tablet development environments. Also, I do plan on adding a dark mode because.. I don't like being blind.&lt;/p&gt;

&lt;p&gt;If you want to view the larger road map, I encourage you to look at the Trello board located at &lt;a href="https://trello.com/b/UPlQNXcH/prauxy"&gt;https://trello.com/b/UPlQNXcH/prauxy&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stack:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Right now, it's using NodeJS in the backend w/ MongoDB for the database and Redis for caching. For the front end, I am just using normal HTML/CSS/JS but I eventually want to switch over to Vue. I started this project in HTML/CSS/JS because I thought I wasn't going to go far with it, but now I'm deep into it so it'll take a bit for me to convert it.&lt;/p&gt;

&lt;p&gt;As for project management methodology, I used Scrum. I used Scrum because I have my CSM and CSPO and have really enjoyed using it in the past to get things done quickly and efficiently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On a side note, the &lt;a href="https://education.github.com/"&gt;GitHub Student Pack&lt;/a&gt; helped immensely in the creation of PRAUXY!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you are a student and have yet to see the &lt;a href="https://education.github.com/"&gt;GitHub Student pack&lt;/a&gt;, you've got to check it out! It is packed with a &lt;strong&gt;ton&lt;/strong&gt; of amazing premium subscription based services, but for free!&lt;/p&gt;

&lt;p&gt;From the pack, I've mainly been using a premium SendGrid account to handle all of the email services that Prauxy requires (mainly for user registration). Without SendGrid, however, it would've been a much sadder process, but I still could've gotten through with their free plan.&lt;/p&gt;

&lt;p&gt;Next, my school laptop, the one I do most of my programming on during school hours (through a VSCode web interface), has 0 access to a terminal and while I can access a Guacamole session while Prauxy is running, if I just so happened to crash Prauxy, I'd be locked out. This happened a ton while in the very early stages, especially before I started using PM2. But, either way, I now use Termius on my phone which lets me SSH into my server through an SSH key. It has a great interface and really saved my butt some days!&lt;/p&gt;

&lt;p&gt;Also, while it's not &lt;em&gt;as&lt;/em&gt; important now, the Pack also comes with GitHub Pro which allowed for private repos pre-freeifying them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here are some screenshots to show the flow:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mRwFFlQq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/04/image-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mRwFFlQq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/04/image-2.png" alt="What is PRAUXY?"&gt;&lt;/a&gt;PRAUXY login screen&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EjjJMgtR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/04/image-3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EjjJMgtR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/04/image-3.png" alt="What is PRAUXY?"&gt;&lt;/a&gt;PRAUXY MFA screen&lt;/p&gt;

&lt;p&gt;I really like my login system here as it supports both TFA tokens through Google Authenticator / etc, or you can simply confirm the login ID through another previously logged-in device ("Confirm on different device"). This feature is similar to Google's confirmation on a different device.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fGzt3PSf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/04/image-4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fGzt3PSf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/04/image-4.png" alt="What is PRAUXY?"&gt;&lt;/a&gt;This is what users on a previously logged-in account would see (as long as they are logged in with the same username)&lt;/p&gt;

&lt;p&gt;Also, if you click on the wrong number it will reset the codes on both the previously-logged in user and the user trying to log in. While it's not necessary, it adds a little bit of marginal security if someone where to access the system from the outside (which shouldn't be possible through the way it is currently set up, but there are probably ways.)&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GnlYDV2G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/04/image-5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GnlYDV2G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/04/image-5.png" alt="What is PRAUXY?"&gt;&lt;/a&gt;PRAUXY home page&lt;/p&gt;

&lt;p&gt;On the home page, you can see all of your proxied "apps." In my case, I have a few different development environments and also a proxy into VSCode (using Coder). I really like having the authentication through my proxy system as it allows me to set permissions for who can see what. It is also handy to add strong authentication to systems that do not currently have it (e.g. vscode).&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8DZz0ZhJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/04/image-6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8DZz0ZhJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/04/image-6.png" alt="What is PRAUXY?"&gt;&lt;/a&gt;PRAUXY "Add an App" modal&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QvOtjT_0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/04/image-7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QvOtjT_0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/04/image-7.png" alt="What is PRAUXY?"&gt;&lt;/a&gt;PRAUXY Static Sites&lt;/p&gt;

&lt;p&gt;Here is the UI for the static sites. I'm not a huge fan of the emptiness, but I'm still learning the UI stuff and it has come a long way since the start. As for adding the sites, it's quite simple as you just fill out the form (below), set up the GitHub webhook with the appropriate secret key, and boom, you're done!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--w8gIEmk---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/04/image-8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--w8gIEmk---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/04/image-8.png" alt="What is PRAUXY?"&gt;&lt;/a&gt;PRAUXY Add Static Site modal&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Vye1Cb8F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/04/image-9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Vye1Cb8F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/04/image-9.png" alt="What is PRAUXY?"&gt;&lt;/a&gt;PRAUXY Users&lt;/p&gt;

&lt;p&gt;There is also full support for multiple users. The only downside is that the permissions aren't great (e.g. each user is sort of an "admin" where they can do anything on the site, but..). Mainly, the current permission level lets you set a level for access which you can set for each app. This allows you to give all Level 1s and higher access to X environment but they cant see Level 2 apps. I had to make this feature quickly for a school assignment where I needed to give my friends access to a VSCode environment that was separate from my main one, but also not let them access anything else.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FwIfoxb8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/04/image-10.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FwIfoxb8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/04/image-10.png" alt="What is PRAUXY?"&gt;&lt;/a&gt;PRAUXY Add User&lt;/p&gt;

&lt;p&gt;Super simple add user form. Sends the user an email with a temporary password using SendGrid.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IbMqdkO1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/04/image-11.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IbMqdkO1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/04/image-11.png" alt="What is PRAUXY?"&gt;&lt;/a&gt;PRAUXY User Settings&lt;/p&gt;

&lt;p&gt;Here, you can change your password and email (and soon username, etc). It is basic, but also usable. You access this page by clicking on your username in the top right next to the log out button.&lt;/p&gt;

&lt;p&gt;Thanks for reading, hope you enjoyed! If you have any feedback, questions, or concerns, I'd love to hear it!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to automatically backup Ghost blogs</title>
      <dc:creator>Kenton Vizdos</dc:creator>
      <pubDate>Thu, 19 Mar 2020 05:44:03 +0000</pubDate>
      <link>https://dev.to/kvizdos/how-to-automatically-backup-ghost-blogs-4he1</link>
      <guid>https://dev.to/kvizdos/how-to-automatically-backup-ghost-blogs-4he1</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rkr8c6B8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/03/backups.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rkr8c6B8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.kentonvizdos.com/content/images/2020/03/backups.png" alt="How to automatically backup Ghost blogs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's the issue. I'm always messing up my server, but now I'm running more production services on this server than my other server, so I need to figure out how to not lose all of this blog data if something catastrophic were to happen.&lt;/p&gt;

&lt;p&gt;Lets get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Figure out what you need to back up.
&lt;/h2&gt;

&lt;p&gt;In my case, I would like to back up both the text posts and other generally backed up things (through Ghosts interface) as well as photos and videos that I may upload in the future. This guide will be for backing up both to Google Drive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Take 1 (DONT (just) do this): Backing up root Ghost directory
&lt;/h2&gt;

&lt;p&gt;Boom! Easy solution, just gotta copy one directory, zip it up, and send it to Google! Boom boom boom done.&lt;/p&gt;

&lt;p&gt;No. Don't &lt;em&gt;just&lt;/em&gt; do this. This will not copy any blog data when running in production mode as they are saved in a SQL database. Let's figure out how to fix it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Take 2: Save the SQL database AND Ghost content directory
&lt;/h2&gt;

&lt;p&gt;"Two steps" here, just saving the SQL database and just copying the ./content/ folder in Ghost.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Create a backup MySQL user
&lt;/h2&gt;

&lt;p&gt;This is good practice just so you can backtrack things if needed. It is also good to just give a user permissions that they require, no more, no less.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mysql&amp;gt; CREATE USER 'backup'@'localhost' IDENTIFIED BY '###';
mysql&amp;gt; GRANT ALL ON ghost_prod.* TO 'backup'@'localhost';
mysql&amp;gt; FLUSH PRIVILEGES;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Create ~/.my.cnf file
&lt;/h2&gt;

&lt;p&gt;Modify the file ~/.my.cnf to include the following, and then make sure it requires chmod 600.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[client]
user=backup
password="###"

# chmod 600 ~/.my.cnf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Create backup scripts
&lt;/h2&gt;

&lt;p&gt;To back up the MySQL database, we will be using MySQLDump to save the file as a gzip with the date.&lt;/p&gt;

&lt;p&gt;Lets figure out this command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mysqldump ghost_prod &amp;gt; ghost_prod.sql
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The above command would technically work, however it won't be compressed, so if a blog is large, the file will most likely be large. Let's figure out how to date and compress the file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mysqldump ghost_prod | gzip &amp;gt; ghost_prod-$(date +%Y%m%d).sql.gz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is a good example on how to zip it up and save the file with a date. Now that we have the database saving setup, let's test it (or, at least I will to double check my work).&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2.5 (optional): Test backup commands
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Run the above command&lt;/li&gt;
&lt;li&gt;Make a Ghost backup through the UI&lt;/li&gt;
&lt;li&gt;Drop the ghost_prod table &lt;code&gt;"DROP DATABASE ghost_prod;"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Exit MySQL&lt;/li&gt;
&lt;li&gt;Recreate the table using &lt;code&gt;mysql -e "create database ghost_prod";&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Decompress the backup &lt;code&gt;gunzip ghost_prod-(date).sql.gz&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Restore database &lt;code&gt;mysql --one-database ghost_prod &amp;lt; ghost_prod-(date).sql&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Success (hopefully)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 3: Compress content
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tar -zcvf ./content-$(date +%Y%m%d).tar.gz /var/www/ghost/content/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Putting it all together in a script
&lt;/h2&gt;

&lt;p&gt;Notice in the script I changed from having the date in the file name to having it in &lt;code&gt;Backups/ghost/(date)/&amp;lt;files&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/bash
now=$(date +'%Y-%m-%d_%H-%M')
echo "Making backup folder for $now"
mkdir "/home/kenton/Backups/ghost/$now"

echo "Saving ghost_prod Database Backup $now"
mysqldump ghost_prod | gzip &amp;gt; "/home/kenton/Backups/ghost/$now/ghost_prod.sql.gz"

echo "Compressing content folder"
tar -zcvf "/home/kenton/Backups/ghost/$now/content.tar.gz" --absolute-names /var/www/ghost/content/ &amp;gt; /dev/null
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Keep backup in Google Drive
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Install rclone &lt;code&gt;sudo apt-get install rclone&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Setup rclone &lt;code&gt;rclone config&lt;/code&gt; (I set the name to google-drive)&lt;/li&gt;
&lt;li&gt;Change to script to include rclone code (make sure to change (USER) to your user)
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo "Sending to Drive"
/usr/bin/rclone copy --update --verbose --transfers 30 --checkers 8 --contimeout 60s --timeout 300s --retries 3 --low-level-retries 10 --stats 1s "/home/(USER)/Backups/ghost/$now/" "google-drive:ServerBackups/ghost/$now/"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 6: Cronjob
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Add a &lt;code&gt;crontab -e&lt;/code&gt; item&lt;/li&gt;
&lt;li&gt;For this example, we will back up the data every day at midnight: &lt;code&gt;0 0 * * * /home/(USER)/Backups/backup.sh&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 7: Congrats! You're now fully backed up!
&lt;/h2&gt;

&lt;p&gt;While I have no liability for any lost data, I'm nearly sure you won't lose any as long as it is backed up. This solution makes sure to keep multiple copies of data across Google Drive and local devices, so you should be good if you ever need to reset.&lt;/p&gt;

</description>
      <category>guides</category>
    </item>
  </channel>
</rss>
