<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: James Cote</title>
    <description>The latest articles on DEV Community by James Cote (@coteh).</description>
    <link>https://dev.to/coteh</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%2F451664%2Fd4966928-dd3f-4715-9a95-d806756f131c.jpeg</url>
      <title>DEV Community: James Cote</title>
      <link>https://dev.to/coteh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/coteh"/>
    <language>en</language>
    <item>
      <title>How to Deploy a React application using AWS Amplify</title>
      <dc:creator>James Cote</dc:creator>
      <pubDate>Thu, 19 Nov 2020 18:03:35 +0000</pubDate>
      <link>https://dev.to/coteh/how-to-deploy-a-react-application-using-aws-amplify-2g37</link>
      <guid>https://dev.to/coteh/how-to-deploy-a-react-application-using-aws-amplify-2g37</guid>
      <description>&lt;p&gt;One of the very first challenges I took on in my new position at TimePlay was figuring out how to deploy a React application to AWS Amplify.&lt;/p&gt;

&lt;p&gt;Amplify is one of the many services under the AWS umbrella that provides frontend developers with the ability to quickly spin up web hosting, GraphQL APIs, and more for their web applications. With all the backend components integrated and managed by AWS, frontend developers no longer need to worry about hassle of managing servers, and can instead focus on the frontend work at hand.&lt;/p&gt;




&lt;p&gt;In this article, I will go over the steps needed to deploy a single-page application (SPA) written in React to AWS Amplify. I will be using the Amplify CLI, which you can install using the following command: (assuming you have Node.js and npm already installed)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -g @aws-amplify/cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Additionally, for simplicity and to keep the focus of this tutorial on Amplify itself, I will literally be deploying the output of the base &lt;a href="https://create-react-app.dev/"&gt;create-react-app&lt;/a&gt; (CRA) creation command with TypeScript template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-react-app my-app --template typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's begin!&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1 - Configuration
&lt;/h2&gt;

&lt;p&gt;Run &lt;code&gt;amplify configure&lt;/code&gt;. This will open up a AWS IAM account page, and you'll have the option to either create a new IAM user for Amplify, or use an existing IAM user. The CLI will prompt you for preferred region and name of the new user, but you can provide an existing user's credentials in the following steps if you already have a user.&lt;/p&gt;

&lt;p&gt;Whether you create a new user or use an existing user, ensure that you have the following permissions set:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2OTlv6pl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/la6l0mmvvfbf68qo39th.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2OTlv6pl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/la6l0mmvvfbf68qo39th.png" alt="Permissions" width="471" height="164"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also, add this IAM policy to your AWS organization and attach it to the user. (either using Visual Editor or this JSON below)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "amplify:*",
            "Resource": "*"
        }
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you have configured your AWS user, the CLI will prompt you for the user's access key ID and secret access key. Enter those in, and leave AWS profile as &lt;code&gt;default&lt;/code&gt; unless you would like it to be something else. Now Amplify has been configured.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;⚠️ Important&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;For the purposes of this tutorial, these should be sufficient. However, I &lt;strong&gt;highly&lt;/strong&gt; suggest setting only the minimum number of permissions necessary for the Amplify user. Take a look at &lt;a href="https://docs.amplify.aws/cli/usage/iam"&gt;this page on the Amplify CLI documentation&lt;/a&gt; for more information on the necessary permissions required for Amplify actions.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Step 2 - Initialization
&lt;/h2&gt;

&lt;p&gt;Now that the user has been configured, on the root directory of the project, run &lt;code&gt;amplify init&lt;/code&gt;. Follow the prompts as you setup your Amplify project on the cloud. For this tutorial, you will select React application and Amplify CLI will configure itself to run the appropriate build commands when it’s time to deploy the app.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ℹ️ Note&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;You should also be able to follow through these steps with little modification if you're deploying an app built with another framework such as Vue or Angular. Amplify CLI also has options for these frameworks. Additionally, you can also deploy static HTML/CSS/JS using Amplify, as long as you have &lt;code&gt;src&lt;/code&gt; and &lt;code&gt;dist&lt;/code&gt; directories and the final build "output" ends up in &lt;code&gt;dist&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ℹ️ Note&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;When Amplify is initialized, it will have also generated an &lt;code&gt;amplify/&lt;/code&gt; directory and updated your &lt;code&gt;.gitignore&lt;/code&gt; to add ignore rules for Amplify-specific files. Push these to source control.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Step 3 - Add Hosting
&lt;/h2&gt;

&lt;p&gt;Now that Amplify is initialized for your project, run &lt;code&gt;amplify add hosting&lt;/code&gt; to add site hosting to your project. You can select "Hosting with Amplify Console" to let Amplify manage the full deployment pipeline for you. (ie. S3 buckets and CloudFront distributions will be created, but the CloudFront distributions will not be on your AWS account) You can also select "Amazon CloudFront and S3" to manage the S3 buckets and CloudFront distributions yourself.&lt;/p&gt;

&lt;p&gt;At the time of this writing, the CLI will present the following options for your hosting based on your selection:&lt;/p&gt;

&lt;h3&gt;
  
  
  "Hosting with Amplify Console" Options
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Amplify Console&lt;/code&gt; will allow you to use your Git repo hosted on a provider such as GitHub, GitLab, Bitbucket, or CodeCommit, and any push you make will trigger a CD pipeline that's managed by Amplify.&lt;/li&gt;
&lt;li&gt;You can also select the &lt;code&gt;manual&lt;/code&gt; option if you plan on deploying manually or as part of another CI/CD pipeline such as CircleCI or Jenkins. You can also drag'n'drop files using the browser if you use this method — useful for designers and non-technical people to publish their updates. For this tutorial, we will choose this option.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "Amazon CloudFront and S3" Options
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Insecure HTTP (S3)&lt;/code&gt; option will allow you to only deploy the built site to an S3 bucket. This is useful if you plan on adding CDN using CloudFront or another CDN provider separately. We use this at TimePlay as our CloudFront distributions are handled using Terraform.&lt;/li&gt;
&lt;li&gt;There's also a &lt;code&gt;Secure HTTPS (S3+CloudFront)&lt;/code&gt; method if you would like to deploy to S3 and front it with CloudFront CDN in one step.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ℹ️ Note&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;You should invalidate CDN cache after every deploy so that your changes are propagated. If you use Amplify Console to manage your deployment, it will do this for you. If you deploy using &lt;code&gt;S3+CloudFront&lt;/code&gt; option, you can pass &lt;code&gt;--invalidateCloudFront&lt;/code&gt; to &lt;code&gt;amplify publish&lt;/code&gt; to have the Amplify CLI perform an invalidation request.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Step 4 - Deploy
&lt;/h2&gt;

&lt;p&gt;Now that we've added hosting, run &lt;code&gt;amplify publish&lt;/code&gt; to build and deploy your application to Amplify.&lt;/p&gt;

&lt;p&gt;Once it finishes deploying successfully, it will provide you with a link that you can access to view your deployment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LeHkKKbZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mxh0nzo4y4wthmc1hbis.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LeHkKKbZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mxh0nzo4y4wthmc1hbis.png" alt="Screen Shot 2020-10-16 at 12.23.22 PM" width="880" height="550"&gt;&lt;/a&gt; &lt;/p&gt;




&lt;p&gt;Now you have a React application successfully deployed to the Cloud in a few easy steps using Amplify! Hope you found this tutorial useful, and do not hesitate to leave a comment if there's anything I may have missed.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://www.pexels.com/photo/abstract-aluminum-architectural-architecture-210158/"&gt;Cover Photo&lt;/a&gt; by &lt;a href="https://www.pexels.com/@pixabay"&gt;Pixabay&lt;/a&gt; on &lt;a href="https://www.pexels.com/"&gt;Pexels&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>6 Continuous Integration tools you can use for an Open Source project</title>
      <dc:creator>James Cote</dc:creator>
      <pubDate>Thu, 24 Sep 2020 16:56:40 +0000</pubDate>
      <link>https://dev.to/coteh/6-continuous-integration-tools-you-can-use-for-an-open-source-project-313m</link>
      <guid>https://dev.to/coteh/6-continuous-integration-tools-you-can-use-for-an-open-source-project-313m</guid>
      <description>&lt;p&gt;I've made it a habit to setup Continuous Integration (CI) pipelines for each of my personal side projects. A CI pipeline can run all tests within a project automatically, and provide immediate feedback if there's any failures. This has given me more confidence in the software I write, and has resulted in better quality code written.&lt;/p&gt;

&lt;p&gt;If you're building an open source project, there are a number of free solutions available to automatically build and test your code. These services also have Continuous Deployment (CD) built-in as well, so you can also automatically deploy your project to production after all tests pass. In no particular order, I list each of the services I have found below, and what they offer for free, open source, users.&lt;/p&gt;




&lt;h1&gt;
  
  
  1. CircleCI
&lt;/h1&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%2Fkcv2k6bc3qvmvuzjh3po.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%2Fkcv2k6bc3qvmvuzjh3po.png" alt="CircleCI"&gt;&lt;/a&gt;&lt;br&gt;
Image Source: &lt;a href="https://boards.greenhouse.io/circleci" rel="noopener noreferrer"&gt;https://boards.greenhouse.io/circleci&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;CircleCI is one of the most well-known providers of CI and CD out there. Originally founded in 2011 and based in San Francisco, they provide solutions for open source developers and business alike.&lt;/p&gt;

&lt;p&gt;They have a free plan that includes 1 concurrent job and 2,500 free credits per week for builds. Under the free usage plan, tests run on machines offering 2 CPUs and 4GB of memory. There is also no active user limit on the free usage plan. I have several side projects on CircleCI, and the free plan suits my needs.&lt;/p&gt;

&lt;p&gt;edit (Oct. 12): CircleCI also provides a &lt;a href="https://circleci.com/open-source/" rel="noopener noreferrer"&gt;free, open-source plan&lt;/a&gt; for public repositories, which contains 400,000 free credits per month for Linux builds, and 25,000 credits per month for macOS builds (on request).&lt;/p&gt;




&lt;h1&gt;
  
  
  2. Travis CI
&lt;/h1&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%2Fnh63tqj567jar3cpavwd.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%2Fnh63tqj567jar3cpavwd.png" alt="Travis CI"&gt;&lt;/a&gt;&lt;br&gt;
Image Source: &lt;a href="https://docs.travis-ci.com/" rel="noopener noreferrer"&gt;https://docs.travis-ci.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Founded in 2011 and based in Berlin, Germany, Travis CI is also a popular solution for both public and private projects.&lt;/p&gt;

&lt;p&gt;&lt;del&gt;Travis CI states that there will be no explicit pricing plan for open source projects and that for these types of projects, they'll always be free. All open source projects get 5 concurrent jobs and unlimited builds for free.&lt;/del&gt;&lt;/p&gt;

&lt;p&gt;edit (Nov. 2): Travis CI &lt;a href="https://blog.travis-ci.com/2020-11-02-travis-ci-new-billing" rel="noopener noreferrer"&gt;announced on November 2nd&lt;/a&gt; that open source projects will now only be given 10,000 credits, which allows for 1000 build minutes on a Linux environment. If you run out, you will need to file a request to Travis CI support with account name, VCS provider, and number of credits you'd like to request.&lt;/p&gt;

&lt;p&gt;I have several of my older side projects on Travis, but have since switched over to CircleCI because I found them to be more reliable in my personal (anecdotal) experience.&lt;/p&gt;




&lt;h1&gt;
  
  
  3. AppVeyor
&lt;/h1&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%2F5i7igh2i3xjqrxqjyd0m.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%2F5i7igh2i3xjqrxqjyd0m.png" alt="AppVeyor"&gt;&lt;/a&gt;&lt;br&gt;
Image Source: &lt;a href="https://status.appveyor.com/" rel="noopener noreferrer"&gt;https://status.appveyor.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AppVeyor is another CI service founded in 2011, and based in Vancouver, Canada. They specialize in CI solutions for Windows software — providing more Windows Server images than the other solutions mentioned in this article. However, they also provide macOS and Linux build options too.&lt;/p&gt;

&lt;p&gt;Their free plan only allows you to run 1 concurrent job, but if you hook up your own machines to run your builds, you can get 5 concurrent jobs for free. They also have a build time restriction of 60 minutes for free plans.&lt;/p&gt;




&lt;h1&gt;
  
  
  4. Drone CI
&lt;/h1&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%2F3xc459wjd5r9t4gr7tl1.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%2F3xc459wjd5r9t4gr7tl1.png" alt="Drone CI"&gt;&lt;/a&gt;&lt;br&gt;
Image Source: &lt;a href="https://github.com/drone/drone" rel="noopener noreferrer"&gt;https://github.com/drone/drone&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Founded in 2012, acquired in August 2020 by &lt;a href="https://harness.io/" rel="noopener noreferrer"&gt;Harness&lt;/a&gt;, and based in San Francisco, Drone CI specializes in providing a simple, lightweight Docker image that can be deployed onto a server. Additional runners can then be installed that poll the server container for tasks to run.&lt;/p&gt;

&lt;p&gt;They also provide a free service for open source repositories called &lt;a href="https://cloud.drone.io/" rel="noopener noreferrer"&gt;Drone Cloud&lt;/a&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  5. GitHub Actions
&lt;/h1&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%2Fudivhe0301qx413phr79.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%2Fudivhe0301qx413phr79.png" alt="GitHub Actions"&gt;&lt;/a&gt;&lt;br&gt;
Image Source: &lt;a href="https://technology.customink.com/blog/2019/09/02/from-travis-ci-to-github-actions/" rel="noopener noreferrer"&gt;https://technology.customink.com/blog/2019/09/02/from-travis-ci-to-github-actions/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GitHub also provides their own CI/CD solution called &lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;GitHub Actions&lt;/a&gt;. It can also be used for many other purposes such as issue creation and automatic comments in PRs. You can also utilize third-party plugins to automate workflows. This can be a good option if your repository is hosted on GitHub.&lt;/p&gt;

&lt;p&gt;Free plans include 2,000 minutes per month, and they are used up at different rates depending on operating system. At the time of this writing, a minute used up in a Linux system uses 1 minute of the plan, a minute in Windows uses up 2 minutes, and a minute in macOS uses up 10 minutes. Read more &lt;a href="https://docs.github.com/en/github/setting-up-and-managing-billing-and-payments-on-github/about-billing-for-github-actions" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  6. GitLab CI/CD
&lt;/h1&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%2Fvw5jlixlza2lenlal64b.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%2Fvw5jlixlza2lenlal64b.png" alt="GitLab CI/CD"&gt;&lt;/a&gt;&lt;br&gt;
Image Source: &lt;a href="https://about.gitlab.com/stages-devops-lifecycle/continuous-integration/" rel="noopener noreferrer"&gt;https://about.gitlab.com/stages-devops-lifecycle/continuous-integration/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Like GitHub, GitLab also provides their own CI/CD solution for their repositories. Also, like GitHub Actions, they provide third-party plugins and the ability to automate workflows besides building and testing.&lt;/p&gt;

&lt;p&gt;Their free plan &lt;a href="https://about.gitlab.com/releases/2020/09/01/ci-minutes-update-free-users/" rel="noopener noreferrer"&gt;has sadly been reduced to 400 a month from 2,000 as of September 1&lt;/a&gt;. However, like with GitHub Actions, it's still an option to consider if your project is hosted on GitLab. You can learn more about the specs of the runners they use &lt;a href="https://docs.gitlab.com/ee/user/gitlab_com/index.html#shared-runners" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;edit (Sept. 26): &lt;a href="https://dev.to/_garybell"&gt;@_garybell&lt;/a&gt; mentions in the comments that GitLab also has an &lt;a href="https://about.gitlab.com/solutions/open-source/" rel="noopener noreferrer"&gt;Open Source Program&lt;/a&gt; that allows open source projects to have Gold status for free, which contains 50,000 CI minutes. If your open source project(s) are eligible you can apply &lt;a href="https://about.gitlab.com/solutions/open-source/program/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;As someone just using CI for personal, open source, side projects, I can go with any of the options mentioned in this article. However, if I were to have an open source project with a large contributor base, I would have to consider the tradeoffs more carefully. I think it's great though that there are many options available to set up CI for a project. I wanted the focus of this article to be on highlighting the different solutions available and make it known for software developers what they can use for CI in their projects.&lt;/p&gt;

&lt;p&gt;I personally recommend anyone working on side projects to practice using CI. I have worked at several workplaces now that use CI for their projects, and I realize it's great to have a system like this in place to ensure correctness of new features and bugfixes. Therefore, I believe it's important to get familiar with these types of tools and understand how they can help software developers write better code.&lt;/p&gt;

&lt;p&gt;If there's another free CI solution out there that I did not mention in this article, do not hesitate to mention it in the comments. Cheers!&lt;/p&gt;




&lt;p&gt;&lt;a href="https://www.pexels.com/photo/gray-gold-and-red-industrial-machine-675987/" rel="noopener noreferrer"&gt;Cover Photo&lt;/a&gt; by &lt;a href="https://www.pexels.com/@skitterphoto" rel="noopener noreferrer"&gt;Skitterphoto&lt;/a&gt; on &lt;a href="https://www.pexels.com/" rel="noopener noreferrer"&gt;Pexels&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ci</category>
      <category>testing</category>
      <category>devops</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Automating Automated Tests with Ponicode</title>
      <dc:creator>James Cote</dc:creator>
      <pubDate>Fri, 11 Sep 2020 15:36:27 +0000</pubDate>
      <link>https://dev.to/coteh/automating-automated-tests-with-ponicode-1k3n</link>
      <guid>https://dev.to/coteh/automating-automated-tests-with-ponicode-1k3n</guid>
      <description>&lt;p&gt;Last week, I heard about this nifty unit testing tool called &lt;a href="https://ponicode.com/"&gt;Ponicode&lt;/a&gt;. It utilizes AI and context information from your code to automatically generate test cases for your functions. At the time of this writing, it is available as a Visual Studio Code extension.&lt;/p&gt;

&lt;p&gt;As someone who's written a decent amount of test cases throughout my early career, whether it's been on my co-op work terms or my side projects, I wanted to give this a spin. Setting up automated tests and configuring runners can take up a lot of time and distract me from the main tasks at hand, so I wanted to see how a tool like this can improve my workflow.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://ponicode.com/docs/get-started/installation"&gt;documentation&lt;/a&gt; provides a lot of useful information on how the tool works, which languages/syntax it currently supports, and information on how to install the tool, so I recommend checking it out to get started.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;⚠️ Important&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Code is sent to Ponicode's servers in order to be analyzed. Since the Ponicode team has not yet explicitly stated how they're handling data of program code sent to them, &lt;strong&gt;I have disabled Ponicode globally&lt;/strong&gt; on my VS Code installation at this time, and &lt;em&gt;only enabling it per workspace&lt;/em&gt;. I recommend you do the same, especially if you are working with confidential projects.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;p&gt;Once I installed Ponicode, I checked out the example project they included, which is a simple function that checks whether a provided string is an email, and it seems to work pretty well so far!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7SE75Zrq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/g88j2g2rkochf0cjr2lp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7SE75Zrq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/g88j2g2rkochf0cjr2lp.png" alt="Email Example" width="880" height="507"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another thing I enjoy so far is having a graphical interface to add and organize test cases for my code. You can add any of the test cases from the generated list to your project by clicking on the "+" button beside it. All added test cases will be written to a file named &lt;code&gt;&amp;lt;file&amp;gt;.test.js&lt;/code&gt;, where &lt;code&gt;&amp;lt;file&amp;gt;&lt;/code&gt; is the original name of the file you're generating tests for.&lt;/p&gt;

&lt;p&gt;The tests will be designed for &lt;a href="https://jestjs.io/"&gt;Jest&lt;/a&gt;, which is a downside for me because I prefer to use &lt;a href="https://mochajs.org/"&gt;Mocha&lt;/a&gt; for testing my JavaScript-based applications. The Ponicode team explains on their blog that they chose to integrate with Jest first in order to get as many people as possible to try out the tool. [1] Completely understandable, but it still would be nice if they eventually provide support for other runners such as Mocha.&lt;/p&gt;




&lt;p&gt;Let's see how Ponicode works outside of their sample project and on a more real-world project. I started opening up some of my open source side projects to see how well Ponicode would work for them. Ponicode only supports JavaScript at the time of this writing, so none of my React, TypeScript, Golang, or Python side projects will work. Also, only globally exported functions are supported at the moment, meaning no classes, static methods, getters/setters, or constructor methods. In addition, class instances, callbacks, and symbols aren't supported either. [2] This makes Ponicode pretty restrictive to just the JavaScript ecosystem at the moment, but hopefully support for other languages and frameworks will come soon.&lt;/p&gt;

&lt;p&gt;Lately, I've been making updates to an open-source &lt;a href="https://atom.io/"&gt;Atom&lt;/a&gt; extension that I created and currently maintain called &lt;a href="https://github.com/Coteh/syntaxdb-atom-plugin"&gt;syntaxdb-atom-plugin&lt;/a&gt;. One piece of functionality of the code, for percent encoding search terms sent to the &lt;a href="https://syntaxdb.com/"&gt;SyntaxDB&lt;/a&gt; API, looks like this:&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;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="nx"&gt;PercentEncoder&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;percentEncodeChar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;char&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;%&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;char&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;charCodeAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;);&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;percentEncodeStr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;for&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;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;result&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;isReservedChar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
                &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;percentEncodeChar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
                &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&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="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&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;isReservedChar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;char&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="nx"&gt;reservedMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;char&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8FVbQJF6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/r7m3hkw387xzx6vdn6by.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8FVbQJF6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/r7m3hkw387xzx6vdn6by.png" alt="Static methods not supported yet notification" width="880" height="111"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As mentioned above, static methods unfortunately do not work with Ponicode at the time of this writing. But, since this entire static class is better off as a single exported method anyway, I can refactor this and hopefully get a real-world example of Ponicode-generated tests for this article.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ℹ️ Note&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;During my refactor, I also noticed that whenever I make a syntax error, Ponicode would still notify me that it can't perform the test generation due to syntax error, even after fixing the error. I needed to switch to a different tab then switch back to fix this.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;After performing the refactor, I was able to get Ponicode to generate some test cases for me:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rMAq64u0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8xji6ztr4xk8bat0yul3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rMAq64u0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8xji6ztr4xk8bat0yul3.png" alt="Alt Text" width="880" height="515"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Very nice! We can see here that some characters within the strings are URL encoded, and after double checking with &lt;a href="https://en.wikipedia.org/wiki/Percent-encoding#Percent-encoding_reserved_characters"&gt;the Wikipedia article on percent-encoding&lt;/a&gt;, I can safely use these as expectations within my tests.&lt;/p&gt;




&lt;p&gt;Ponicode isn't perfect though — in one of my old projects back in 2015, &lt;a href="https://github.com/Coteh/hacka-news"&gt;hacka-news&lt;/a&gt;, I have a function that takes in an array of &lt;a href="https://news.ycombinator.com/"&gt;Hacker News&lt;/a&gt; article IDs, and only returns a slice of those ids up to the limit number that the user requested.&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;var&lt;/span&gt; &lt;span class="nx"&gt;pruneResults&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;limit&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;prunedIDs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;limit&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;prunedIDs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3sDQePdi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/usb5229gbe6vxbxcru2s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3sDQePdi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/usb5229gbe6vxbxcru2s.png" alt="pruneResults tests" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Unfortunately, Ponicode does not seem to pick up on what &lt;code&gt;ids&lt;/code&gt; and &lt;code&gt;limit&lt;/code&gt; mean.&lt;/p&gt;

&lt;p&gt;If I change the parameter names to &lt;code&gt;arrayOfIDs&lt;/code&gt; and &lt;code&gt;limitNum&lt;/code&gt; respectively, the results look more suitable:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QBL8JTAu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/go07uyr5ptr0hqh7po90.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QBL8JTAu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/go07uyr5ptr0hqh7po90.png" alt="pruneResults tests with new parameter names" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I can also adjust the parameter name in the percent encode function from the earlier example to get Ponicode to generate better test coverage:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2uF6IpbN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ge4ktcgt42w7so959ms1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2uF6IpbN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ge4ktcgt42w7so959ms1.png" alt="Percent encode test with better parameter name" width="880" height="646"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Ponicode also provides a feature where it invokes your program, observes the inputs and outputs of your functions, and uses those observations to improve test cases further. I decided not to use this as I don't believe it's very practical for real-world test development, especially if you're working with a library (such as hacka-news) or an extension (such as syntaxdb-atom-plugin), which are not normally invoked directly, and will require writing scaffolding code to get the Ponicode runner to execute code within these projects.&lt;/p&gt;

&lt;p&gt;During my research, I also found an insightful article on Ponicode from &lt;a href="https://sylvainleroy.com/"&gt;Sylvain Leroy&lt;/a&gt;, who has much more experience than I do in this area. [3] I recommend checking out his article if you want to learn more about Ponicode, as he provides a more critical analysis of the tool and suggests some great ideas that can improve it further.&lt;/p&gt;




&lt;p&gt;Overall, this addon has a lot of potential, even as just a nice GUI frontend that allows me to plop in test cases easily to get things rolling. However, where this addon falls short is the results of their AI-generated test cases, which seem to mostly provide irrelevant test cases and require a bit of tweaking of function parameters to improve. Despite this, I believe that the tool can have the potential to produce higher quality test cases in the future. Ultimately, I don't see myself using this tool for day-to-day developer work, but I am interested to see future developments of the tool — hopefully with more language support, more accessible features, and more effective test case generation.&lt;/p&gt;




&lt;p&gt;&lt;a&gt;&lt;/a&gt;[1] &lt;a href="https://blog.ponicode.com/2020/08/14/jest-versus-mocha-which-testing-framework-for-you/"&gt;https://blog.ponicode.com/2020/08/14/jest-versus-mocha-which-testing-framework-for-you/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;[2] &lt;a href="https://ponicode.com/docs/using-ponicode/testable-functions"&gt;https://ponicode.com/docs/using-ponicode/testable-functions&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;[3] &lt;a href="https://sylvainleroy.com/2020/07/23/ponicode-my-feedback-and-a-mixed-overall-feeling-about-the-tool/"&gt;https://sylvainleroy.com/2020/07/23/ponicode-my-feedback-and-a-mixed-overall-feeling-about-the-tool/&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://www.pexels.com/photo/colorful-toothed-wheels-171198/"&gt;Cover Photo&lt;/a&gt; by &lt;a href="https://www.pexels.com/@digitalbuggu"&gt;Digital Buggu&lt;/a&gt; from &lt;a href="https://www.pexels.com/"&gt;Pexels&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>testing</category>
      <category>tdd</category>
      <category>ai</category>
    </item>
    <item>
      <title>Power up create-react-app!</title>
      <dc:creator>James Cote</dc:creator>
      <pubDate>Thu, 27 Aug 2020 16:50:52 +0000</pubDate>
      <link>https://dev.to/coteh/power-up-create-react-app-14b8</link>
      <guid>https://dev.to/coteh/power-up-create-react-app-14b8</guid>
      <description>&lt;p&gt;&lt;strong&gt;create-react-app&lt;/strong&gt; (CRA) provides developers with the ability to quickly spin up single-page web applications (SPA) using the React framework without wasting time with configuration or version upgrades. It is a powerful toolkit that has helped make React a dominant player in the web framework space.&lt;/p&gt;

&lt;p&gt;There are times however when the out-of-the-box configuration provided by CRA is not enough. Perhaps you want to install a new tool, or you're behind a company firewall and need to use audited dependency versions. In situations like these, CRA provides you with the option to "eject" from the CRA setup. This will allow you to have full control over all dependencies and run scripts. However, this will also prevent you from receiving new upgrades to the React toolchain from CRA. It will also make the React setup much more difficult to manage for newcomers to the framework.&lt;/p&gt;

&lt;p&gt;If you want to have more control over your dependencies, but still receive upgrades and support to your React setup from CRA, there are two options available:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Forking the &lt;code&gt;react-scripts&lt;/code&gt; package&lt;/strong&gt; from the official CRA repository, which is a core dependency of CRA applications that contains all the other dependencies. By forking this package, you can add your own dependencies in an encapsulated manner, and all projects using the latest version of your fork will get them automatically.&lt;/li&gt;
&lt;li&gt;Introduced in CRA v3.3.0, a &lt;strong&gt;Custom Template&lt;/strong&gt; can be used to define a set of dependencies and scripts that can be added directly to a React project upon creation. (ie. direct dependency instead of through &lt;code&gt;react-scripts&lt;/code&gt;) Templates provide the benefit of adding dependencies to your project transparently and allows you to update them independently of other projects that use the template.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this post, I will walk through creating both a custom &lt;code&gt;react-scripts&lt;/code&gt; fork and a custom CRA template, and I will compare both of the solutions.&lt;/p&gt;




&lt;h1&gt;
  
  
  Forking &lt;code&gt;react-scripts&lt;/code&gt;
&lt;/h1&gt;

&lt;p&gt;To get started with forking &lt;code&gt;react-scripts&lt;/code&gt;, perform the following steps:&lt;/p&gt;

&lt;p&gt;1. Fork the &lt;a href="https://github.com/facebook/create-react-app"&gt;official create-react-app repository on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ℹ️ Note&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;You can also fork, or simply clone, the &lt;code&gt;packages/react-scripts&lt;/code&gt; folder specifically if you like, since that's all we're touching for this tutorial.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;2. Clone your newly forked repository to your local machine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/&amp;lt;YOUR GITHUB USERNAME&amp;gt;/create-react-app.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where &lt;code&gt;&amp;lt;YOUR GITHUB USERNAME&amp;gt;&lt;/code&gt; is your GitHub username, assuming you have performed step 1.&lt;/p&gt;

&lt;p&gt;3. Checkout the latest release branch of CRA rather than from &lt;code&gt;master&lt;/code&gt; branch to ensure stability. At the time of this writing, 3.4.1 is the latest release. [1]&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git checkout v3.4.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4. Now, navigate to the &lt;code&gt;react-scripts&lt;/code&gt; package, in &lt;code&gt;packages/react-scripts&lt;/code&gt;. Here is where the core CRA dependencies come from. By modifying this package, you will be changing what gets included in your React installation by default.&lt;/p&gt;

&lt;p&gt;In my case, I wanted to add &lt;a href="https://www.npmjs.com/package/jest-junit"&gt;jest-junit&lt;/a&gt;, which is an extension for &lt;a href="https://jestjs.io/"&gt;Jest&lt;/a&gt; that exports test results in &lt;a href="https://llg.cubic.org/docs/junit/"&gt;JUnit XML format&lt;/a&gt;, which can then be accepted by Continuous Integration (CI) tools such as &lt;a href="https://circleci.com/"&gt;CircleCI&lt;/a&gt; to provide readable test results on every build.&lt;/p&gt;

&lt;p&gt;I wanted this package to be included with all my current React projects, and every new one I make in the future. Thus, I installed it to the &lt;code&gt;react-scripts&lt;/code&gt; package in my fork. This will make it available in all my React apps, so long as it's pointing to my fork of &lt;code&gt;react-scripts&lt;/code&gt; instead of the official.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ℹ️ Note&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;I also recommend making your changes in a new branch within your fork, so that when you pull in changes from upstream (ie. if CRA were to be updated) it's easy to merge in with your custom version.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Once you finish making your changes, you will want to use your fork of &lt;code&gt;react-scripts&lt;/code&gt; instead of Facebook's. To do this, you will need to make some changes to its &lt;code&gt;package.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="err"&gt;{&lt;/span&gt;
-  "name": "react-scripts",
&lt;span class="gi"&gt;+  "name": "&amp;lt;custom&amp;gt;-react-scripts",
&lt;/span&gt;  "version": "3.4.1",
&lt;span class="gd"&gt;-  "description": "Configuration and scripts for Create React App.",
&lt;/span&gt;&lt;span class="gi"&gt;+  "description": "Custom configuration and scripts for Create React App.",
&lt;/span&gt;  "repository": {
    "type": "git",
&lt;span class="gd"&gt;-    "url": "https://github.com/facebook/create-react-app.git",
&lt;/span&gt;&lt;span class="gi"&gt;+    "url": "https://github.com/&amp;lt;YOUR GITHUB USERNAME&amp;gt;/create-react-app.git",
&lt;/span&gt;    "directory": "packages/react-scripts"
  },
  "license": "MIT",
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change &lt;code&gt;&amp;lt;custom&amp;gt;&lt;/code&gt; to something identifiable to you, and &lt;code&gt;&amp;lt;YOUR GITHUB USERNAME&amp;gt;&lt;/code&gt; to your GitHub username.&lt;/p&gt;

&lt;p&gt;You can test your custom &lt;code&gt;react-scripts&lt;/code&gt; with a new React project by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-react-app my-app --scripts-version file:../path/to/your/react-scripts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where &lt;code&gt;../path/to/your/react-scripts&lt;/code&gt; can be either a relative or absolute path to your forked &lt;code&gt;react-scripts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;--scripts-version&lt;/code&gt; argument allows for a custom &lt;code&gt;react-scripts&lt;/code&gt; to be installed in place of the official one. A name of an existing custom scripts from npm can be passed in, or a local copy can be passed in using the &lt;code&gt;file:&lt;/code&gt; prefix, like we did above.&lt;/p&gt;

&lt;p&gt;By making these changes, you will be able to publish it to the &lt;a href="https://www.npmjs.com/"&gt;npm registry&lt;/a&gt;, making it available for your React apps to install as a dependency.&lt;/p&gt;

&lt;p&gt;To publish your &lt;code&gt;react-scripts&lt;/code&gt; to npm, simply run &lt;code&gt;npm publish&lt;/code&gt; and login with your npm credentials when prompted.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ℹ️ Note&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ensure the name of your custom &lt;code&gt;react-scripts&lt;/code&gt; package isn't already taken on npm.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Once your fork has been published, you can switch the dependency in your app like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; {
   "name": "my-app",
   "version": "0.1.0",
   "private": true,
   "dependencies": {
&lt;span class="p"&gt;@@ -8,7 +8,7 @@&lt;/span&gt;
     "@testing-library/user-event": "^7.1.2",
     "react": "^16.13.1",
     "react-dom": "^16.13.1",
&lt;span class="gd"&gt;-    "react-scripts": "3.4.3"
&lt;/span&gt;&lt;span class="gi"&gt;+    "&amp;lt;custom&amp;gt;-react-scripts": "3.4.1"
&lt;/span&gt;   },
   "scripts": {
     "start": "react-scripts start",
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;&amp;lt;custom&amp;gt;&lt;/code&gt; is the identifiable name you gave to your forked &lt;code&gt;react-scripts&lt;/code&gt; from the previous step.&lt;/p&gt;

&lt;p&gt;You can also run &lt;code&gt;yarn remove react-scripts&lt;/code&gt; then &lt;code&gt;yarn add &amp;lt;custom&amp;gt;-react-scripts&lt;/code&gt; to install your fork.&lt;/p&gt;

&lt;p&gt;Since the CRA team is continuously making new updates to &lt;code&gt;react-scripts&lt;/code&gt;, you will need to keep your fork up-to-date as time goes on.&lt;/p&gt;

&lt;p&gt;First, ensure your local repository is connected to the CRA team's version by adding an upstream remote, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git remote add upstream https://github.com/facebook/create-react-app.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, fetch upstream by running &lt;code&gt;git fetch upstream&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After that, apply changes from upstream to your local copy by running &lt;code&gt;git checkout upstream/vX.X.X&lt;/code&gt;, where &lt;code&gt;X.X.X&lt;/code&gt; is the newest version released, then switching into your custom branch and merging changes into it. &lt;code&gt;git merge vX.X.X&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;There may be some conflicts, but should mostly just be simple version conflicts within &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Also, to use your fork of &lt;code&gt;react-scripts&lt;/code&gt; with new apps you make in the future, simply run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-react-app --scripts-version &amp;lt;custom&amp;gt;-react-scripts my-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is one slight caveat with this setup you will need to address manually if you also use a TypeScript template, see [2].&lt;/p&gt;




&lt;h1&gt;
  
  
  Custom Template
&lt;/h1&gt;

&lt;p&gt;The CRA team also added a &lt;a href="https://create-react-app.dev/docs/custom-templates/"&gt;Custom Templates&lt;/a&gt; feature starting in v3.3.0, where you can simply have a template file containing your dependencies and scripts, and it'll add them to your project upon creation. This is an alternative to creating a custom fork of &lt;code&gt;react-scripts&lt;/code&gt;, and it's useful when you only have a handful of dependencies and prefer to update them on a per-project basis.&lt;/p&gt;

&lt;p&gt;There are many custom templates already published on the npm registry that you can plug-and-play, such as &lt;a href="https://www.npmjs.com/package/cra-template-quickstart-redux"&gt;this heavily customized Redux template&lt;/a&gt;, &lt;a href="https://www.npmjs.com/package/@bamya/cra-template-tailwind"&gt;a Tailwind CSS template&lt;/a&gt;, and &lt;a href="https://www.npmjs.com/package/cra-template-storybk"&gt;a template containing Storybook&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you'd like to create your own template with your own set of dependencies and scripts, perform the following steps:&lt;/p&gt;

&lt;p&gt;1. Go to the official &lt;a href="https://github.com/facebook/create-react-app"&gt;create-react-app&lt;/a&gt; repository and navigate to &lt;code&gt;packages&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;2. Copy and paste one of the default templates as a base for your template. As of this writing, there are two official templates, &lt;code&gt;cra-template&lt;/code&gt;, which is the default, and &lt;code&gt;cra-template-typescript&lt;/code&gt;, which is the default TypeScript template.&lt;/p&gt;

&lt;p&gt;3. In &lt;code&gt;package.json&lt;/code&gt;, add a new property called &lt;code&gt;main&lt;/code&gt; and point it to &lt;code&gt;template.json&lt;/code&gt;. At the time of this writing, this property is not present in the official templates and new projects will fail to be built if this property is not present in your template.&lt;/p&gt;

&lt;p&gt;From the official webpage for Custom Templates, this is the directory structure for a template: [3]&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cra-template-[template-name]/
  README.md (for npm)
  template.json
  package.json
  template/
    README.md (for projects created from this template)
    gitignore
    public/
      index.html
    src/
      index.js (or index.tsx)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important bits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;template.json&lt;/code&gt; contains the dependencies, scripts, and other entries that will be copied over into the new React project's &lt;code&gt;package.json&lt;/code&gt; file upon creation. They must be populated under a &lt;code&gt;"package"&lt;/code&gt; field in this JSON file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;template/&lt;/code&gt; directory contains files that will be copied over into the new project upon creation. &lt;code&gt;gitignore&lt;/code&gt; will be renamed to &lt;code&gt;.gitignore&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Update &lt;code&gt;template.json&lt;/code&gt; with the dependencies you want to add to your project, add any files you will need to &lt;code&gt;template/&lt;/code&gt; directory, and update &lt;code&gt;README.md&lt;/code&gt; and &lt;code&gt;package.json&lt;/code&gt; with information about your template.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;⚠️ Important&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;All custom templates must start with &lt;code&gt;cra-template-&lt;/code&gt; so that CRA knows it's a custom template. Ensure the name of your template within &lt;code&gt;package.json&lt;/code&gt; follows this convention.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Once all that's done, you can test your template by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-react-app my-app --template file:../path/to/your/template/cra-template-[template-name]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where &lt;code&gt;../path/to/your/template/cra-template-[template-name]&lt;/code&gt; can be either a relative or absolute path to your CRA template project.&lt;/p&gt;

&lt;p&gt;Now you can publish the template to the &lt;a href="https://www.npmjs.com/"&gt;npm registry&lt;/a&gt;, making it available for new CRA apps to use as a template.&lt;/p&gt;

&lt;p&gt;To publish your template to npm, simply run &lt;code&gt;npm publish&lt;/code&gt; and login with your npm credentials when prompted.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ℹ️ Note&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ensure the name of your custom template package isn't already taken on npm.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You can create new React projects using your template by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-react-app my-app --template cra-template-[YOUR TEMPLATE]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Comparison
&lt;/h1&gt;

&lt;p&gt;In this section, I will compare each of these two solutions. You may want to use one or the other depending on your situation, and you can also use both of them together!&lt;/p&gt;

&lt;h2&gt;
  
  
  Forking react-scripts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  👍 Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Allows you to update dependencies and scripts for your projects in one go&lt;/li&gt;
&lt;li&gt;Less dependency overhead in your projects' &lt;code&gt;package.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Useful for managing dependencies if behind company firewall and/or using a corporate npm registry&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  👎 Downsides
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Not well suited for React projects that would need only a subset of the dependencies updated while keeping old versions of other dependencies (would need to start overriding dependency versions in &lt;code&gt;package.json&lt;/code&gt; at this point)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Creating templates
&lt;/h2&gt;

&lt;h3&gt;
  
  
  👍 Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Much simpler to use - simply specify the dependencies and scripts you need in the &lt;code&gt;template.json&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;Inserts dependencies directly into your app upon creation, sidestepping the need to fork &lt;code&gt;react-scripts&lt;/code&gt; if you want to manage the dependencies on a per-project basis&lt;/li&gt;
&lt;li&gt;Makes your dependencies visible, unlike the forked &lt;code&gt;react-scripts&lt;/code&gt;, which encapsulates them (depending on the situation, this may be a pro or a con)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  👎 Downsides
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Will need to update dependencies and scripts for every new project you make manually&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;And that's it - You now have the ability to customize your CRA installation however you see fit! Let me know in the comments if there's something I missed, and heart and save it if you found this useful.&lt;/p&gt;




&lt;p&gt;&lt;a&gt;&lt;/a&gt;[1] The latest version of this writing is actually v3.4.3, but there were no commits between v3.4.1 and this version. The update was simply to bump up dependencies of some internal tools to satisfy audit requirements. You can learn more about this &lt;a href="https://github.com/facebook/create-react-app/discussions/9484"&gt;here&lt;/a&gt;. Because this minor change does not affect CRA itself, the maintainers felt there was no need to make a release entry for it on GitHub. Thus, v3.4.1 remains as the latest version for the purposes of this article.&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;[2] When creating a new project using a TypeScript template, there is a special file called &lt;code&gt;react-app-env.d.ts&lt;/code&gt; that allows special objects such as images and CSS modules to be detected by TypeScript. It does this by referencing a file in &lt;code&gt;react-scripts&lt;/code&gt; that provides these type definitions. This reference to &lt;code&gt;react-scripts&lt;/code&gt; does not change even if a custom &lt;code&gt;react-scripts&lt;/code&gt; is substituted in place of the official &lt;code&gt;react-scripts&lt;/code&gt;. At the moment, a workaround is to change the reference in &lt;code&gt;react-app-env.d.ts&lt;/code&gt; to the name of your custom &lt;code&gt;react-scripts&lt;/code&gt;. See this &lt;a href="https://github.com/facebook/create-react-app/issues/8223"&gt;issue&lt;/a&gt; for more information.&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;[3] &lt;a href="https://create-react-app.dev/docs/custom-templates/#building-a-template"&gt;https://create-react-app.dev/docs/custom-templates/#building-a-template&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>node</category>
    </item>
    <item>
      <title>Dead Simple OAuth</title>
      <dc:creator>James Cote</dc:creator>
      <pubDate>Tue, 18 Aug 2020 16:43:54 +0000</pubDate>
      <link>https://dev.to/coteh/dead-simple-oauth-nho</link>
      <guid>https://dev.to/coteh/dead-simple-oauth-nho</guid>
      <description>&lt;p&gt;Recently, I started building a single-page web application (SPA) using the GitHub API as a side project, and along the way I came across a really cool and simple way to add GitHub OAuth authentication with minimal setup - using an OAuth proxy called &lt;strong&gt;&lt;a href="https://github.com/simov/grant"&gt;Grant&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Quick overview of OAuth:&lt;/strong&gt; OAuth allow applications to add third party "Sign-In" functionality without risk of your credentials getting leaked or applications accessing more data than you gave it permission to. It's a 3-step process that involves you (the end-user) granting consent to the application, then the application taking that consent (in the form of an authorization token) and exchanging it for an access token.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yQ6UO4Ra--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/w4x36qkefzu2zb2ty2hg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yQ6UO4Ra--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/w4x36qkefzu2zb2ty2hg.png" alt="OAuth 2.0 Flow Diagram" width="850" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Simple OAuth 2.0 flow diagram - &lt;a href="https://www.researchgate.net/figure/Interaction-between-the-four-roles-of-the-OAuth-protocol-flow_fig5_279063057"&gt;https://www.researchgate.net/figure/Interaction-between-the-four-roles-of-the-OAuth-protocol-flow_fig5_279063057&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;OAuth can provide integrations with third party services in a number of ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They can be used to create extensions or third party applications for a particular service. The type of application I made falls under this category - it's an application that utilizes GitHub API resources to extend functionality.&lt;/li&gt;
&lt;li&gt;They can also be used as a way to handle user accounts and authorization for an entire application. Services such as &lt;a href="https://auth0.com/"&gt;Auth0&lt;/a&gt; specialize in providing drop-in solutions for this type of flow.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;I started work on a GitHub application that imports and exports issues as CSV after I noticed that there wasn't a feature on GitHub itself for exporting and importing issues to/from a spreadsheet. GitHub allows for developers to use personal access tokens with their API, but I wanted to build something that would only take the user a couple of clicks to get setup. I also wanted to learn more about OAuth and how to integrate with another service using it.&lt;/p&gt;

&lt;p&gt;I originally started writing a backend with Golang to handle the authorization grant, but after discovering Grant I realized that it can be made simpler. In less than 50 lines, you can get a Node backend setup that will handle the entire OAuth flow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express-session&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;cors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cors&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;grant&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;grant-express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;defaults&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ORIGIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;session&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;github&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GITHUB_CLIENT_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GITHUB_CLIENT_SECRET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;scope&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;repo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;response&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;tokens&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;express&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SESSION_SECRET&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;grant&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;resave&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;saveUninitialized&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;grant&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="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;cors&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REDIRECT_URI&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/get_token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;grant&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;access_token&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="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/connect/github/callback&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REDIRECT_URI&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;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(features such as persistent session storage and error checking are omitted from this example for brevity)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;After setting this up, it's just a matter of plugging in the environment variables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ORIGIN&lt;/code&gt;: The URL of the grant server&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;REDIRECT_URI&lt;/code&gt;: The redirect URI back to your application. It does not have to match the one on your GitHub OAuth app, since you'll be plugging the special route generated by Grant instead.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SESSION_SECRET&lt;/code&gt;: Secret for &lt;code&gt;express-session&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GITHUB_CLIENT_ID&lt;/code&gt;|&lt;code&gt;GITHUB_CLIENT_SECRET&lt;/code&gt;: GitHub client ID and secret respectively, both obtained from settings page for your GitHub OAuth app&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PORT&lt;/code&gt;: port to run your Grant server on&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;...and setting up the "Authorization callback URL" in the GitHub OAuth app to point to the special callback generated by Grant which will go through the flow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4u-JZL7W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/byy4y7tevz2oiwntqwpf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4u-JZL7W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/byy4y7tevz2oiwntqwpf.png" alt="Configure Authorization callback URL" width="880" height="990"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once that's done, run the Grant server, point to its &lt;code&gt;/connect/github&lt;/code&gt; route, and voilà!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jgLq0qY6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/guo9xuna0gn1ceb9yv7u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jgLq0qY6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/guo9xuna0gn1ceb9yv7u.png" alt="Sample GitHub OAuth Authorization Grant screen" width="880" height="1035"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once it redirects back to your app, you can make an AJAX call to &lt;code&gt;/get_token&lt;/code&gt; (passing the session ID cookie) to retrieve the access token.&lt;/p&gt;




&lt;p&gt;Grant is a powerful tool. It abstracts away the entire process of issuing access tokens, and also provides built-in security features such as generating + checking of the &lt;code&gt;state&lt;/code&gt; parameter, preventing attackers from injecting their own access tokens into your app. It's also extremely configurable, allowing for static configuration (from a config file or from an object) as well as dynamic configuration via HTTP GET/POST requests. Configuration can also be changed during runtime. It's very flexible.&lt;/p&gt;

&lt;p&gt;Additionally, not only can you add multiple providers, but you can also add multiple OAuth apps for the same provider using overrides. This allows you to reuse the same OAuth grant server for many OAuth apps.&lt;/p&gt;

&lt;p&gt;To learn more about Grant, check out the &lt;a href="https://github.com/simov/grant"&gt;README.md&lt;/a&gt; on the Grant repository, it's very resourceful and contains information on how to easily setup the OAuth proxy for not just GitHub, but many other providers as well. (as a matter of fact, &lt;a href="https://github.com/simov/grant#misc-custom-providers"&gt;any OAuth-compatible server can be integrated into Grant&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;If you're building OAuth integrations for your app, I recommend checking this out!&lt;/p&gt;




&lt;p&gt;As an aside, if you want to check out my side project, github-issue-tools, it's located &lt;a href="https://github.com/Coteh/github-issue-tools"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://www.pexels.com/photo/black-and-grey-keys-792034/"&gt;Cover Photo by George Becker&lt;/a&gt; from &lt;a href="https://www.pexels.com/"&gt;Pexels&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>oauth</category>
      <category>node</category>
      <category>javascript</category>
      <category>authentication</category>
    </item>
  </channel>
</rss>
