<?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>Forem: Vincent Tang</title>
    <description>The latest articles on Forem by Vincent Tang (@vincentntang).</description>
    <link>https://forem.com/vincentntang</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%2F90366%2F6d54bb11-7ebe-499d-8cb7-a99199474825.png</url>
      <title>Forem: Vincent Tang</title>
      <link>https://forem.com/vincentntang</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/vincentntang"/>
    <language>en</language>
    <item>
      <title>Lessons learned from Junior to Senior Developer</title>
      <dc:creator>Vincent Tang</dc:creator>
      <pubDate>Tue, 18 May 2021 19:54:12 +0000</pubDate>
      <link>https://forem.com/vincentntang/lessons-learned-from-junior-to-senior-developer-2dob</link>
      <guid>https://forem.com/vincentntang/lessons-learned-from-junior-to-senior-developer-2dob</guid>
      <description>&lt;p&gt;3 years ago, I decided to change careers and become a software developer. I had no formal training in software development and decided to learn on my own. Through countless youtube and Udemy tutorials, and hackathons, I landed my first job working on construction management software.&lt;/p&gt;

&lt;p&gt;Fast forward to today. I'm a senior frontend developer in charge of delegating &amp;amp; delivering features affecting millions of users at a time. I've come a long way since then and I'm writing this post reflecting on what I learned along the way.&lt;/p&gt;

&lt;p&gt;This isn't an exhaustive list but just lessons I learned along the way&lt;/p&gt;

&lt;h2&gt;
  
  
  Working with stakeholders
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If you demo to stakeholders, record a video of the demo in advance as a backup. &lt;/li&gt;
&lt;li&gt;Live coding/testing has a high chance of failure&lt;/li&gt;
&lt;li&gt;The frontend is always highly scrutinized by non-tech stakeholders since it's visual and easier to understand&lt;/li&gt;
&lt;li&gt;When you demo, talk slow and move your mouse slow. Things that are obvious to you are this way since you spent several weeks on a feature. Stakeholders are seeing your work for the first time&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Working with management
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If you need to estimate a task, assume it's way harder than it is&lt;/li&gt;
&lt;li&gt;Deliver bad news early and good news frequently&lt;/li&gt;
&lt;li&gt;If your PM is messaging you directly for updates frequently, either there's an issue with the process or you are doing things wrong. &lt;/li&gt;
&lt;li&gt;Push back deadlines as far back as possible during planning phases. You'll thank yourself later. It's better to underpromise and overdeliver&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Working with engineers
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Create living documentation upfront and do it regularly, it saves everyone time. Google docs is your friend&lt;/li&gt;
&lt;li&gt;If you get stuck on a problem for more than 3 hours, ask for help.&lt;/li&gt;
&lt;li&gt;Make your teammates look good and give credit where it's due. The analogy is if you hang out with awesome friends chances are you are awesome as well&lt;/li&gt;
&lt;li&gt;Make an ADR (Architectural Decision Record) when you implement big changes to a codebase. It prevents you (and others) from 2nd guessing why certain things were done 6 months ago&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Code Reviews
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;For code reviews, critique the code, not the person&lt;/li&gt;
&lt;li&gt;Make your code reviews awesome by explaining every question a person might come up with&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Leading a team
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Mentoring developers can be fun and enjoyable, but you need to spend time and effort on it&lt;/li&gt;
&lt;li&gt;Plan out your ticket action plan for the team over several days to iterate and improve&lt;/li&gt;
&lt;li&gt;Spend time onboarding newer developers on the project, and write documentation on questions they have. They're looking at things from a fresh perspective&lt;/li&gt;
&lt;li&gt;Always give good candid feedback to your teammates when possible&lt;/li&gt;
&lt;li&gt;Emphasize the big picture and give room for others to be creative/ take ownership of features&lt;/li&gt;
&lt;li&gt;When you pair program, one person is the driver, the other is the instructor&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Time Management
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Plan large focus periods of work where you won't get interrupted&lt;/li&gt;
&lt;li&gt;Don't forget we're all people too. Plan your vacation and sick days&lt;/li&gt;
&lt;li&gt;Think win-win and lump related tasks together and get them done in one go&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Reducing Technical Debt
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Don't over-engineer things unless it's warranted&lt;/li&gt;
&lt;li&gt;If you use two booleans that conflict with each other, use an enumerable instead&lt;/li&gt;
&lt;li&gt;Type safety is effective at reducing technical debt.&lt;/li&gt;
&lt;li&gt;Always use pure functions when possible. This makes the app reusable and obvious at a glance&lt;/li&gt;
&lt;li&gt;Write more tests against iterative and less obvious code&lt;/li&gt;
&lt;li&gt;Use undefined instead of sentinel values. Sentinel values are checks on seemingly random values in the codebase&lt;/li&gt;
&lt;li&gt;Always use a linter. It saves you time and effort&lt;/li&gt;
&lt;li&gt;Don't have competing sources of truth. Use as few scoped variables as possible, and use as few derived/computed variables as possible&lt;/li&gt;
&lt;li&gt;If you need to tackle legacy debt, migrate one feature at at time&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Architectural Rules
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Most systems use soft deletes. This means companies don't actually delete your data, it's just marked as inactive&lt;/li&gt;
&lt;li&gt;Use caching to reduce amount of work service-layers need to make. But don't treat it as the source of truth if possible.&lt;/li&gt;
&lt;li&gt;Never trust the frontend. The backend should handle the vast majority of business logic. Avoid database business logic if possible, it's hard to maintain.&lt;/li&gt;
&lt;li&gt;If you don't need high scalability on your project, just ship it out and don't worry about it until needed &lt;/li&gt;
&lt;li&gt;Don't put too many shiny things in the app. It increases the risk of failure. Pick preferably popular libraries with good documentation&lt;/li&gt;
&lt;li&gt;Feature flagging helps you deploy and deliver features to other teams while still deploying regularly&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Database Rules
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Keep your database designs as simple as possible to reduce complex JOIN SQL statements&lt;/li&gt;
&lt;li&gt;NoSQL datastores don't have ACID requirements, so it's great when you design a system where users don't talk to each other&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Let me know what you learned over the years and add it in a comment :)&lt;/p&gt;

</description>
    </item>
    <item>
      <title>My personal 2020 reflections</title>
      <dc:creator>Vincent Tang</dc:creator>
      <pubDate>Mon, 04 Jan 2021 02:27:03 +0000</pubDate>
      <link>https://forem.com/vincentntang/2020-into-2021-1joc</link>
      <guid>https://forem.com/vincentntang/2020-into-2021-1joc</guid>
      <description>&lt;p&gt;Every year I write a &lt;a href="https://www.vincentntang.com/2019-into-2020/" rel="noopener noreferrer"&gt;blog post&lt;/a&gt; reflecting what I've learned and accomplished. And whether or not I met my goals for this year. It's a great way to see how far I've come since I started my coding journey.&lt;/p&gt;

&lt;p&gt;Without further ado, here's my 2021 version!&lt;/p&gt;

&lt;h2&gt;
  
  
  I started a coding podcast, and released &lt;strong&gt;7&lt;/strong&gt; episodes!
&lt;/h2&gt;

&lt;p&gt;I didn't plan on building a coding podcast this year. It all started when I was invited to the &lt;a href="https://backendbear.com/" rel="noopener noreferrer"&gt;backend-bears&lt;/a&gt; coding podcast. I spoke with Marko about what it's like for a frontend developer to learn backend development. It was a blast reliving what it was like working at my first job, and the challenges I overcame to be where I am today. I had such a positive experience on this show that I decided to create my own, so I could invite my own guests too!&lt;/p&gt;

&lt;p&gt;I reached out to one of my closest coding friends, German Gamboa to cohost with me. Thus &lt;a href="https://codechefs.dev/" rel="noopener noreferrer"&gt;Code Chefs&lt;/a&gt; was born. We've been steadily releasing content every week, and have air'd 7 episodes so far:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.codechefs.dev/first-developer-jobs" rel="noopener noreferrer"&gt;1 - First Developer Jobs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.codechefs.dev/react-vs-vue" rel="noopener noreferrer"&gt;2 - React vs Vue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.codechefs.dev/hackathons" rel="noopener noreferrer"&gt;3 - Level up with Hackathons&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.codechefs.dev/css-crash-course" rel="noopener noreferrer"&gt;4 - CSS Crash Course&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.codechefs.dev/fitness" rel="noopener noreferrer"&gt;5 - Fitness 101 for Developers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.codechefs.dev/intro-to-backend" rel="noopener noreferrer"&gt;6 - Intro to Backend Development&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.codechefs.dev/intro-to-qa" rel="noopener noreferrer"&gt;7 - Intro to Quality Assurance&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I challenged myself to build the entire thing from scratch. Read about how it was built &lt;a href="https://www.vincentntang.com/custom-podcast-site-gatsby-react/" rel="noopener noreferrer"&gt;here&lt;/a&gt;. This coding podcast is the first real side project I've built since starting my coding journey.&lt;/p&gt;

&lt;h2&gt;
  
  
  I wrote &lt;strong&gt;10&lt;/strong&gt; blog articles
&lt;/h2&gt;

&lt;p&gt;One of my goals this past year is to write more frequently. I wrote a few different articles reflecting upon my career, and things I learned while building &lt;a href="https://codechefs.dev" rel="noopener noreferrer"&gt;code chefs&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.vincentntang.com/fixing-broken-webapp/" rel="noopener noreferrer"&gt;Inheriting a broken Javascript webapp and how to fix it&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.vincentntang.com/react-use-state-explained/" rel="noopener noreferrer"&gt;Demystifying React useState&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.vincentntang.com/react-use-effect-explained/" rel="noopener noreferrer"&gt;Demystifying React useEffect&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.vincentntang.com/customize-bootstrap-with-react/" rel="noopener noreferrer"&gt;Customize Bootstrap in a React App&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.vincentntang.com/custom-podcast-site-gatsby-react/" rel="noopener noreferrer"&gt;Build a Custom Podcast Site with GatsbyJS, ReactJS, AmazonS3, and Netlify&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.vincentntang.com/custom-podcast-site-gatsby-react/" rel="noopener noreferrer"&gt;How Competing in Hackathons helped me land my first job&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.vincentntang.com/installing-gatsbyjs-blog-comments/" rel="noopener noreferrer"&gt;Installing Blog Comments on your GatsbyJS/ ReactJS site using Utterances&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.vincentntang.com/writing-custom-rss-gatsby/" rel="noopener noreferrer"&gt;On writing a custom RSS feed for GatsbyJS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.vincentntang.com/wtf-are-jamstack-apps-and-static-site-generators/" rel="noopener noreferrer"&gt;What are JAMstack Apps and Static Site Generators(SSG)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.vincentntang.com/learning-path-for-self-taught-web-developer/" rel="noopener noreferrer"&gt;Recommended Learning Path for a Self Taught Web Developer (React / NodeJS)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  I did my &lt;strong&gt;first&lt;/strong&gt; paid freelancing gig!
&lt;/h2&gt;

&lt;p&gt;I've never done a paid freelancing gig before. Granted, I've helped in numerous startups when I first started programming, some spinning off from hackathon applications I wrote. I had the opportunity to work through a web agency on a VR project with Verizon.&lt;/p&gt;

&lt;p&gt;Read about it &lt;a href="https://www.thedrum.com/news/2020/10/23/nightmares-are-loose-verizon-launches-virtual-immersive-experience-marketers" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  I dropped &lt;strong&gt;35 lbs&lt;/strong&gt; in 6 months!
&lt;/h2&gt;

&lt;p&gt;At the start of this year, before Covid hit, I started to become overweight. Namely, I just moved to a new city and found myself constantly eating out at new restaurants every day. I drew up a plan around January to drop weight for the first time in my life. This was done through a recipe tracker I made on google spreadsheet in which I tracked how many calories I ate every day and measured my weight progress over time. The biggest challenges for me here was adjusting to the new diet and discovering what things I did and didn't like eating. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F25c4oh0bth5rgrmzwbte.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F25c4oh0bth5rgrmzwbte.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  I furnished my &lt;strong&gt;first&lt;/strong&gt; apartment!
&lt;/h2&gt;

&lt;p&gt;Every apartment I've lived in before this had been furnished. Before this, I had been couch surfing for several months in Tampa as I didn't know which area in town I wanted to live in. I settled in the old downtown district and have loved it ever since!&lt;/p&gt;

&lt;p&gt;However, furnishing my first apartment was more difficult than I'd imagine. I never realized how many different combinations of styles and genre of interior decor exist out there. From chic, to country, to minimalistic - the combinations were endless. I ended up spending several weeks sleeping on Ikea sofas and couches nearby to find out what suits me best, an ungodly amount of time shopping online, and learning about something called &lt;a href="https://www.homenish.com/focal-point-interior-design/" rel="noopener noreferrer"&gt;focal points&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here's what my place looks like, after throwing my first house warming Pre-Covid:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fo5s9nyesqygejnubc169.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fo5s9nyesqygejnubc169.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  I adopted my &lt;strong&gt;first&lt;/strong&gt; cat
&lt;/h2&gt;

&lt;p&gt;I've always wanted a furry companion. I never had one growing up. Although, one time my dad called me on my 12th birthday, proudly exclaiming he adopted a new dog. I was coming home from school when I got the news. I felt a rush of excitement as I couldn't wait to meet him! Upon arriving home, I didn't find a new dog dashing forward to meet me at the door. Confused, I called my dad and he told me to check near the staircase. I ended up finding a dog statue. I later found out we never had pets because my dad was allergic to them.&lt;/p&gt;

&lt;p&gt;This past month I adopted my first cat companion, Monty. Prior to this, I had recently been laid off, so I used the free time I had to visit various animal shelters. Monty was actually one of the first cats I met at the first animal shelter I went to! I adopted him, and I later found out my entire team at my new job had cats.&lt;/p&gt;

&lt;p&gt;Here's a picture of Monty:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdrnj6bjuy6531ffc8vt4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdrnj6bjuy6531ffc8vt4.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  I redesigned my website
&lt;/h2&gt;

&lt;p&gt;Around Q3 2019, I got laid off from Covid. With that free time, I used it to redo my website!&lt;/p&gt;

&lt;p&gt;It's still based on a fork off of another popular theme, but suffice to say I've added a lot of new features to the site. Including the ability to add comments, a new newsletter, amongst many other cool features&lt;/p&gt;

&lt;h2&gt;
  
  
  I learned musicality
&lt;/h2&gt;

&lt;p&gt;This year I sought to explore personal skills over professional ones. I'm still trying to find myself, my identity, and how I'd like to be perceived by others. For that, I wanted to explore hobbies I never had done previously and skills I never was good at. So I focused on musicality - dancing, singing, and musical instruments.&lt;/p&gt;

&lt;p&gt;Over the course of a few months, I learned how to play "Knocking on Heaven's Door" from ACDC/ Bob Dylan. Both a simple musical strum pattern and singing at the same time. It's a simple enough song and the lyrics aren't difficult, but I spent weeks learning about my voice, and what I could produce, given enough time and practice.&lt;/p&gt;

&lt;p&gt;For dancing, I picked this up through a dance studio. I never thought it was something I'd enjoy, but I fell in love with how expressive it can be. You can tell a lot about someone's personality, just by the way they move. For instance, slower movements are associated with someone more relaxed, whereas someone who has style tends to be more expressive. Everyone has a different pattern and I'm still finding my own. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fakky89dmgun6y4mciauf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fakky89dmgun6y4mciauf.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Goals this year
&lt;/h2&gt;

&lt;p&gt;My goals last year were rather generic. This year I'm going to quantify what I'd like to achieve by the end of 2021&lt;/p&gt;

&lt;p&gt;Professional goals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build 1 side project that is primarily backend based&lt;/li&gt;
&lt;li&gt;Build 1 tool for creating cutting edge user-experiences / assets&lt;/li&gt;
&lt;li&gt;Build 1 fun hardware-based IoT project&lt;/li&gt;
&lt;li&gt;Get AWS solution architect associates certified&lt;/li&gt;
&lt;li&gt;Finish 1 computer science course, most likely NAND2Tetris&lt;/li&gt;
&lt;li&gt;Finish 1 course on Cypress Testing and Web-Accessibility&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Personal goals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Increase overall strength by 30% by July, 135/175 bench/squat at 5x1 currently&lt;/li&gt;
&lt;li&gt;Create a financial stock portfolio&lt;/li&gt;
&lt;li&gt;Finish a course on improving charisma and be able to apply them to my life&lt;/li&gt;
&lt;li&gt;Improve my writing ability through writing more blog posts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's my reflection for 2020 and my goals for this coming year! Most of my accomplishments this year were personal. It's the year in which I wanted to discover more about myself, amidst a pandemic&lt;/p&gt;

</description>
      <category>personal</category>
      <category>2021</category>
      <category>development</category>
      <category>2020</category>
    </item>
    <item>
      <title>Recommended Learning Path for a Self Taught Web Developer (React / NodeJS)</title>
      <dc:creator>Vincent Tang</dc:creator>
      <pubDate>Sun, 06 Dec 2020 17:09:35 +0000</pubDate>
      <link>https://forem.com/vincentntang/recommended-learning-path-for-a-self-taught-web-developer-react-nodejs-3b53</link>
      <guid>https://forem.com/vincentntang/recommended-learning-path-for-a-self-taught-web-developer-react-nodejs-3b53</guid>
      <description>&lt;p&gt;Back in 2016, I designed commercial kitchens for a living. This meant I consulted with restaurant owners who were starting their business for the first time. And made recommendations on how best to run their operation.&lt;/p&gt;

&lt;p&gt;I found myself constantly needing new tools to manage these tasks. I would often times catalog the tools I use on &lt;a href="https://alternativeto.net/user/kagerjay/"&gt;alternativeto.net&lt;/a&gt;, and try a lot of software products in the startup space.&lt;/p&gt;

&lt;p&gt;At one point, I asked one of the developers if they could implement a new feature that I wanted. They didn't have the bandwidth to build it and challenged me to write my first &lt;a href="https://www.vincentntang.com/Writing%20a%20custom%20userscript/"&gt;Javascript widget&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But, I didn't know anything about Javascript, CSS, or HTML. But I taught myself and built it.&lt;/p&gt;

&lt;p&gt;And people started &lt;a href="https://github.com/vincentntang/dynalist-extensions"&gt;using the tool I made&lt;/a&gt;. And I got hooked. I wanted to become that developer who actually shipped web apps like the ones I relied on daily.&lt;/p&gt;

&lt;p&gt;It's 2020 now and I've been hired on as senior frontend engineer, working in React/NodeJS primarily. I didn't go through a coding bootcamp, and just learned mostly everything through things I found online.&lt;/p&gt;

&lt;p&gt;I remember how much of a struggle it was trying to find the best learning resources out there. And what things I should even learn as a webdeveloper. There's just so many tutorials out there that I didn't know where to begin, so I spent a great deal of time auditing many of the popular courses out there. &lt;/p&gt;

&lt;p&gt;I'm writing the article I wish I had read, when I first started learning to become a web developer (React / NodeJS). What I should learn, in what order, to get that first job and start my coding career.&lt;/p&gt;

&lt;p&gt;Here's that guide, and my impression of the learning resources I used as well:&lt;/p&gt;

&lt;h2&gt;
  
  
  Your First Job
&lt;/h2&gt;

&lt;p&gt;You can learn only so much on your own, and real-world experience always trumps things you learn in a course. You should focus on getting a job ASAP in the software space, and figure out what you want to do after.&lt;/p&gt;

&lt;p&gt;I always recommend any junior developer to get a frontend developer position. This is usually someone who makes a website pretty and functional for users. Like what the site looks like, how it talks to a backend, and cool little widgets that make the web fun.&lt;/p&gt;

&lt;p&gt;It exposes you to the whole software development cycle and you learn many applicable skills to ship real-world products. Frontend developer roles usually don't have a huge barrier-to-entry and are junior developer-friendly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Course Guide Overview &amp;amp; Criteria:
&lt;/h3&gt;

&lt;p&gt;I recommend taking multiple courses in different related topics, and not to take a one-course fit-all plan. You learn much faster when you learn from multiple teachers and see different viewpoints on related topics.&lt;/p&gt;

&lt;p&gt;At the same time, I also don't like over recommending too many overlapping courses either. You only have so much time throughout the day, so might as well make the best use of it.&lt;/p&gt;

&lt;p&gt;Here's the guide:&lt;/p&gt;

&lt;h3&gt;
  
  
  Part 1 - Learn Computer Science Fundamentals
&lt;/h3&gt;

&lt;p&gt;Before learning web development, you should take an &lt;a href="https://online-learning.harvard.edu/course/cs50-introduction-computer-science?delta=0"&gt;intro course to computer science&lt;/a&gt; through Harvard's CS50. It's free.&lt;/p&gt;

&lt;p&gt;My reasons as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It teaches you a few different languages, C and python, so you'll be able to make comparisons to this and Javascript. It'll also teach you foundational backend programming when you build an image-decoder&lt;/li&gt;
&lt;li&gt;You'll learn how to use the command line, which is useful when working with Git in team settings and working with webservers&lt;/li&gt;
&lt;li&gt;It teaches you basic algorithms, which you'll need to know for writing optimal frontend code and backend code. As well as all the coding challenges you run into in interviews&lt;/li&gt;
&lt;li&gt;It teaches you how memory addresses work, so you can debug things much easier&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Most of the things you learn in Harvard's CS50 will pop up later on. When you learn the basics, learning everything else just becomes much easier. There are many patterns that emerge in programming, and they're usually tied to computer science.&lt;/p&gt;

&lt;h3&gt;
  
  
  Part 2 - Learn Javascript and CSS really well:
&lt;/h3&gt;

&lt;p&gt;I recommend taking two courses in parallel:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.freecodecamp.org/learn"&gt;FreeCodeCamp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Any foundational course on Javascript:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For (1), FreeCodeCamp is a free online platform for teaching frontend and backend development. Originally, it started as a way to teach frontend development (HTML, CSS, JS), so I recommend sticking with that. &lt;/p&gt;

&lt;p&gt;The two certifications I suggest going for at this point are the "Responsive web design certifications (300 hours)" and  "Javascript Algorithms and data structures (300 hours)". These two certifications teaches you the basics of Javascript, HTML, and CSS in a more learn at your own-pace hands-on fashion. &lt;/p&gt;

&lt;p&gt;For (2), a foundational course will give you a video instructional overview from an instructor. I suggest taking &lt;strong&gt;either&lt;/strong&gt; of these (or both):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://watchandcode.com/"&gt;Watch and Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.udemy.com/course/the-web-developer-bootcamp/learn/lecture/22587506#overview"&gt;Colt Steel's Web Developer Bootcamp&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Both teachers here tend to teach in a more gentle fashion. So it's an easier introduction to the topic:&lt;/p&gt;

&lt;p&gt;Watch and code is from an ex-google engineer. He teaches you how to build a todo-app from the ground up, and more so how to think like a programmer. Taking this course taught me a lot of foundational design patterns, and how to properly write out the requirements of an app before building it&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For watch and code, don't go past building the todo-app course, which is about 4-8 hours long. The other content is senior-level and great for doing later in your career.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Colt Steel's Bootcamp is a high level introduction of how the web works. How a backend talks to a frontend. It's a solid course covering all the fundamentals, but I still recommend watch-and-code though, since the next course will cover overlapping topics&lt;/p&gt;

&lt;h3&gt;
  
  
  Part 3 - Crash course on a full-stack application React NodeJS
&lt;/h3&gt;

&lt;p&gt;After taking an instructor that takes a more gentle approach (bottoms-up), I recommend taking a course now that takes a hard-fast ball approach instead(top-down). &lt;/p&gt;

&lt;p&gt;The course I recommend taking is "MERN stack front to back" from Brad Traversy on Udemy&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.udemy.com/course/mern-stack-front-to-back/"&gt;MERN Stack front to back&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Brad Traversy doesn't really explain how everything works, but just enough for you to understand what's going on. It'll teach you how everything is connected together using React and NodeJS so you can reference down the road later. It'll teach you just enough backend knowledge such that you can entirely focus on frontend afterward&lt;/p&gt;

&lt;h3&gt;
  
  
  Part 4 - Learn React, Bootstrap, and Sass
&lt;/h3&gt;

&lt;p&gt;At this point, you have solid foundational knowledge on Javascript, HTML, and CSS and have built a few small projects through FreeCodeCamps certification challenges. And have an overview of how React, NodeJS, and MongoDB work together through Brad Traversy's course.&lt;/p&gt;

&lt;p&gt;Now you just need to hone in on what employers actually hire for and the skills needed to build features in a codebase.&lt;/p&gt;

&lt;p&gt;I suggest taking these two in parallel:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://www.freecodecamp.org/learn"&gt;FreeCodeCamp&lt;/a&gt; - Frontend Libraries Certification (300 hours)&lt;/li&gt;
&lt;li&gt;Any in-depth React Course&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For (2), if you took Colt Steel's course early, I suggest taking a different instructor this time around. Any of the popular Udemy courses are good, but I personally recommend taking this one:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.udemy.com/course/react-the-complete-guide-incl-redux/"&gt;Max Schwartz - React the Complete Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After taking these courses, you'll have built a few React projects, have a solid understanding of react hooks, class components, lifecycles, and redux. Redux is a steep learning curve but once you get over that hump everything else is pretty easy.&lt;/p&gt;

&lt;p&gt;There's also a second React course I recommend grokking over as well with Max's course, this one is from Stephen Grider.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.udemy.com/course/react-redux/"&gt;Stephen Griders - Modern React Redux&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;He makes some of the best diagrams in my opinion for explaining concepts in React / Redux. And also the best analogy on the topic as well.&lt;/p&gt;

&lt;h3&gt;
  
  
  Part 5 - Learn to build things in a team setting
&lt;/h3&gt;

&lt;p&gt;You have now a ton of useful skills. Now you should start applying it to build actual projects. You should learn a little bit about project management and team dynamics. This is all the things you would have learned at a coding boot camp but didn't because you're learning mostly on your own&lt;/p&gt;

&lt;p&gt;I recommend taking these two paths: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://chingu.io/"&gt;Chingu cohorts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devpost.com/hackathons"&gt;Hackathons&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Chingu cohorts is a place where you get together with other self-learning developers such as yourself, and build a project. You can either pick to build something unique or clone something that exists out there. I recommend cloning an application like Trello for instance, you can focus purely on problem-solving instead of generating ideas&lt;/p&gt;

&lt;p&gt;Hackathons are great places to learn from others. It's a short 1 - 3 day event most times, where you get together and build a project. Covid makes things complicated, but I always recommend competing with ones local to your area as the learning experience will be much better.&lt;/p&gt;

&lt;h3&gt;
  
  
  Part 6 - Your portfolio capstone project
&lt;/h3&gt;

&lt;p&gt;I don't really recommend the saying of "following your passion", but rather build something that you actually would want to use.&lt;/p&gt;

&lt;p&gt;You should have one project you can talk about at great lengths with an employer. I suggest one, and not two, because it makes it easier for a potential employer to say "Oh he/she was that person that built X project". It's easier to remember than "Oh he/she was that person that built A,B, and C projects"&lt;/p&gt;

&lt;p&gt;Also, if you're coming from a different career, consider building something related to that field. It tells a story of how you are transitioning from one career to the next.&lt;/p&gt;

&lt;p&gt;But if you truly don't have any ideas, feel free to add new features to a tutorial project and make it unique. Or, check out these recommendations for ideas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/florinpop17/app-ideas"&gt;Github Idea Repo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Make sure the project you build looks really clean on the frontend, I suggest using a CSS framework like MaterialUI, Bootstrap, or Tailwinds. It's the first impression someone makes on your project if it's structured well. You could have an ugly frontend and a beautiful backend, but it won't be appreciated as much. &lt;/p&gt;

&lt;h3&gt;
  
  
  Part 7 - Be a part of a tech community
&lt;/h3&gt;

&lt;p&gt;I recommend listening to podcasts during your drive to work or commutes. This should be done in parallel in my experience from parts 1 to 6. You'll gain a huge amount of insight on how experienced developers communicate with each other, and pick up knowledge you wouldn't have otherwise gotten anywhere else.&lt;/p&gt;

&lt;p&gt;Podcasts I recommend:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://codechefs.dev"&gt;code chefs&lt;/a&gt; - My personal podcast&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://syntax.fm"&gt;syntax.fm&lt;/a&gt; - Heavily frontend focused&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://codingblocks.net"&gt;coding blocks&lt;/a&gt; - A really good friend of mine runs this, it's computer science + backend heavy focused&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://techjr.dev"&gt;tech jr&lt;/a&gt; - Lots of career related topics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also, I recommend joining your local tech community. If you live in the middle of nowhere, there are still options for you!&lt;/p&gt;

&lt;p&gt;First check out a list of slack channels out there: &lt;a href="https://github.com/ladyleet/tech-community-slacks"&gt;Github city slack channels&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And join your local &lt;a href="https://meetup.com"&gt;tech meetups&lt;/a&gt; in town&lt;/p&gt;

&lt;p&gt;And I also recommend writing about what you learn along the way on &lt;a href="https://dev.to"&gt;dev.to&lt;/a&gt;, or your own personal blog. Feel free to use my site as an &lt;a href="https://vincentntang.com/"&gt;example&lt;/a&gt; and fork the &lt;a href="https://github.com/vincentntang/vincentntang.com"&gt;source code here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Blogging is a good way to reflect on what you learn and to show a potential employer what you know&lt;/p&gt;

&lt;h2&gt;
  
  
  Recap Summary
&lt;/h2&gt;

&lt;p&gt;Here's a quick recap summary for courses I recommend to take in that order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Learn basic computer science - &lt;a href="https://online-learning.harvard.edu/course/cs50-introduction-computer-science?delta=0"&gt;Harvard's CS50&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Learn Javascript and CSS well - &lt;a href="https://www.freecodecamp.org/learn"&gt;FreeCodeCamp&lt;/a&gt; - Do these certifications: "Responsive web design certifications (300 hours)" and  "Javascript Algorithms and data structures (300 hours)". In parallel, take &lt;a href="https://watchandcode.com/"&gt;Watch and Code&lt;/a&gt; course on building a todo-app&lt;/li&gt;
&lt;li&gt;Get a grasp on a full-stack app built - &lt;a href="https://www.udemy.com/course/mern-stack-front-to-back/"&gt;MERN Stack front to back&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Get good at React - &lt;a href="https://www.freecodecamp.org/learn"&gt;FreeCodeCamp&lt;/a&gt; - Frontend Libraries Certification (300 hours). And this course in parallel: &lt;a href="https://www.udemy.com/course/react-the-complete-guide-incl-redux/"&gt;Max Schwartz - React the Complete Guide&lt;/a&gt;. I would also watch the introductory topics from here, but you don't need to finish this one: &lt;a href="https://www.udemy.com/course/react-redux/"&gt;Stephen Griders - Modern React Redux&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Apply skills in a team setting - &lt;a href="https://chingu.io/"&gt;Chingu cohorts&lt;/a&gt; and &lt;a href="https://devpost.com/hackathons"&gt;Hackathons&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Showcase your work - Build your capstone project&lt;/li&gt;
&lt;li&gt;Pick up everything else you missed - Be a part of your local tech scene, podcasts, and meetups&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Everyone has a different learning style, but this is the learning path I would have told myself a few years ago. It covers the foundations really well, in a short time frame for a job skill that'll still be in demand years from now.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;NOTE: Also if you're on a budget, always buy the Udemy courses when they're on sale. Don't get them for more than $10 to $15 each. Make a new account under a new email, clear your cookies, and you can always get the first course for that price. You shouldn't have to spend more than $50 on all these courses in total.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Feel free to follow me here if you'd like to follow and read more :D&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="http://vincentntang.substack.com/"&gt;newsletter&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/vincentntang"&gt;twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vincentntang.com"&gt;personal site&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>react</category>
      <category>node</category>
      <category>beginners</category>
      <category>bootcamp</category>
    </item>
    <item>
      <title>WTF are JAMstack Apps and Static Site Generators (SSG)</title>
      <dc:creator>Vincent Tang</dc:creator>
      <pubDate>Mon, 30 Nov 2020 02:14:22 +0000</pubDate>
      <link>https://forem.com/vincentntang/wtf-are-jamstack-apps-and-static-site-generators-ssg-56if</link>
      <guid>https://forem.com/vincentntang/wtf-are-jamstack-apps-and-static-site-generators-ssg-56if</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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvt0f5d0xzoswp79wvwf2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvt0f5d0xzoswp79wvwf2.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;JAMstack and Static Site Generators are tools often used for building blog and marketing sites, usually as a replacement for older tools like &lt;a href="https://wordpress.com/" rel="noopener noreferrer"&gt;Wordpress&lt;/a&gt;. They provide huge performance gains to your site, don't require much maintenance, and makes scaling your content cheap and easy.&lt;/p&gt;

&lt;p&gt;But where do such benefits come from? &lt;/p&gt;

&lt;p&gt;In this article, I will breakdown how Static Site Generators (SSG) work. First, by describing the original problem that it was created to solve. Next, I'll describe what JAMstacks app is, and how they evolved from SSGs. Then, I'll cover some actual tools you can use to build your next JAMstack app, such as &lt;a href="https://gatsbyjs.com" rel="noopener noreferrer"&gt;GatsbyJs&lt;/a&gt;. Finally, I'll summarize the similarities and differences between both JAMstack and SSG tools, and when to use each of these tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Good Ol' Days of PHP and HTML files in the year 2000
&lt;/h2&gt;

&lt;p&gt;Back in the good ol' days, the web used to be simple. You spun up an &lt;code&gt;index.html&lt;/code&gt; site, pushed it to a server, and tada! You have a webpage! Maybe it's your own personal site. Or maybe it's a marketing site. Heck, maybe you just used Geocities or myspace back in the day which did this for you.&lt;/p&gt;

&lt;p&gt;Sometimes you needed more than just basic HTML. Maybe it's an e-commerce site, and you want customers to buy things online. Usually, this meant you ran a backend language like PHP to handle this for you. &lt;/p&gt;

&lt;p&gt;That PHP code would usually run on somebody's computer (server) and handle these interactions. It would also handle different parts of the site like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;https://website.com/about-us&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;https://website.com/category/t-shirts&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;https://website.com/products/awesome-t-shirt&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And possibly 100+ other specific suburls, usually dedicated to products and category pages. &lt;/p&gt;

&lt;p&gt;You could however opt and not use PHP or a server-side language, and just make 100+ index.html pages for each of these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;about-us.html&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;category/t-shirts.html&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;products/awesome-t-shirt.html&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But here's the dilemma. All 100+ of these index.html pages use the same &lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;footer&amp;gt;&lt;/code&gt; element on the page, amongst many other things. That means if you wanted to update one small thing, you have to do the same thing everywhere else!&lt;/p&gt;

&lt;p&gt;Let's just say now, your site isn't an e-commerce site. It's a blog now! But it still has 100+ pages and articles you've written.&lt;/p&gt;

&lt;p&gt;You don't need to charge money on these blog articles or have a cart/checkout page. Your site is basically a &lt;strong&gt;Read-only&lt;/strong&gt; site with minimal updates. There are no dynamic prices, or sales/promos. It doesn't need fancy PHP or server-side languages, it can just be plain &lt;code&gt;.html&lt;/code&gt; files&lt;/p&gt;

&lt;p&gt;But we've discussed early the problems here, updating the header on one &lt;code&gt;.html&lt;/code&gt; file means you have to do it for the other 99+ &lt;code&gt;.html&lt;/code&gt; files! That's ALOT of maintenance&lt;/p&gt;

&lt;p&gt;Here's where static site generators come in!&lt;/p&gt;

&lt;h2&gt;
  
  
  The coming of Static Site Generators in 2008
&lt;/h2&gt;

&lt;p&gt;Static Site generators solve the maintenance issue of modifying so many &lt;code&gt;.html&lt;/code&gt; files. The first major one that had a lot of traction was Jekyll in 2008 because you could deploy it on Github Pages. It was written in Ruby which is another backend language like PHP&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;NOTE: Jekyll was not the first Static Site generator, but the one that made SSGs popular &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Jekyll took a unique approach to solve modifying so many &lt;code&gt;.html&lt;/code&gt; files on a blogsite. Why not just create a reusable template for blogs and pages?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Post-template.html&lt;/li&gt;
&lt;li&gt;Page-template.html&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A post-template.html file might look something like this (&lt;a href="https://github.com/mmistakes/jekyll-theme-basically-basic/blob/master/_layouts/post.html" rel="noopener noreferrer"&gt;link&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;---
layout: default
---

{% include page-intro.html %}

&lt;span class="nt"&gt;&amp;lt;main&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"main"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"page-content"&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"Content"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;article&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"entry-wrap"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        {{ content }}
    &lt;span class="nt"&gt;&amp;lt;/article&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Basically, we specify what type of layout it is, and the &lt;code&gt;{{content}}&lt;/code&gt; is where the actual stuff the reader reads gets rendered. &lt;code&gt;Layout&lt;/code&gt; is the entire look and feel of the site&lt;/p&gt;

&lt;p&gt;So now if you change your HTML/CSS for the &lt;code&gt;Layout&lt;/code&gt;, it changes it for all blog posts! Likewise for pages too&lt;/p&gt;

&lt;p&gt;And why not write content in an easier way? Such as &lt;a href="https://daringfireball.net/projects/markdown/syntax" rel="noopener noreferrer"&gt;markdown&lt;/a&gt;? And use that markdown to generate each of those pages for the &lt;code&gt;{{content}}&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;look-at-me-ma-my-first-article.md&lt;/li&gt;
&lt;li&gt;wtf-are-jamstackapps-and-ssgs.md&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example of the 2nd markdown file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Post:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;WTF&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;are&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;JAMstack&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Apps&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;SSGs?"&lt;/span&gt;
&lt;span class="na"&gt;categories&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Post Formats&lt;/span&gt;
&lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Post Formats&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;readability&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;standard&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

If you've ever read an article on JAMstack apps 
or Static Site Generators (SSG), sometimes you're left.............
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tada! That's a static site generator! It does all the boring, heavy lifting work for you so you can generate those 100 &lt;code&gt;.html&lt;/code&gt; pages with ease! And modify all the styles for all the posts in one go if you had to!&lt;/p&gt;

&lt;p&gt;Here's the kicker with Static Site Generators. &lt;strong&gt;It does run on a backend language like Ruby or PHP. BUT, it only runs every time you write a new article or modify CSS/HTML on the site&lt;/strong&gt;. We call this "build time", and this is why it takes a while to see changes right away. &lt;/p&gt;

&lt;p&gt;So because it needs to rebuild every time, it doesn't make a whole lot of sense to write an e-commerce site with it. I mean just imagine this, every time you add/remove a product from the site, you need to rebuild EVERYTHING! Even for product pages that didn't change! If you have 100,000+ products, it could take hours or even days to rebuild!&lt;/p&gt;

&lt;p&gt;So to hit the point home, &lt;strong&gt;Static Site Generators work best for READ-ONLY websites&lt;/strong&gt;. We're talking about things like marketing and informational sites, blog sites, podcast sites, etc. The rule of thumb for me is &lt;strong&gt;if you need to update content more than twice a day or some unknown amount of times after the site is stable, you probably shouldn't use a static site generator&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That's not to say you can't have a dynamic comments feature, or a place to gather emails. You can have this still! That's where Javascript comes in, and maybe a mini-backend living elsewhere that does all the heavy lifting for you!&lt;/p&gt;

&lt;p&gt;Here's why JAMstack applications are so popular!&lt;/p&gt;

&lt;h2&gt;
  
  
  WTF is a JAMstack application?
&lt;/h2&gt;

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

&lt;p&gt;So what is a JAMstack app? Well, it stands for Javascript API Markup. We covered the &lt;strong&gt;Markup&lt;/strong&gt; (ironically, which usually uses &lt;em&gt;markdown&lt;/em&gt; &lt;code&gt;.md&lt;/code&gt; files). &lt;strong&gt;API&lt;/strong&gt; refers to if you wanted to integrate a separate backend for dynamic comments on a blog, using HTTP fetch methods for instance. &lt;strong&gt;Javascript&lt;/strong&gt; is actually really broad and encompassing here, and I have to expand on this.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;NOTE: all JAMstack applications are also Static Site Generators (SSGs)! But the reverse is not true.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Javascript&lt;/strong&gt; means you can use Javascript on each of your post pages. Like maybe you want to sprinkle a tiny jQuery widget on a specific page, such as something to read off how many likes you got on Twitter. Most SSGs did support this out of the box, but it becomes kind of cumbersome having all these jQuery widgets sprinkled everywhere.&lt;/p&gt;

&lt;p&gt;But then we had a new kid on the block back in 2015. This was React, and React pretty much changed the way we wrote frontend applications.&lt;/p&gt;

&lt;p&gt;In the first history lesson I gave about PHP and the year 2000s era, things were server-side rendered. Which meant, when a user went on different pages on the e-commerce site, the server would just send a new HTML, CSS, and JS that would be rendered on your browser like google chrome.&lt;/p&gt;

&lt;p&gt;This is where React differs. It decouples the backend from the frontend, in that the client only talks to the backend via an API. This means you can have what's called &lt;strong&gt;client-side routing&lt;/strong&gt; amongst many other benefits.&lt;/p&gt;

&lt;p&gt;So that same e-commerce site example. Say you had these suburls:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;about-us.html&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;category/t-shirts.html&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;products/awesome-t-shirt.html&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When the user hits the site, you can preload where all these routes live! And when a user navigates to that page, maybe the &lt;code&gt;&amp;lt;footer&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt; on the page is the same. But it doesn't make sense to rerender those every time a user navigates to a different part of the page.&lt;/p&gt;

&lt;p&gt;React does what is called tree-shaking, or diff-rendering. It figures out what actually needs to change, and &lt;strong&gt;only renders&lt;/strong&gt; those changes. So you don't rerender the &lt;code&gt;&amp;lt;footer&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt; every time. &lt;/p&gt;

&lt;p&gt;When you hear why JAMstack applications are so popular, that is what the &lt;strong&gt;Javascript&lt;/strong&gt; portion is referring to! &lt;strong&gt;These are the benefits every JAMstack article is referring to!&lt;/strong&gt; It uses React, which is a &lt;strong&gt;single-page-application&lt;/strong&gt; framework that does all this magic for you.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There's also Vue which is like React, but I omitted talking about it because the concepts and benefits are exactly the same&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  So, what are some actually JAMstack tools?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbwor4rmsufuhaju27xo5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbwor4rmsufuhaju27xo5.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So here's where I talk about &lt;a href="http://gatsbyjs.com/" rel="noopener noreferrer"&gt;Gatsby&lt;/a&gt;. Gatsby was built on React, BUT it's also built on NodeJS.&lt;/p&gt;

&lt;p&gt;Remember when I talked a century ago about Static Site Generators? And how modifying 100+ &lt;code&gt;.html&lt;/code&gt; files was a pain in the butt?. And how SSGs used a backend language like Ruby or PHP to take some markdown files to generate all these &lt;code&gt;.html&lt;/code&gt; files for you?&lt;/p&gt;

&lt;p&gt;Well, JAMstack applications do the same thing! Because &lt;strong&gt;all JAMstack apps are SSGs!&lt;/strong&gt; And so is Gatsby too, because it's a JAMstack app!&lt;/p&gt;

&lt;p&gt;Gatsby uses NodeJS instead of Ruby or PHP, and it builds that every time you make new &lt;code&gt;markdown&lt;/code&gt; file changes. But wait Vincent, why does Gatsby (JAMstack and SSG) differ from Jekyll (SSG)?&lt;/p&gt;

&lt;p&gt;Gatsby uses React, which has all the benefits mentioned previously! It renders only things that change, it decouples the backend, and can even preload different pages so it renders even faster! From the user's perspective, this just means the site is ooooooooohhhhh soooooo much faster, and that means better SEO and performance.&lt;/p&gt;

&lt;p&gt;But wait there's more! I didn't mention this earlier, but SSGs and JAMstack apps also can optimize images for you too! Maybe your lazy and upload a fat 5Mb image to the site, and don't feel like compressing the files. Well, because SSGs and JAMstacks run a backend every time you upload a new markdown file, guess what! You can run image compression too and dump it into the &lt;code&gt;public&lt;/code&gt; or &lt;code&gt;dist&lt;/code&gt; folder, where the frontend gets rendered!&lt;/p&gt;

&lt;p&gt;But it gets even better! Gatsby, since it's React and Javascript based, can do Javascript magic too! Instead of just pre-optimizing images, you can lazy-load images! What do I mean by this? A gif is a better explanation:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8thpo8aqjv3gdwp7iskn.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8thpo8aqjv3gdwp7iskn.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check out my &lt;a href="https://vincentntang.com" rel="noopener noreferrer"&gt;personal site here for the example&lt;/a&gt;! I use GatsbyJS on my personal blog, and what you see happening here is the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I hard refreshed the page&lt;/li&gt;
&lt;li&gt;Before the image loads, a lower-res image loads first&lt;/li&gt;
&lt;li&gt;When the actual image loads, it replaces the lower-res image&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is really only possible with JAMstack applications like Gatsby! Traditional SSGs don't support Javascript features like this out of the box and requires a lot of work to configure. Whereas Gatsby, which uses React, has access to all the wonderful React libraries out there! It makes it easy to plug and play.&lt;/p&gt;

&lt;p&gt;Let's not forget how easy it is to integrate 3rd party APIs! I wrote an article about how to &lt;a href="https://www.vincentntang.com/installing-gatsbyjs-blog-comments/" rel="noopener noreferrer"&gt;install blog comments in your Gatsby site&lt;/a&gt;, which uses an external API.&lt;/p&gt;

&lt;h2&gt;
  
  
  In summary
&lt;/h2&gt;

&lt;p&gt;In summary, I wrote this article because I find there's a lot of misconceptions about what JAMstack and Static Site Generators (SSG) are. I myself found it very confusing what the differences were until I actually played around with Jekyll, Gatsby, and many other SSGs that I didn't mention.&lt;/p&gt;

&lt;p&gt;To summarize:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Static Site Generators (SSG) solve the pain points of a blog, marketing, or read-only site with minimal updates. Instead of modifying 100 &lt;code&gt;.html&lt;/code&gt; files, you modify a &lt;code&gt;post-template&lt;/code&gt; and write markdown, and the SSG creates the &lt;code&gt;.html&lt;/code&gt; files for you. Meaning, less maintenance work long term. An example of this is Jekyll&lt;/li&gt;
&lt;li&gt;All JAMstack apps are SSGs, but the reverse is not true. What separates JAMstack apps from SSGs is the &lt;strong&gt;Javascript&lt;/strong&gt; portion, in that it uses more recent frontend tools like React for better UX. A JAMstack tool example is Gatsby, which uses React and NodeJS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When it comes to when to, and when not to use a JAMstack app or SSG&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JAMstack and SSGs are best for read-only sites. That means you don't want to build a dynamic and constantly updating e-commerce site with it, else you deal with crazy build times. If you're building a feature-rich web app or startup, you're actually better off building a separate backend (NodeJS) and a separate frontend (React) and not using JAMstack or SSGs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's a list of popular JAMstack apps as of the end of 2020&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="http://gatsbyjs.com/" rel="noopener noreferrer"&gt;Gatsby&lt;/a&gt; - which runs React&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://vuepress.vuejs.org/" rel="noopener noreferrer"&gt;VuePress&lt;/a&gt; - which runs Vue&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://gridsome.org/" rel="noopener noreferrer"&gt;Gridsome&lt;/a&gt; - which runs Vue&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's a list of popular SSGs, that are technically not JAMstack apps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://gohugo.io/" rel="noopener noreferrer"&gt;Hugo&lt;/a&gt; - It sometimes gets lumped in as a JAMstack app, but technically it's just an SSG since it just uses GO-lang to render files behind the scenes&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://jekyllrb.com/" rel="noopener noreferrer"&gt;Jekyll&lt;/a&gt; - Jekyll was the first popular SSG, as you could power it on &lt;a href="https://pages.github.com/" rel="noopener noreferrer"&gt;githubpages&lt;/a&gt; since it's written in Ruby and Github is too!&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://hexo.io/" rel="noopener noreferrer"&gt;Hexo&lt;/a&gt; - Hexo was the first major SSG written in NodeJS. It became popular in China before it came to the states, so you'll find a lot of theme authors are Chinese. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Check out some of the JAMstack apps I built (in Gatsby!)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://vincentntang.com" rel="noopener noreferrer"&gt;vincentntang.com&lt;/a&gt; - My personal blog, source code is &lt;a href="https://github.com/vincentntang/vincentntang.com" rel="noopener noreferrer"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://codechefs.dev" rel="noopener noreferrer"&gt;codechefs.dev&lt;/a&gt; - I run a podcast for junior to mid-level developers seeking to level up! Source code is &lt;a href="https://github.com/vincentntang/codechefs" rel="noopener noreferrer"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ssg</category>
      <category>jamstack</category>
      <category>gatsby</category>
      <category>react</category>
    </item>
    <item>
      <title>On writing a custom RSS feed for GatsbyJS</title>
      <dc:creator>Vincent Tang</dc:creator>
      <pubDate>Wed, 25 Nov 2020 23:01:06 +0000</pubDate>
      <link>https://forem.com/vincentntang/on-writing-a-custom-rss-feed-for-gatsbyjs-10o2</link>
      <guid>https://forem.com/vincentntang/on-writing-a-custom-rss-feed-for-gatsbyjs-10o2</guid>
      <description>&lt;p&gt;We recently released a podcast site built in GatsbyJs called &lt;a href="https://codechefs.dev" rel="noopener noreferrer"&gt;CodeChefs&lt;/a&gt;. I made a write up on how to build your own podcast site from scratch &lt;a href="https://www.vincentntang.com/custom-podcast-site-gatsby-react/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
Including how to generate the RSS that's consumed on different podcast platforms like Spotify and iTunes.&lt;/p&gt;

&lt;p&gt;However, we've run into an issue. We couldn't get one of the podcast platforms, &lt;a href="https://stitcher.com" rel="noopener noreferrer"&gt;stitcher.com&lt;/a&gt;, to support our RSS feeds. During the submission process, it would just get held up:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8dct2koihizef5nrv5ew.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8dct2koihizef5nrv5ew.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I reached out directly to Stitcher for support, in hopes to resolve the issue. It just seemed weird that all other platforms but this one supported our RSS feeds. This was the support response I got back:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8p5pnr3yp32feevg0qwr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8p5pnr3yp32feevg0qwr.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Not terribly helpful, I got the "reach out to the admin of the site for assistance". Unfortunately, that's me! I did a little digging and found that stitcher uses &lt;a href="http://validator.w3.org/" rel="noopener noreferrer"&gt;http://validator.w3.org&lt;/a&gt; for validating RSS feeds. Upon submitting the feed, we got this error:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Schema Error: XML document with no namespace; cannot determine any schema to use for validation.&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Upon searching through this issue, I found NO solutions whatsoever for resolving this issue! It just became more questions and no answers. &lt;/p&gt;
&lt;h2&gt;
  
  
  Back to the drawing board
&lt;/h2&gt;

&lt;p&gt;Instead of taking a top-down approach to the problem, I felt it would be best to understand how Gatsby is generating RSS feeds.&lt;/p&gt;

&lt;p&gt;Through some digging, I found the plugin Gatsby uses for RSS feed generation is called &lt;a href="https://www.gatsbyjs.com/plugins/gatsby-plugin-feed/" rel="noopener noreferrer"&gt;Gatsby-plugin-feed&lt;/a&gt;. And through a separate &lt;a href="https://github.com/gatsbyjs/gatsby/issues/27476" rel="noopener noreferrer"&gt;issue&lt;/a&gt; I created on Gatsby's Github Page, I found out it uses &lt;a href="https://github.com/dylang/node-rss" rel="noopener noreferrer"&gt;node-rss&lt;/a&gt; behind the scenes to generate the XML for the RSS.&lt;/p&gt;

&lt;p&gt;Upon looking through the repo, I was slightly disappointed. The repo is in maintenance mode, and the last PR merge to it was back in 2017. There were dozens of open/closed PR that were ignored and didn't pass &lt;a href="https://travis-ci.org/" rel="noopener noreferrer"&gt;TravisCI&lt;/a&gt;, which meant the author has since moved on with the project. Meaning if I open a PR and actually implement a fix, it probably would be ignored.&lt;/p&gt;

&lt;p&gt;I decided to dig through the issue log regardless, curious as to what problems people were having. I stumbled upon this random comment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Experiencing similar problem with VLC (for a podcast). 
Finally got it to work by removing the CDATA section from the title tag. 
Now the feed is being recognized by the reader.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A possible solution to the problem I'm having! I didn't know what &lt;a href="https://en.wikipedia.org/wiki/CDATA" rel="noopener noreferrer"&gt;CDATA&lt;/a&gt; was actually for, but upon searching Wikipedia, I found it's mostly used to support &lt;code&gt;&amp;amp;&lt;/code&gt; characters. Which makes sense, our site was currently using that character for the &lt;code&gt;&amp;lt;author&amp;gt;&lt;/code&gt; tag.&lt;/p&gt;

&lt;p&gt;Now I checked the RSS our site was outputting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;rss&lt;/span&gt; &lt;span class="na"&gt;xmlns:dc=&lt;/span&gt;&lt;span class="s"&gt;"http://purl.org/dc/elements/1.1/"&lt;/span&gt; &lt;span class="na"&gt;xmlns:content=&lt;/span&gt;&lt;span class="s"&gt;"http://purl.org/rss/1.0/modules/content/"&lt;/span&gt; &lt;span class="na"&gt;xmlns:atom=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2005/Atom"&lt;/span&gt; &lt;span class="na"&gt;xmlns:itunes=&lt;/span&gt;&lt;span class="s"&gt;"http://www.itunes.com/dtds/podcast-1.0.dtd"&lt;/span&gt; &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;"2.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;channel&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;![CDATA[ Code Chefs - Hungry Web Developer Podcast ]]&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;description&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;![CDATA[ Looking to expand your skills as a Web Developer? Vincent Tang and German Gamboa break down topics in Javascript, NodeJS, CSS, DevOps, AWS, and career development! ]]&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/description&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our site was outputting &lt;code&gt;CDATA&lt;/code&gt; tags on the &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;description&amp;gt;&lt;/code&gt;. So this clued me in on a potential fix. So I needed to modify the RSS generator such that it no longer outputted those tags.&lt;/p&gt;

&lt;p&gt;I scoured through the &lt;code&gt;node-rss&lt;/code&gt; package to see if there were any details on how to set this up. RSS feeds couldn't be that difficult to make could they? I decided to inspect the source code instead, which ended up being a mere 189 lines of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;generateXML&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;

    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;channel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;           &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;_cdata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;     &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;_cdata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I found exactly what I was looking for! How the CDATA was being generated on our site. Unfortunately, the &lt;code&gt;_cdata&lt;/code&gt; tag was hardcoded here for both the &lt;code&gt;title&lt;/code&gt; and &lt;code&gt;description&lt;/code&gt;, which meant there is no configuration for disabling it.&lt;/p&gt;

&lt;p&gt;That just makes things so much more complicated. I didn't even know if this solution would even work! I'm basing all of these decisions just on a random comment I came across. &lt;/p&gt;

&lt;p&gt;Therefore, I needed to validate if removing the &lt;code&gt;_cdata&lt;/code&gt; tags would fix the RSS issues I was having. &lt;/p&gt;

&lt;h2&gt;
  
  
  Running a local MVP test
&lt;/h2&gt;

&lt;p&gt;I needed a quick and dirty test. Since the &lt;code&gt;gatsby-plugin-feed&lt;/code&gt; was already installed on our repo, and probably imported &lt;code&gt;node-rss&lt;/code&gt; behind the scenes, I figured I could just modify the file directly. I removed the &lt;code&gt;_cdata&lt;/code&gt; values here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;generateXML&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;

    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;channel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the new RSS feed worked! But I needed a way to test this out against &lt;a href="https://validator.w3.org/" rel="noopener noreferrer"&gt;https://validator.w3.org/&lt;/a&gt;. Unfortunately, using &lt;code&gt;localhost&lt;/code&gt; doesn't cut it, as the site needs to be deployed.&lt;/p&gt;

&lt;p&gt;I didn't want to run this through our CI/CD pipeline through &lt;a href="https://netlify.com/" rel="noopener noreferrer"&gt;Netlify&lt;/a&gt; until I was sure it worked. What I did instead was run &lt;a href="https://ngrok.com/" rel="noopener noreferrer"&gt;ngrok&lt;/a&gt;, which tunnels information through a port of my choosing. So &lt;code&gt;localhost:8000/rss.xml&lt;/code&gt; now just became accessible at &lt;code&gt;https://cb996f9480ed.ngrok.io/rss.xml&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Great! Now we're in business! I submitted this publically available URL on &lt;a href="https://stitcher.com" rel="noopener noreferrer"&gt;stitcher.com&lt;/a&gt; to see if it worked:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fww43gi0lf6u95rivp2h9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fww43gi0lf6u95rivp2h9.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And it did! This meant &lt;code&gt;CDATA&lt;/code&gt; had to be removed on the &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;description&amp;gt;&lt;/code&gt; for the RSS to be accepted at this site&lt;/p&gt;

&lt;h2&gt;
  
  
  Making the solution permanent
&lt;/h2&gt;

&lt;p&gt;Yet another dilemma. Even though I had a working solution, I still couldn't actually get this to run on our site. You aren't supposed to modify &lt;code&gt;node_modules&lt;/code&gt; locally, as this means another computer can't duplicate the deployment process. This means I still can't deploy on Netlify.&lt;/p&gt;

&lt;p&gt;I only had a few solutions at hand:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Modify the RSS package with a PR, and make another PR towards the Gatsby Plugin&lt;/li&gt;
&lt;li&gt;Make a Gatsby Plugin with the forked RSS package&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The 2nd option made more sense, so that's what I opted to do.&lt;/p&gt;

&lt;p&gt;Through Gatsby Docs, I found you can create a local plugin &lt;a href="https://www.gatsbyjs.com/docs/creating-a-local-plugin/" rel="noopener noreferrer"&gt;here&lt;/a&gt; by running this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gatsby new gatsby-plugin-foo https://github.com/gatsbyjs/gatsby-starter-plugin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This generates a starter plugin that I could modify. Next thing I did was convert this starter template, and merging this through the source code for &lt;a href="https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-plugin-feed" rel="noopener noreferrer"&gt;Gatsby-plugin-feed&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I changed the dependency so instead of using &lt;code&gt;node-rss&lt;/code&gt; here, it would use my custom modified package instead&lt;/p&gt;

&lt;p&gt;There were numerous issues putting this all together. Gatsby for whatever reason used &lt;code&gt;import&lt;/code&gt; statements on these backend files, which is Javascript syntax, not &lt;code&gt;nodeJs&lt;/code&gt; syntax. So I modified accordingly, but this created several async/await issues that then had to be fixed.&lt;/p&gt;

&lt;p&gt;The next set of issues I ran across was installing &lt;code&gt;package.json&lt;/code&gt; in both a subfolder and a root folder. I did some research and found that &lt;code&gt;npm&lt;/code&gt; ships with a default config called &lt;code&gt;postinstall&lt;/code&gt;, which is a command that runs after &lt;code&gt;npm install&lt;/code&gt;. So you can install subfolders of your choosing, or even do a rainbow match of folders to install&lt;/p&gt;

&lt;p&gt;Once everything looked good, I made a &lt;a href="https://github.com/vincentntang/codechefs/pull/39" rel="noopener noreferrer"&gt;PR&lt;/a&gt; against my &lt;code&gt;development&lt;/code&gt; branch so Netlify can rebuild to these newest changes too.&lt;/p&gt;

&lt;p&gt;And it worked!&lt;/p&gt;

&lt;p&gt;Feel free to check out the source code and local plugin:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/vincentntang/codechefs" rel="noopener noreferrer"&gt;source code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://codechefs.dev/rss.xml" rel="noopener noreferrer"&gt;rss&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://codechefs.dev" rel="noopener noreferrer"&gt;codechefs website&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;EDIT: I just realized the RSS issue we were having on stitcher podcast site was actually on stitcher's side! But we still modified our RSS successfully :) &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>debugging</category>
      <category>rss</category>
      <category>gatsby</category>
      <category>react</category>
    </item>
    <item>
      <title>Installing Blog Comments on your GatsbyJs/React Site using Utterances</title>
      <dc:creator>Vincent Tang</dc:creator>
      <pubDate>Sat, 21 Nov 2020 17:37:39 +0000</pubDate>
      <link>https://forem.com/vincentntang/installing-gatsbyjs-blog-comments-using-utterances-1h8j</link>
      <guid>https://forem.com/vincentntang/installing-gatsbyjs-blog-comments-using-utterances-1h8j</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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuo8ngaf1c8n4cf7gg6d9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuo8ngaf1c8n4cf7gg6d9.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Adding a commenting system into a blog platform is really useful. I wanted something that didn't require a lot of configuration, was open source, and had data stored in a visible way in the event I needed to move around blogging platforms. I also didn't want something externally controlled like &lt;a href="https://wptavern.com/disqus-hits-sites-with-unwanted-advertising-plans-to-charge-large-publishers-a-monthly-fee-to-remove-ads" rel="noopener noreferrer"&gt;Disqus&lt;/a&gt;, as they've been known to inject ads into your site.&lt;/p&gt;

&lt;p&gt;Enter &lt;a href="https://utteranc.es/" rel="noopener noreferrer"&gt;Utterances&lt;/a&gt;. It's based on Github's search API, so that means it's free and open-source! &lt;br&gt;
It uses Github's issue tracker to create an entry, and all comments in that entry are tied directly to a blog post&lt;/p&gt;
&lt;h2&gt;
  
  
  How does it work?
&lt;/h2&gt;

&lt;p&gt;So for instance, say I take my blog post on &lt;a href="https://www.vincentntang.com/custom-podcast-site-gatsby-react/" rel="noopener noreferrer"&gt;Building a Custom Podcast Site using Gatsby, ReactJs, Netlify, and AmazonS3&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The article lives here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.vincentntang.com/custom-podcast-site-gatsby-react/" rel="noopener noreferrer"&gt;https://www.vincentntang.com/custom-podcast-site-gatsby-react/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is something called a "slug" or a "pathname". It's basically everything that is after the main website name, in this case, &lt;code&gt;www.vincentntang.com&lt;/code&gt;. Here's the slug for the article:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/custom-podcast-site-gatsby-react&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If I add a comment to that blog post, here's what it looks like on the page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fw17p5qgur7a4o0iq6yqf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fw17p5qgur7a4o0iq6yqf.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have it configured so that the utterance bot creates an issue in this repo, tied to that "slug":&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/vincentntang/vincentntang.com-comments" rel="noopener noreferrer"&gt;https://github.com/vincentntang/vincentntang.com-comments&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the default out of the box setting with Utterances; the setting I used is &lt;code&gt;Issue title contains page pathname&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Also there's no code in this repo, it just has Utterances installed  on the repo, per step 2 on installation on the &lt;a href="https://utteranc.es/" rel="noopener noreferrer"&gt;utterances webpage&lt;/a&gt;. This means you install a widget on the repo and grant Utterances read/write permissions to create issues in there.&lt;/p&gt;

&lt;p&gt;So Utterances creates an issue here, and each comment in this issue gets mapped directly into your blog post's comments.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fy842ack38ku5nrkjydxf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fy842ack38ku5nrkjydxf.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can check out the issue tracker created here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/vincentntang/vincentntang.com-comments/issues/1" rel="noopener noreferrer"&gt;https://github.com/vincentntang/vincentntang.com-comments/issues/1&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The main benefit of using Utterances is you fully own the comments on your site since it lives in your repository. Its secondary benefit is it fights spam since users have to authenticate in Github first to make a comment. There are no anonymous comments, and it creates a trust system for both the commenter and the blogger&lt;/p&gt;
&lt;h2&gt;
  
  
  How do you configure this in GatsbyJs React?
&lt;/h2&gt;

&lt;p&gt;It took me way too long to figure out this configuration. I'm writing the blog I wish I had read when I tried getting Utterances setup.&lt;/p&gt;

&lt;p&gt;Utterances works by adding a &lt;code&gt;script&lt;/code&gt; tag into your blog post &lt;code&gt;template&lt;/code&gt;. What it does is it adds an &lt;code&gt;iframe&lt;/code&gt; into your site, with the comments associated with your blog post. &lt;/p&gt;

&lt;p&gt;In the installation &lt;a href="https://utteranc.es/" rel="noopener noreferrer"&gt;readme&lt;/a&gt;, it suggests adding this script here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://utteranc.es/client.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="nx"&gt;repo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[ENTER REPO HERE]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="nx"&gt;issue&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;term&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pathname&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;github-light&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="nx"&gt;crossorigin&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;anonymous&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;async&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the &lt;code&gt;repo=[ENTER REPO HERE]&lt;/code&gt;, this got me tripped up. I thought that it meant the full URL of the repo, in this case:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/vincentntang/vincentntang.com-comments" rel="noopener noreferrer"&gt;https://github.com/vincentntang/vincentntang.com-comments&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But the actual configuration for the &lt;code&gt;repo=[ENTER REPO HERE]&lt;/code&gt; is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;vincentntang/vincentntang.com-comments&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the full configuration for the &lt;code&gt;script&lt;/code&gt; element looks like this for my current setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://utteranc.es/client.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="nx"&gt;repo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vincentntang/vincentntang.com-comments&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="nx"&gt;issue&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;term&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pathname&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;github-light&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="nx"&gt;crossorigin&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;anonymous&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;async&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hold up a moment though! There's actually more to this, you need to reference a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; for where this &lt;code&gt;script&lt;/code&gt; tag injects it's &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt; comments. This is where I had to read through a lot of obscure blogs to find out how to set this up in GatsbyJs and React.&lt;/p&gt;

&lt;p&gt;The best way to handle this is to create a seperate React Component for installing Utterances. I called my component &lt;code&gt;Comments.js&lt;/code&gt; and wrote it in React Class Components. Here's how I add the script configuration in React:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ThemeContext&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../context/ThemeContext&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Comments&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;contextType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ThemeContext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt; 
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;commentBox&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createRef&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Creates a reference to inject the &amp;lt;script&amp;gt; element&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;componentDidMount &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;utteranceTheme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dark&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;github-dark&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;github-light&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;scriptEl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;scriptEl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;src&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://utteranc.es/client.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;scriptEl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;crossorigin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;anonymous&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;scriptEl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;async&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;scriptEl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;repo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vincentntang/vincentntang.com-comments&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;scriptEl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;issue-term&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pathname&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;scriptEl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;theme&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;utteranceTheme&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;commentBox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scriptEl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;comment-box-wrapper container pt-7&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mb-0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Comments&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;hr&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;commentBox&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;comment-box&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Above element is where the comments are injected */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This &lt;code&gt;Comments&lt;/code&gt; class component uses &lt;code&gt;React.createRef()&lt;/code&gt; to create a reference for how the Utterances &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; element is injected. There's a &lt;code&gt;&amp;lt;div ref={this.commentBox}/&amp;gt;&lt;/code&gt; for the div element that adds the comment HTML from that &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; injection.&lt;/p&gt;

&lt;p&gt;Also, I use both a dark, and a light theme mode in my blog. Utterances has a configuration for setting a theme, &lt;code&gt;github-light&lt;/code&gt; and &lt;code&gt;github-dark&lt;/code&gt; being the most common configurations. I use React's &lt;a href="https://reactjs.org/docs/context.html" rel="noopener noreferrer"&gt;Context API&lt;/a&gt; to make this variable globally available, so I know when a user toggles the dark/light mode in my blog. &lt;/p&gt;

&lt;p&gt;This is where the code in &lt;code&gt;ComponentDidMount&lt;/code&gt; comes into play:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;utteranceTheme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dark&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;github-dark&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;github-light&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// .....&lt;/span&gt;
&lt;span class="nx"&gt;scriptEl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;theme&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;utteranceTheme&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you don't have a dark/light theme in your app, feel free to modify the above code to a dark theme:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;scriptEl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;theme&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;github-dark&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or a light theme:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;scriptEl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;theme&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;github-light&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That should be everything you need for setting up Utterances! You'll also need to call the &lt;code&gt;&amp;lt;Comments&amp;gt;&lt;/code&gt; component too in your blog template. I put mine right below the information about the author&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PostTemplate&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Layout&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;
            &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;dangerouslySetInnerHTML&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;__html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;postNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt; 
           &lt;span class="p"&gt;}}&lt;/span&gt;
          &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/article&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserInfo&lt;/span&gt; &lt;span class="nx"&gt;gatsbyImg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;vincentBlue&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Comments&lt;/span&gt;&lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Layout&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Feel free to checkout out how I setup the &lt;code&gt;&amp;lt;Comments&amp;gt;&lt;/code&gt; component in my codebase:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/vincentntang/vincentntang.com/blob/master/src/components/Comments.js" rel="noopener noreferrer"&gt;Comment.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/vincentntang/vincentntang.com/blob/master/src/templates/post.js" rel="noopener noreferrer"&gt;Post.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.vincentntang.com/custom-podcast-site-gatsby-react/" rel="noopener noreferrer"&gt;Article with comments&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/vincentntang/vincentntang.com-comments/issues/1" rel="noopener noreferrer"&gt;Comments living in the repo issue tracker for that article&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a final note, there are some things you should know about themes in Utterances:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can't change the comment theme when a user toggles light/dark mode, it's set depending on what theme is set when the user navigates to the page. You have to completely unmount the &lt;code&gt;Comments&lt;/code&gt; Component and create a new seperate instance of it if you want to have toggleable dark/light modes.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>comment</category>
      <category>utterances</category>
      <category>gatsby</category>
      <category>react</category>
    </item>
    <item>
      <title>How competing in hackathons helped me land my first job</title>
      <dc:creator>Vincent Tang</dc:creator>
      <pubDate>Fri, 20 Nov 2020 21:52:27 +0000</pubDate>
      <link>https://forem.com/vincentntang/how-competing-in-hackathons-helped-me-land-my-first-job-3k63</link>
      <guid>https://forem.com/vincentntang/how-competing-in-hackathons-helped-me-land-my-first-job-3k63</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XQYdurue--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/vc0600dwyav05r6h25kn.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XQYdurue--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/vc0600dwyav05r6h25kn.jpeg" alt="" width="800" height="580"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I got my frontend certifications with FreeCodeCamp back in 2017. I remember how daunting it was applying to jobs and feeling ready for the workforce. Everytime I sent an application in, I felt like it went to the void, never to be heard from again.&lt;/p&gt;

&lt;p&gt;I wanted a way to standout amongst other applicants, and coding bootcamp students. I challenged myself everyday to "level up" as quickly as possible, and ultimately I ended up competing in a lot of hackathons.&lt;/p&gt;

&lt;p&gt;It taught me a lot of things that I wouldn't have traditionally have gotten learning on my own. I learned how to work with others in a team setting, use git, use 3rd party libraries, and had a lot of mentorship and help along the way from senior developers&lt;/p&gt;

&lt;p&gt;When I started applying to jobs, one employer took a chance on me. I was far from qualified compared to other applicants applying to the position. But he could tell that I was eager to learn new things and picked up things rather quickly, thanks to competing in hackathons. So he took a chance, and the rest is history.&lt;/p&gt;

&lt;p&gt;I'm hoping to give back to the community from where I started from. I recently launched a podcast with one of my really close coding friends. It's called Code Chefs.&lt;/p&gt;

&lt;p&gt;We recently recorded a podcast about our experiences with Hackathons&lt;br&gt;
&lt;a href="https://codechefs.dev/hackathons"&gt;https://codechefs.dev/hackathons&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hopefully this helps anyone looking to learn more about what a hackathon is and what you can learn from it!&lt;/p&gt;

&lt;p&gt;Also writing out what I learned along the way helped too! &lt;br&gt;
&lt;a href="https://vincentntang.com"&gt;https://vincentntang.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>hackathon</category>
      <category>job</category>
      <category>career</category>
      <category>programming</category>
    </item>
    <item>
      <title>Building a Podcast Site using Gatsby, React, Netlify, and Amazon S3</title>
      <dc:creator>Vincent Tang</dc:creator>
      <pubDate>Sun, 15 Nov 2020 19:44:35 +0000</pubDate>
      <link>https://forem.com/vincentntang/building-a-podcast-site-using-gatsby-react-netlify-and-amazon-s3-58m7</link>
      <guid>https://forem.com/vincentntang/building-a-podcast-site-using-gatsby-react-netlify-and-amazon-s3-58m7</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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxz4acojp77mkrhhgdqdy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxz4acojp77mkrhhgdqdy.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;6 months ago, I reached out to one of my best buddies to start a coding podcast! We wanted to reflect upon our journey as software developers thus far, and push ourselves to greater limits.&lt;/p&gt;

&lt;p&gt;Only recently, we released our podcast to all the major platforms! It's here at &lt;a href="https://codechefs.dev" rel="noopener noreferrer"&gt;Code Chefs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We decided to build everything from scratch! We wanted full control over the distribution. So we could customize how it gets pushed out to Spotify, how ads are controlled, etc. And a website that could also be a podcast player too!&lt;/p&gt;

&lt;p&gt;Here's how it's done with GatsbyJs, React, Netlify, and Amazon S3&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview of how the stack works
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fn9yki9z55v8bfkwbh4y5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fn9yki9z55v8bfkwbh4y5.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;TL;DR &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GatsbyJS hosts the website, markdown files, and generates RSS feeds for podcast platforms to consume&lt;/li&gt;
&lt;li&gt;AmazonS3 hosts mp3 files&lt;/li&gt;
&lt;li&gt;Netlify pushes the gatsby site to the frontend&lt;/li&gt;
&lt;li&gt;ReactJS for a custom media player on the website&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;GatsbyJS is a popular JAMstack framework built in React. It's used often in the blogging world, and a podcast website isn't that terribly different. Where one episode = one blog post.&lt;/p&gt;

&lt;p&gt;Most podcast platforms like Spotify, Apple Podcasts, etc are controlled by an RSS feed. Since GatsbyJS provides this out of the box too, this meant we could fine-tune it to different platforms.&lt;/p&gt;

&lt;p&gt;Hosting mp3 files is a different issue entirely. It equates to about 1-2 mB post-processed for every minute of audio. Hosting these files within the same bandwidth as the static frontend site doesn't make sense, so we opted for amazon S3&lt;/p&gt;

&lt;p&gt;AmazonS3 is a great place for deploying static assets like images, videos, or mp3 files. It doesn't cost a lot either, I don't have analytics yet but it comes up to a few cents every month.&lt;/p&gt;

&lt;p&gt;We specify in our &lt;code&gt;.md&lt;/code&gt; files within Gatsby, where the hosted mp3 files are located in S3. This is then pulled into the RSS feed created when Gatsby builds. &lt;/p&gt;

&lt;p&gt;We push this code using Netlify where the site is hosted at &lt;code&gt;https://codechefs.dev&lt;/code&gt;. Netlify has a CI/CD feature that lets you target a branch in your GitHub repo (in this case &lt;code&gt;development&lt;/code&gt;), and anytime that branch is updated, the frontend site is too&lt;/p&gt;

&lt;p&gt;The code for our podcast site is open source! Check it out on &lt;a href="https://github.com/vincentntang/codechefs" rel="noopener noreferrer"&gt;here on github&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  GatsbyJs and RSS Configuration
&lt;/h2&gt;

&lt;p&gt;If you've used ReactJS before, GatsbyJS is actually quite confusing to learn. At least it was for me! It wasn't until I wrote a starter theme template that I understood how it all worked &lt;a href="https://github.com/vincentntang/gatsby-hooks-starter-theme" rel="noopener noreferrer"&gt;here&lt;/a&gt;. I'll break it down into the simplest explanation possible though, so bear with me!&lt;/p&gt;

&lt;p&gt;GatsbyJS is both a backend and frontend system. It's built-in NodeJS and React. When a GatsbyJS site is hosted on Netlify or even your localhost, only static (frontend) contents are shown. &lt;strong&gt;You need to build the frontend!&lt;/strong&gt; When you type in the command line &lt;code&gt;$ gatsby build&lt;/code&gt;, it uses NodeJS to look through the contents of the repo. Then it generates SEO friendly posts and pages, and RSS feeds thereafter&lt;/p&gt;

&lt;p&gt;This is why GatsbyJS works great as a blogging platform! The only changes you make to the site are generally when new blog posts, or in this case, new podcast episodes are released. It doesn't work well for applications that require frequent real-time updates, like a stock trading app.&lt;/p&gt;

&lt;p&gt;GatsbyJS's backend build time is configured based on two files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/vincentntang/codechefs/blob/development/gatsby-config.js" rel="noopener noreferrer"&gt;gatsby-config.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/vincentntang/codechefs/blob/development/gatsby-node.js" rel="noopener noreferrer"&gt;gatsby-node.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The above links are the actual files used for our podcasting site, Code Chefs!&lt;/p&gt;

&lt;p&gt;If you read through those two files, it's hard to grasp what it's doing at a glance. That's because it built on top of GraphQL, and Gatsby has specific library helpers in the background doing a lot of heavy work. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;Gatsby-node.js&lt;/code&gt; is the entry point for building the static frontend. It generates SEO friendly web pages, categories, tags, etc.&lt;/p&gt;

&lt;p&gt;Most &lt;code&gt;gatsby-node.js&lt;/code&gt; files look relatively the same, so I'll cover how &lt;code&gt;gatsby-config.js&lt;/code&gt; configuration works for RSS feeds&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Gatsby-config.js&lt;/code&gt; is all the plugins for generating markdown content to HTML, RSS feeds, amongst other things. If you ever used WordPress, they are just like WordPress plugins! It's libraries that you can just import to help do common tasks that you otherwise don't have to write&lt;/p&gt;

&lt;p&gt;For &lt;code&gt;gatsby-config.js&lt;/code&gt;, there's a plugin called &lt;code&gt;gatsby-plugin-feed&lt;/code&gt;. This is how we generate RSS feeds to Spotify, Apple Podcasts, etc!&lt;/p&gt;

&lt;p&gt;Here's the plugin configuration for &lt;code&gt;gatsby-plugin-feed&lt;/code&gt;, which generates the RSS for all the platforms&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gatsby-plugin-feed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;site&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;siteMetadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rssMetadata&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;allMarkdownRemark&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;allMarkdownRemark&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;generator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GatsbyJS Advanced Starter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    {
      site {
        siteMetadata {
          rssMetadata {
            site_url
            feed_url
            title
            description
            image_url
            copyright
          }
        }
      }
    }
  `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// https://www.npmjs.com/package/rss#feedoptions to override any specs&lt;/span&gt;
    &lt;span class="na"&gt;custom_namespaces&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;itunes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://www.itunes.com/dtds/podcast-1.0.dtd&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;site_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://codechefs.dev&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;custom_elements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;language&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;itunes:author&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Vincent Tang &amp;amp; German Gamboa&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;itunes:explicit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;clean&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;itunes:subtitle&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hungry Web Developer Podcast&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;itunes:summary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Looking to expand your skills as a Web Developer? Vincent Tang and German Gamboa break down topics in Javascript, NodeJS, CSS, DevOps, AWS, and career development!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;itunes:owner&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;itunes:name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Vincent Tang&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;itunes:email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vincentntang@gmail.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;]},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;itunes:category&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;_attr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;News&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;}},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;itunes:category&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;_attr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Tech News&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}}&lt;/span&gt;
      &lt;span class="p"&gt;]},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;itunes:category&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;_attr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Technology&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;}},&lt;/span&gt;
      &lt;span class="p"&gt;]},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;itunes:category&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;_attr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Education&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;itunes:type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;episodic&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;itunes:image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;_attr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://codechefs.dev/logos/code_chefs_podcast_art.png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;}},&lt;/span&gt;
      &lt;span class="p"&gt;]},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;url&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://codechefs.dev/logos/code_chefs_podcast_art.png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Code Chefs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;link&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://codechefs.dev&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;]},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;itunes:keywords&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;javascript, webdevelopment,html,css,js, codechefs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="nx"&gt;feeds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;serialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rssMetadata&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;site&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;siteMetadata&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;allMarkdownRemark&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;edge&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;frontmatter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;frontmatter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;excerpt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rssMetadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;site_url&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;guid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rssMetadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;site_url&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;custom_elements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
              &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;content:encoded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
              &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;itunes:author&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Vincent Tang &amp;amp; German Gamboa&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
              &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;itunes:subtitle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;excerpt&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
              &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;itunes:duration&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;frontmatter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;showLength&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
              &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;itunes:explicit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;no&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
              &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;enclosure&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;_attr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3bucket&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;frontmatter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;audioPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;frontmatter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fileSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// megabytes to bytes&lt;/span&gt;
                  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;audio/mpeg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;}},&lt;/span&gt;
              &lt;span class="p"&gt;]},&lt;/span&gt;
            &lt;span class="p"&gt;]&lt;/span&gt;
          &lt;span class="p"&gt;}));&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
        {
          allMarkdownRemark(
            limit: 1000,
            sort: { order: DESC, fields: [fields___date] },
          ) {
            edges {
              node {
                excerpt
                html
                timeToRead
                fields {
                  slug
                  date
                }
                frontmatter {
                  title
                  cover
                  date
                  category
                  tags
                  shortDescription
                  episodeNumber
                  audioPath
                  showLength
                  fileSize
                }
              }
            }
          }
        }
      `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;siteRss&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;siteRssTitle&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This generates the XML RSS feeds at &lt;code&gt;https://codechefs.dev/rss.xml&lt;/code&gt; upon deployment. It first outputs data about the site, then each episode is wrapped in an XML &lt;code&gt;&amp;lt;item&amp;gt;&lt;/code&gt; tag&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkukhy4ghiywyocp6u1oi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkukhy4ghiywyocp6u1oi.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feel free to check out the generate RSS feed for codechefs &lt;a href="https://www.codechefs.dev/rss.xml" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Amazon S3 Configuration
&lt;/h2&gt;

&lt;p&gt;Amazon S3 hosts the raw mp3 files for different podcast distributions to consume. Everything on this bucket is public by default since any listener should be able to access it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fk8iiulyoxnjta2reeonc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fk8iiulyoxnjta2reeonc.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By enabling this setting, anytime you upload an mp3 to the s3 bucket, it is publically read-accessible&lt;/p&gt;

&lt;p&gt;You may also have to make each mp3 file uploaded to be read-accessible by the public, to do this, click the file and go to Access Control List(ACL) and grant it read properties&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fl84scyec104fkgqrhqv0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fl84scyec104fkgqrhqv0.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also, you can add cloudwatch on your amazonS3 bucket, and google analytics on your site to see stats related to your site&lt;/p&gt;

&lt;h2&gt;
  
  
  ReactJS Audio Player
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7n876ht8filcyotb6zjl.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7n876ht8filcyotb6zjl.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ReactJS is used as the physical podcast player on the site. The default HTML audio player is rather limited, so we use React to build custom event handlers and custom UI to control those events.&lt;/p&gt;

&lt;p&gt;Things like being able to control the playback speed of the file, volume levels, pausing the episode, etc&lt;/p&gt;

&lt;p&gt;Here's the source code for the &lt;a href="https://github.com/vincentntang/codechefs/tree/development/src/components/audio" rel="noopener noreferrer"&gt;audio player&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'll write a separate blog post later for how this works!&lt;/p&gt;

&lt;h2&gt;
  
  
  Netlify + Github
&lt;/h2&gt;

&lt;p&gt;Netlify is used to deploy the GatsbyJS site, whereas Github is used to host the code itself. We configure Gatsby to update based on the latest changes in the &lt;code&gt;development&lt;/code&gt; branch in our repo.&lt;/p&gt;

&lt;p&gt;Here's what the setup looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6hv8cnx8nayc6ewrtt95.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6hv8cnx8nayc6ewrtt95.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Netlify also controls the custom domain. We point our name records from hosting provider, Namecheap, and point it Netlify. You can find more information about that &lt;a href="https://docs.netlify.com/domains-https/custom-domains/" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The workflow process
&lt;/h2&gt;

&lt;p&gt;Here's how everything comes together! How we go from brainstorming an episode, to getting it published on all the podcasting platforms:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First, we write a list of show notes on google docs, this is used to help brainstorm what we'll talk about before we record the episode&lt;/li&gt;
&lt;li&gt;We warm up in the first 20 minutes talking about the content&lt;/li&gt;
&lt;li&gt;Then we record on zencastr for the audio, and Zoom video so it feels more like a natural conversation&lt;/li&gt;
&lt;li&gt;Afterwards, we download each audio track, combine it, and post-process it using Audacity&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The file is then uploaded to AmazonS3 manually, and we create a blog markdown file in GatsbyJS with the metadata. It looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;React&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;vs.&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Vue"&lt;/span&gt;
&lt;span class="na"&gt;slug&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;react-vs-vue"&lt;/span&gt;
&lt;span class="na"&gt;cover&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;code_chefs_podcast_art.png"&lt;/span&gt;
&lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2020-05-23&lt;/span&gt;
&lt;span class="na"&gt;audioPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;002_react_vs_vue.mp3&lt;/span&gt;
&lt;span class="na"&gt;episodeNumber&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;002&lt;/span&gt;
&lt;span class="na"&gt;fileSize&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;67.8&lt;/span&gt;
&lt;span class="na"&gt;showLength&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;49:23&lt;/span&gt;
&lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tech"&lt;/span&gt;
&lt;span class="na"&gt;shortDescription&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;How&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;do&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;these&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;two&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;popular&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;frontend&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;frameworks&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;compare&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;with&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;each&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;other?"&lt;/span&gt;
&lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;programming&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;react&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;vue&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gu"&gt;### How do these two popular frontend frameworks compare with each other?&lt;/span&gt;

In this episode, we discuss the similarities and differences between React and ..........
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;fileSize&lt;/code&gt; refers to how many megabytes the final recorded final size is. Apple in particular wants this data (and a lot of other data related to the podcast), so it's important to gather this information ahead of time. There are ways to automatically determine file sizes dynamically, but it's not that much effort though to check the mp3 file size contents. &lt;code&gt;showLength&lt;/code&gt; refers to how long the mp3 file is. &lt;code&gt;audioPath&lt;/code&gt; is the name of the file itself, we also prepend the s3 bucket to this location so Gatsby knows where that file is located&lt;/p&gt;

&lt;p&gt;After this blog post is created, we push it to a &lt;code&gt;development&lt;/code&gt; branch. Netlify then reads the changes against this branch and publishes the new RSS feeds. &lt;/p&gt;

&lt;p&gt;It takes about 3 - 4 hours for each podcast platform to update from this feed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Hopefully, this helps you in creating your own podcast site! We didn't find a huge amount of information on creating a GatsbyJS podcast site from scratch, so we made the guide we wish we had when we first started&lt;/p&gt;

&lt;p&gt;Additional Links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://codechefs.dev" rel="noopener noreferrer"&gt;codechefs.dev&lt;/a&gt; - Our podcast site&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/vincentntang/codechefs" rel="noopener noreferrer"&gt;code chefs source code&lt;/a&gt; - Source Code&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://vincentntang.com" rel="noopener noreferrer"&gt;vincentntang.com&lt;/a&gt; - Personal website&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>gatsby</category>
      <category>podcast</category>
      <category>react</category>
      <category>rss</category>
    </item>
    <item>
      <title>Learning Vue as a React Developer</title>
      <dc:creator>Vincent Tang</dc:creator>
      <pubDate>Wed, 07 Aug 2019 00:42:02 +0000</pubDate>
      <link>https://forem.com/vincentntang/learning-vue-as-a-react-developer-385l</link>
      <guid>https://forem.com/vincentntang/learning-vue-as-a-react-developer-385l</guid>
      <description>&lt;p&gt;React. The first major JavaScript framework I decided to learn coming from jQuery land.&lt;/p&gt;

&lt;p&gt;My journey learning was painful. I had to watch three different Udemy tutorials to finally get it. Months were spent wrapping my head around this foreign way of coding.&lt;/p&gt;

&lt;p&gt;I slowly and surely learned the basics, such how state management works and how the React lifecycle operates. These things came with time and eventually I learned to use this knowledge to build apps in hackathons and to build tools I would use in my daily life.&lt;/p&gt;

&lt;p&gt;The time came to start my first development job as part of a team that used Vue. I didn't know anything about this framework and I felt like I had to learn JavaScript all over again.&lt;/p&gt;

&lt;p&gt;This intense but interesting new journey where I transitioned from React to Vue left me with the following valuable lessons that I want to share with you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;Vue has a CLI like Create-React-App, but gives you more control with what settings you get out of the box. For instance, you can choose whether you want to include client-side routing or CSS Pre-processors like Sass.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Styling and Syntax
&lt;/h2&gt;

&lt;p&gt;React uses JSX which lets you write HTML-like syntax.&lt;/p&gt;

&lt;p&gt;Writing in Vue was like revisiting the good old days of EJS or any templating language. No longer did I have to write my HTML, and then convert it to JSX. I could just write HTML^TM and be on my way.&lt;/p&gt;

&lt;p&gt;Here's an example of what a typical Vue file looks like:&lt;/p&gt;

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

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{{&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello World&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;style&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"scss"&lt;/span&gt; &lt;span class="na"&gt;scoped&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nc"&gt;.h1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;style&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Assuming you declared your Vue component at the top level, this just outputs a "Hello World" string in red color.&lt;/p&gt;

&lt;p&gt;In Vue, you write single file components. By convention, your component file will include the declaration of your template at the top, followed by a script definition with all the component logic, and it wii close with any necessary style declarations.&lt;/p&gt;

&lt;p&gt;React, on the other hand, is less opinionated on file structure. You can still create single file components but instead of implementing the template in HTML and the styling in SCSS, for example, you would write everything in Javascript: template in JSX and styling in CSS-in-JS. This is demonstrated in this example:&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyFirstComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello World&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// CSS in JS&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;red&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;but you could also just import a &lt;code&gt;.css&lt;/code&gt; or &lt;code&gt;.scss&lt;/code&gt; file as well. The problem you run into though when using an import, is you pollute the global namespace. As your app and your team grows, chances are high your developer co-worker might name a class the same as yours.&lt;/p&gt;

&lt;p&gt;You could opt to use a library like &lt;code&gt;styled-components&lt;/code&gt;. This gives you a Sass-like syntax to tightly couple your styles with your JSX.&lt;/p&gt;

&lt;p&gt;React brings another set of issues. Do you use a functional component or stateful component? By default, it's better to use only what you need, but this means potentially more refactoring down the road. This doesn't factor in that you can use React Hooks now instead of class components.&lt;/p&gt;

&lt;h2&gt;
  
  
  Props, State
&lt;/h2&gt;

&lt;p&gt;React has something called props, which is data loaded in from the parent component. And something called state, data intrinsic to that component.&lt;/p&gt;

&lt;p&gt;Here's an example of just rendering a "Hello World" message:&lt;/p&gt;

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

&lt;span class="c1"&gt;// React Parent Component&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Child&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Child&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Parent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello World&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Child&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

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

&lt;span class="c1"&gt;// React Child Component&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Child&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Child&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;With Vue, the concepts were the same. But Vue prefers convention over configuration. Meaning, there are specific naming conventions. Child components declared in parent component are in camelCase. When the component is added to the HTML, the syntax is then kebab-case.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

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

&lt;span class="c"&gt;&amp;lt;!-- Vue Parent Component --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;child-component&lt;/span&gt; &lt;span class="na"&gt;:message=&lt;/span&gt;&lt;span class="s"&gt;"message"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ChildComponent&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./ChildComponent.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello world&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;ChildComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;


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

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

&lt;span class="c"&gt;&amp;lt;!-- Vue Child Component --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    &lt;span class="si"&gt;{{&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="si"&gt;}}&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Vue requires you to declare a child component twice, once on import another on &lt;code&gt;Components&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;React differs in that there is one less step, you import the file then use it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Type Enforcement
&lt;/h2&gt;

&lt;p&gt;One thing I miss in static languages like C# or Java is type enforcement. Javascript is a dynamic scripting language. Meaning it doesn't care if a variable is a string, number, boolean, etc.&lt;/p&gt;

&lt;p&gt;When you declare a string, you can always typecast it to a number after. This makes scaling large frontend apps difficult. Because you might not know what data type you're working with.&lt;/p&gt;

&lt;p&gt;React natively solves this with &lt;code&gt;PropTypes&lt;/code&gt;. Example in the &lt;code&gt;&amp;lt;Child/&amp;gt;&lt;/code&gt; component we made earlier:&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PropTypes&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;prop-types&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Child&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;Child&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;propTypes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PropTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isRequired&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Child&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;There are a few issues with propTypes in React&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It's really easy to misspell&lt;/li&gt;
&lt;li&gt;It's optional&lt;/li&gt;
&lt;li&gt;You have to declare an import&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because of these reasons, I find myself forgetting to use propTypes. You could opt to use Typescript instead with React, but this just means more additional time configuring your setup.&lt;/p&gt;

&lt;p&gt;Vue requires the declaration of props, and propTypes are in the same location. Inside your &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag where all the other logic lives&lt;/p&gt;

&lt;p&gt;Example of a child component:&lt;/p&gt;

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

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    &lt;span class="si"&gt;{{&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="si"&gt;}}&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;style&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"scss"&lt;/span&gt; &lt;span class="na"&gt;scoped&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;style&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;This is a much better design overall and makes it so that Typescript is not necessary in Vue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data Reactivity
&lt;/h2&gt;

&lt;p&gt;This was the concept that tripped me on Vue several times. In React, everything is reactive. Meaning you can add properties to objects, and React would call it's lifecycle when properties changed.&lt;/p&gt;

&lt;p&gt;In Vue ... things don't work the same. In React, every time you modify state, you could pass a new entire state object.&lt;/p&gt;

&lt;p&gt;Vue differed in that you &lt;em&gt;mutated&lt;/em&gt; your state directly through methods. Because we're intrinsically adding side effects, you have to actually &lt;em&gt;declare&lt;/em&gt; when new properties are being added to the object.&lt;/p&gt;

&lt;p&gt;Namely using something called &lt;code&gt;Vue.set()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A common example of when you would use this is if your loading data from the backend. And need to create new data to send back.&lt;/p&gt;

&lt;p&gt;You also have to define a &lt;code&gt;key&lt;/code&gt; value for components that have been iterated. React / Vue work the same way, it lets the library know what parts to rerender on data changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Watchers and Observables
&lt;/h2&gt;

&lt;p&gt;I never quite understood design patterns that well. But the term "observable" finally made sense to me.&lt;/p&gt;

&lt;p&gt;Vue has something called watchers. This lets you call a method every time a specific variable changes.&lt;/p&gt;

&lt;p&gt;However, there's some caveats, because you could have watchers watching watchers. This causes circular referential issues.&lt;/p&gt;

&lt;p&gt;The Vue docs warn against this. I myself have accidentally done this using inputs to watch over other inputs.&lt;/p&gt;

&lt;p&gt;React's implementation of watchers is through the lifecycle method of &lt;code&gt;componentDidUpdate&lt;/code&gt;. You select which items you wish to watch independently inside of here.&lt;/p&gt;

&lt;p&gt;For the React Hooks implementation, &lt;code&gt;useState&lt;/code&gt; is another implementation of an observable&lt;/p&gt;

&lt;h2&gt;
  
  
  Computed properties
&lt;/h2&gt;

&lt;p&gt;This was a new concept to me, from the React world. In Vue, you can have variables that depend on other variables. Anytime a dependency changes, so does the computed property.&lt;/p&gt;

&lt;p&gt;It seems useful at first, but computed properties are only good if you aren't modifying it at all directly.&lt;/p&gt;

&lt;p&gt;When you start needing to, this is when you go away from computed properties entirely to the next item...&lt;/p&gt;

&lt;h2&gt;
  
  
  Methods
&lt;/h2&gt;

&lt;p&gt;Methods in Vue worked the same as in React. These methods were called through event-directives that extend from HTML DOM events. Examples include putting &lt;code&gt;@click&lt;/code&gt; events, or &lt;code&gt;@input&lt;/code&gt; if a user typed text in an input field.&lt;/p&gt;

&lt;p&gt;Methods are what you'll always fall back in Vue when computed properties and watchers don't fit your use-case.&lt;/p&gt;

&lt;p&gt;Methods are like any function in javascript. The return statement is optional, you can just use it to mutate data in the background.&lt;/p&gt;

&lt;h2&gt;
  
  
  Asynchronous Gotchas
&lt;/h2&gt;

&lt;p&gt;This is a gotcha that you find out later in Vue, and in React. &lt;br&gt;
In React, there is a built-in method called &lt;code&gt;setState()&lt;/code&gt;. When &lt;code&gt;setState()&lt;/code&gt; gets called, it gets handled asynchronously in the background.&lt;/p&gt;

&lt;p&gt;Vue is no different, you have a method called &lt;code&gt;Vue.nextTick()&lt;/code&gt; that awaits the latest updated value to the data.&lt;/p&gt;

&lt;p&gt;One lesson I learned is that it's best to set local variables within your methods, and only mutate data attributes as needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Templates
&lt;/h2&gt;

&lt;p&gt;With Vue, there is something called &lt;code&gt;templates&lt;/code&gt;. In your component, you have the ability to declare &lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt; slots. When that component gets called, you can inject HTML where those slots match.&lt;/p&gt;

&lt;p&gt;This has been immensely useful when working in libraries. I could inject functionality as I saw fit, to get the feature I needed.&lt;/p&gt;

&lt;p&gt;Templates do not get rendered as a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; element in the DOM. React has a similar approach to templates called fragments, but the approach is limited to just the first element in your component.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lifecycle methods
&lt;/h2&gt;

&lt;p&gt;Lifecycle methods describe what components do during their lifetime.&lt;/p&gt;

&lt;p&gt;Here are common ones you'll use in Vue:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;mounted() - Similar to React's &lt;code&gt;componentDidMount&lt;/code&gt;. This generally when making an Axios/fetch call to initialize data in your component from a backend.&lt;/li&gt;
&lt;li&gt;updated() - Similar to React's &lt;code&gt;componentDidUpdate&lt;/code&gt;. When you update data through your components, you want to send a POST request to your backend to keep things in sync&lt;/li&gt;
&lt;li&gt;destroyed() - Similar to React's &lt;code&gt;componentWillUnmount&lt;/code&gt;. You don't need to use this, but it helps clean up leftover event listeners.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Hooks
&lt;/h2&gt;

&lt;p&gt;Hooks makes React an extremely powerful framework. No longer did you have to use redux for handling state, you could just use &lt;code&gt;useState()&lt;/code&gt; instead. No longer did you have to deal with &lt;code&gt;setState()&lt;/code&gt;, there were a slew of other new improved methods to use.&lt;/p&gt;

&lt;p&gt;Vue has no equivalent to hooks, although there is an RFC at the time of writing this&lt;/p&gt;

&lt;h2&gt;
  
  
  Directives
&lt;/h2&gt;

&lt;p&gt;Vue's built-in directives make development a breeze. You could create iterable directives right inside your HTML.&lt;/p&gt;

&lt;p&gt;In React, this often meant making another component called "group(s)" and maybe one called "group".&lt;/p&gt;

&lt;p&gt;Vue, you can just dump the &lt;code&gt;v-for&lt;/code&gt;, &lt;code&gt;v-if&lt;/code&gt; etc right inside your HTML. Your logic coherently just makes sense looking at it.&lt;/p&gt;

&lt;p&gt;Alternatively, you can write your own directives! This lets you attach functionality to page if necessary, making it easier to develop faster&lt;/p&gt;

&lt;p&gt;One great use case for startups is to develop a reporting system. If a user clicks on a feature that doesn't yet exist, you can add a popup modal saying "Sorry we're working hard on this new feature! Come back later". In the background, you can make Axios request to notify users really do want that feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mixins
&lt;/h2&gt;

&lt;p&gt;Some companies swear by these. It's a reusable code snippet library that can be implemented across multiple components. React out of the box does not have such a feature, you can alternatively use callback functions instead that are made globally available&lt;/p&gt;

&lt;h2&gt;
  
  
  Emitting Events
&lt;/h2&gt;

&lt;p&gt;Props are passed from parent to child component, via one-way data binding. To handle business logic at the parent level, from the child component, you generally emit events.&lt;/p&gt;

&lt;p&gt;With Vue, there are two different ways.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You can pass a reference to the function from parent to child&lt;/li&gt;
&lt;li&gt;Emit an event from the child and capture the response in parent&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Most applications generally use #2. Example from a button that triggers a method in the parent component&lt;/p&gt;


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

&lt;p&gt;&lt;span class="c"&gt;&amp;lt;!-- Parent Component --&amp;gt;&lt;/span&gt;&lt;br&gt;
&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;br&gt;
  &lt;span class="nt"&gt;&amp;lt;ChildComponent&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;event-emitted=&lt;/span&gt;&lt;span class="s"&gt;"_handleUpdatedEvent"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;&lt;br&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ChildComponent&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./components/ChildComponent.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
    &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
      &lt;span class="nx"&gt;ChildComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;&lt;br&gt;
    &lt;span class="na"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
      &lt;span class="nf"&gt;_handleUpdatedEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Button was clicked&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;&lt;br&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;&lt;br&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;&lt;br&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;

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

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

&lt;p&gt;&lt;span class="c"&gt;&amp;lt;!-- Child Component --&amp;gt;&lt;/span&gt;&lt;br&gt;
&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;br&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"hello"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;br&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click=&lt;/span&gt;&lt;span class="s"&gt;"$emit('event-emitted')"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Click Me&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;&lt;br&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;br&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;

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

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Global State Management&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;Vue's CLI comes with the ability to add Vuex out of the box.  &lt;/p&gt;

&lt;p&gt;In React you pass a new set of state using &lt;code&gt;setState()&lt;/code&gt;, Redux only extends this through global dispatches/flux architecture. &lt;/p&gt;

&lt;p&gt;In Vue, you mutate objects behind the scene. Vuex is no different but at the global level. &lt;/p&gt;

&lt;p&gt;Vue natively ships with the ability to create a global event bus, which is similar to React's context API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Learning Vue has been a great way to learn new programming paradigms.&lt;/p&gt;

&lt;p&gt;Many principles in React translate over to Vue. There are a few things that differ, namely:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You don't replace your state, you mutate it which creates data reactivity and async gotchas.&lt;/li&gt;
&lt;li&gt;New constructs. There are computed properties, watchers, and mixins that don't exist in React out of the box&lt;/li&gt;
&lt;li&gt;You write HTML and styles the way you would traditionally in a regular HTML page.&lt;/li&gt;
&lt;li&gt;PropTypes are optional in Vue and React, but Vue requires less effort to enforce.&lt;/li&gt;
&lt;li&gt;Styling. In Vue you just write Sass or CSS, it's super easy compared to React.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are some of the differences from React to Vue. Some things that are similar include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lifecycle methods&lt;/li&gt;
&lt;li&gt;Props/State&lt;/li&gt;
&lt;li&gt;Assigning keys to iterated items&lt;/li&gt;
&lt;li&gt;Methods / functions&lt;/li&gt;
&lt;li&gt;Passing events upward&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>vue</category>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>VueJS E-commerce Desk Configurator</title>
      <dc:creator>Vincent Tang</dc:creator>
      <pubDate>Mon, 08 Jul 2019 01:47:05 +0000</pubDate>
      <link>https://forem.com/vincentntang/vuejs-e-commerce-desk-configurator-1dn5</link>
      <guid>https://forem.com/vincentntang/vuejs-e-commerce-desk-configurator-1dn5</guid>
      <description>&lt;p&gt;I was shopping for a standing desk and stumbled upon this cool site:
&lt;a href="https://www.fully.com/standing-desks/jarvis/jarvis-adjustable-height-desk-bamboo.html"&gt;https://www.fully.com/standing-desks/jarvis/jarvis-adjustable-height-desk-bamboo.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;so I recreated it in codepen with some additions&lt;/p&gt;

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

</description>
      <category>codepen</category>
      <category>vue</category>
    </item>
  </channel>
</rss>
