<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Dev Blog]]></title><description><![CDATA[A curious tech junkie. Breaking keyboards to build software from 'Hello World' 🌍 to 'cloud' 🚀!
Perpetually caffeinated 🍼]]></description><link>https://blog.vishnuprasaath.dev</link><generator>RSS for Node</generator><lastBuildDate>Fri, 10 Apr 2026 19:17:42 GMT</lastBuildDate><atom:link href="https://blog.vishnuprasaath.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Blockchain: Understanding basics - part 2]]></title><description><![CDATA[With peer-to-peer models, even if all peers are ‘trusted’, there is a potential problem of agreement or consensus – let's assume that each peer is updating at a different speed and end up holding different states, how to determine the “real” or “true...]]></description><link>https://blog.vishnuprasaath.dev/blockchain-understanding-basics-part-2</link><guid isPermaLink="true">https://blog.vishnuprasaath.dev/blockchain-understanding-basics-part-2</guid><category><![CDATA[Blockchain]]></category><category><![CDATA[Web3]]></category><category><![CDATA[consent]]></category><category><![CDATA[bitcoin transactions]]></category><category><![CDATA[4th]]></category><dc:creator><![CDATA[Vishnu Prasaath]]></dc:creator><pubDate>Sun, 28 May 2023 05:58:51 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1685253410058/5ed08290-1849-4a74-86fb-fc8a450bff41.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>With peer-to-peer models, even if all peers are ‘trusted’, there is a potential problem of agreement or consensus – let's assume that each peer is updating at a different speed and end up holding different states, how to determine the “real” or “true” state of the data?</p>
<p>In the case of an ‘untrusted’ peer-to-peer network, we can’t necessarily trust any of the peers, how to ensure that the bad peers won't corrupt the system?</p>
<hr />
<h3 id="heading-consensus-how-to-resolve-conflicts">CONSENSUS: <em>How to resolve conflicts?</em></h3>
<p>A very basic conflict is when multiple miners create blocks at the same time.  As the blocks take time to be shared across the network, which one should be considered a legit block?</p>
<p><strong>Example:</strong> Let’s consider that all the nodes on the network have synchronised their blockchains, and they are all on block number 80.<br />If three different miners create ‘Block 81’ at roughly the same time, which ‘Block 81’ should be considered valid?  Remember that each ‘Block 81’ will look slightly different: They will certainly contain a different payment address for the 25 BTC block reward, and they may contain a different set of transactions.  Let’s call them 81a, 81b, 81c.</p>
<p><img src="https://i0.wp.com/bitsonblocks.net/wp-content/uploads/2015/09/three_blocks1.jpg?resize=420%2C182&amp;ssl=1" alt="three_blocks" class="image--center mx-auto" /></p>
<p>Which block will be considered the legit one?<br />How to resolve this?</p>
<p><strong>Longest chain rule.</strong>  In Bitcoin, this conflict is resolved by a rule called the “longest chain rule”.</p>
<p>In the example above, you would assume that the first ‘Block 81’ you see is valid. Let’s say you see 81a first. You can start building the next block on that, trying to create 82a:</p>
<p><img src="https://i0.wp.com/bitsonblocks.net/wp-content/uploads/2015/09/mine_on_first.jpg?resize=484%2C154&amp;ssl=1" alt="mine_on_first" class="image--center mx-auto" /></p>
<p>Treat the first block you see as legitimate.</p>
<p>However, in a few seconds, you may see 81b. If you see this, you keep an eye on it. If later you see 82b, the “longest chain rule” says that you should regard the longer ‘b’ chain as the valid one (…80, 81b, 82b) and ignore the shorter chain (…80, 81a). So you stop trying to make 82a and instead, start trying to make 83b:</p>
<p><img src="https://i0.wp.com/bitsonblocks.net/wp-content/uploads/2015/09/mine_on_longest.jpg?resize=563%2C232&amp;ssl=1" alt="mine_on_longest" class="image--center mx-auto" /></p>
<p>Longest chain rule: If there are multiple blocks, treat the longest chain as legitimate.</p>
<p>The “longest chain rule” is the rule that the Bitcoin blockchain ecosystem uses to resolve these conflicts which are common in distributed networks.</p>
<p>However, with a more centralised or trusted blockchain network, we can make decisions by using a trusted, or senior validator to arbitrate in these cases.</p>
<hr />
<h3 id="heading-defence-how-do-you-make-it-hard-for-baddies">DEFENCE: <em>How do you make it hard for baddies?</em></h3>
<p>The most common issue with permissionless, or open networks is that they can be attacked easily. So we need to make sure the network as a whole needs to be trustworthy, even if few nodes aren't.</p>
<p>Understanding the Miscreant's Capabilities</p>
<p>A dishonest miner, despite causing concern, is confined in terms of the harm they can inflict. Here are some actions a dishonest miner can take:</p>
<ol>
<li><p>Refusal to relay valid transactions: A dishonest miner can choose not to pass valid transactions to other nodes within the network.</p>
</li>
<li><p>Manipulating block contents: They can attempt to create blocks that selectively include or exclude specific transactions according to their preferences.</p>
</li>
<li><p>Attempting to construct a longer chain: By creating a sequence of blocks that surpasses the existing main chain, a dishonest miner can render previously accepted blocks as "orphans," thereby excluding them from the primary chain.</p>
</li>
</ol>
<p>However, a dishonest miner is unable to execute the following actions:</p>
<ol>
<li><p>Generating bitcoins out of thin air: While theoretically possible, creating bitcoins out of nothing remains unfeasible. If such transactions are attempted, other nodes will reject them, emphasizing the importance of confirming transactions across multiple nodes.</p>
</li>
<li><p>Stealing bitcoins from your account: The security measures in place prevent a dishonest miner from pilfering bitcoins from a user's account.</p>
</li>
<li><p>Impersonation or unauthorized payments: A dishonest miner cannot conduct payments on behalf of others or pretend to be someone else within the network.</p>
</li>
</ol>
<p>Transaction Security</p>
<p>The impact of a dishonest miner's actions on transactions is limited, primarily due to the presence of honest nodes in the network. If the majority of nodes are honest, they will reject any invalid transactions introduced by the miscreant. Moreover, these honest nodes will propagate valid transactions to ensure their inclusion in subsequent blocks, even if the dishonest miner refuses to relay them.</p>
<p>Block Security</p>
<p>In the context of blocks, the influence of a miscreant with significant block creation power becomes more pronounced. They can delay a specific transaction by omitting it from their blocks. However, other honest nodes will recognize this transaction as an "unconfirmed transaction" and incorporate it into their blocks.</p>
<p>A more significant concern arises when a dishonest miner manages to construct a longer chain of blocks compared to the rest of the network. By invoking the "longest chain rule," the miscreant can effectively undermine a transaction. Here's an overview of this strategy:</p>
<ol>
<li><p>Creating dual payments: Initiate two payments with the same bitcoins—one to an online retailer and the other to another address under your control.</p>
</li>
<li><p>Broadcasting the retailer payment: Only share the payment intended for the retailer with the network.</p>
</li>
<li><p>Retailer payment confirmation: As the payment is included in an honest block, the retailer dispatches the ordered goods.</p>
</li>
<li><p>Secretly constructing a longer chain: Covertly generates a longer chain of blocks that excludes the payment to the retailer but includes the payment to yourself.</p>
</li>
<li><p>Publishing the longer chain: When the longer chain is published, nodes following the "longest chain rule" ignore the honest block containing the retailer payment. Instead, they continue building on the longer chain, effectively orphaning the honest block.</p>
</li>
<li><p>Invalidating the retailer payment: Due to the existence of the longer chain, honest nodes deem the original payment to the retailer invalid, as the bitcoins associated with it have already been spent according to your longer chain.</p>
</li>
</ol>
<p><img src="https://i0.wp.com/bitsonblocks.net/wp-content/uploads/2015/09/double_spend1.jpg?resize=558%2C630&amp;ssl=1" alt="double_spend" class="image--center mx-auto" /></p>
<p>The “<strong>double spend</strong>” attack.</p>
<p>This is called a “double spend” because the same bitcoins were spent twice – but the second one was the one that became part of the eventual blockchain, and the first one eventually gets rejected.</p>
<h3 id="heading-ia"> </h3>
<p>How to make it hard for dishonest miners to create blocks?</p>
<p>Remember, this is only a problem for ledgers where block-makers aren’t trusted.</p>
<p>Essentially you want to make it hard, or expensive for baddies to add blocks.  In Bitcoin, this is done by making it <strong>computationally expensive</strong> to add blocks.  Computationally expensive means “takes a lot of computer processing power” and translates to financially expensive (as computers need to be bought then run and maintained).</p>
<p>The computation itself is a <strong>guessing game</strong> where block-makers need to guess a number, which when crunched with the rest of the block data contents, results in a hash/fingerprint that is smaller than a certain number.  That number is related to the ‘difficulty’ of mining which is related to the total network processing power.  The more computers join in to process blocks, the harder it gets, in a self-regulating cycle.</p>
<p>Every 2,016 blocks (roughly every 2 weeks), the Bitcoin network adjusts the difficulty of the guessing game based on the speed in which the blocks have been created.</p>
<p>This guessing game is called <strong>“Proof of work”</strong>. By publishing the block with a fingerprint that is smaller than the target number, you are proving that you did enough guesswork to satisfy the network at that point in time.</p>
]]></content:encoded></item><item><title><![CDATA[Blockchain: Understanding basics - part 1]]></title><description><![CDATA[In this article let's try to demystify and understand the basics of the blockchain infrastructure and see how it contributes to the web3 ecosystem.
What is a blockchain?
Basically, blockchain is a Data Structure.  Very similar to other data structure...]]></description><link>https://blog.vishnuprasaath.dev/blockchain-understanding-basics</link><guid isPermaLink="true">https://blog.vishnuprasaath.dev/blockchain-understanding-basics</guid><category><![CDATA[Blockchain]]></category><category><![CDATA[Bitcoin]]></category><category><![CDATA[Ethereum]]></category><category><![CDATA[Blockchain technology]]></category><category><![CDATA[Web3]]></category><dc:creator><![CDATA[Vishnu Prasaath]]></dc:creator><pubDate>Thu, 27 Apr 2023 13:05:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1682599641121/7c9a3b4c-8292-4836-8ef8-02be77dab10d.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this article let's try to demystify and understand the basics of the blockchain infrastructure and see how it contributes to the <strong>web3</strong> ecosystem.</p>
<h3 id="heading-what-is-a-blockchain"><strong>What is a blockchain?</strong></h3>
<p>Basically<strong>, blockchain is a Data Structure</strong>.  Very similar to other data structures like databases (rows, columns, tables), text files, CSV, images, lists, and so on. Blockchain competes most closely with a database.</p>
<p>For an analogy, let's visualize blockchain <em>as</em> pages in a book<br /><strong>Chain = Book</strong><br /><strong>Block = Page</strong><br /><strong>Blocks in Chain = Pages in Book</strong><br />Each page in a book contains:</p>
<ul>
<li><p><strong>text</strong>: content/story</p>
</li>
<li><p><strong>information about the page</strong>: chapter number/title, page number</p>
</li>
</ul>
<p>Similarly in a blockchain block, each block has:</p>
<ul>
<li><p><strong>contents</strong> of the block: Transaction details in cryptocurrency, or any data which we prefer to store</p>
</li>
<li><p><strong>header</strong>: <strong>Metadata</strong> - data about the block.  Some sort of technical info about the block, a reference to the previous block, and a fingerprint (hash) of the data for the current block</p>
</li>
</ul>
<p>In blockchains, each block references the previous block by a computed hash value called the <strong>block’s fingerprint</strong>. The fingerprint is computed based on the <strong>contents</strong> of the block.</p>
<p>The concept of maintaining a reference to the previous blocks can be visualized as a <strong>linked list structure</strong>. In the linked list each node holds a reference to the next node, whereas in the blockchain each block holds a reference to the previous block.</p>
<p><img src="https://i0.wp.com/bitsonblocks.net/wp-content/uploads/2015/09/books_and_blocks.png?resize=570%2C129&amp;ssl=1" alt="books_and_blocks" class="image--center mx-auto" /></p>
<p>This creates the fancy structure called the <strong>blockchain</strong>!</p>
<hr />
<p>The fingerprint in each block is responsible for taking care of the consistency and validity of the data. If someone tries to meddle with any of the data, they have to end up regenerating all the fingerprints from that point forwards and the blockchain will look different. This is basically impossible as the process of creating fingerprints is difficult and slow. Therefore, if someone wants to re-write parts of the blockchain, it will take them a long time, and they have to catch up with and overtake the rest of the honest network. Which is not feasible.</p>
<p>Hence the blockchain is called <strong>immutable</strong> (as it cannot be changed).</p>
<p>The below image shows the inside of a blockchain block: the fingerprints are unique to the block’s contents.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1682595755311/91e67114-6349-4083-ae30-9c2de7184735.png" alt="block-chain-inside" class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-data-distribution">Data Distribution</h3>
<p>There are two ways of distributing data in a network: Client-Server and Peer to peer. Blockchain is built on top of the <strong>peer-to-peer</strong> model.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1682592527479/b730f1ac-9e8b-4fa8-8c28-cdb8cc47c980.png" alt="peer-to-peer and client-server" class="image--center mx-auto" /></p>
<p><strong>Client-server</strong><br />This is a traditional approach where the server holds 100% of the data, and the clients connect via required protocols to access/consume the data.</p>
<p><strong>Peer-to-peer</strong><br />In peer-to-peer models, each peer has 100% of the data (or as close to it as possible), and updates are shared around.  This is less efficient than client-server, as data is replicated many times. However, it's more robust as there is no central server that can be controlled, so closing down peer-to-peer networks is harder.  </p>
<p>But on the contrary, the peer-to-peer model comes with its downsides. In the real world each peer on the network is gonna process and update at its own speed and latency and end up having varied states at a given timestamp. Deciding on which peer holds the valid data and which peer has stale or tampered data is ambiguous.</p>
<p>This conflict is resolved by a rule called the <strong>“longest chain rule”</strong> - If you see multiple blocks, treat the longest chain as legitimate. We can discuss in-depth on this conflict resolution and consensus in a separate article.</p>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>Blockchain is not something that is associated with only <strong>Bitcoin</strong>. <strong>Ethereum</strong> is a great variant of blockchain with <strong>smart contracts</strong>. There are significant challenges involved.<br />On the other hand, private or internally distributed ledgers and blockchains can be deployed to solve a wide range of problems and use cases.</p>
]]></content:encoded></item><item><title><![CDATA[GitHub CLI: gives wings to terminal]]></title><description><![CDATA[When working with git, you’re obviously aware that you need to switch to the web browser to perform various actions on the GitHub repo - Pull Request, Issues, Review... The GitHub CLI tool gives wings to the cmd-line, so you can execute many of these...]]></description><link>https://blog.vishnuprasaath.dev/github-cli</link><guid isPermaLink="true">https://blog.vishnuprasaath.dev/github-cli</guid><category><![CDATA[github-cli]]></category><category><![CDATA[Git]]></category><category><![CDATA[GitHub]]></category><category><![CDATA[Pull Requests]]></category><category><![CDATA[Gitcommands]]></category><dc:creator><![CDATA[Vishnu Prasaath]]></dc:creator><pubDate>Thu, 13 Apr 2023 16:54:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1681404374432/14d23908-e00b-49f9-ad04-33738b8985f5.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When working with git, you’re obviously aware that you need to switch to the web browser to perform various actions on the GitHub repo - Pull Request, Issues, Review... The GitHub CLI tool gives wings to the cmd-line, so you can execute many of these actions without leaving the cmd-line.</p>
<h2 id="heading-setup"><strong>Setup</strong></h2>
<p>To get started, visit the <a target="_blank" href="https://cli.github.com/manual/installation"><strong>installation page</strong></a> and find instructions on how to install GitHub CLI for your preferred OS. The easy-peasy way for Windows users is to use <a target="_blank" href="https://scoop.sh/"><strong>scoop</strong></a> package manager.</p>
<p>Below are snapshots of install instructions for each supported platform:</p>
<ul>
<li><p>Windows:</p>
<pre><code class="lang-powershell">  scoop bucket add github<span class="hljs-literal">-gh</span> https://github.com/<span class="hljs-built_in">cli</span>/scoop<span class="hljs-literal">-gh</span>.git
  scoop install gh
</code></pre>
</li>
<li><p>macOS:</p>
<pre><code class="lang-bash">  brew install github
</code></pre>
</li>
<li><p>Debian/Ubuntu Linux:</p>
<pre><code class="lang-bash">  sudo apt install git &amp;&amp; sudo dpkg -i gh_*_linux_amd64.deb
</code></pre>
</li>
</ul>
<hr />
<h2 id="heading-authenticate-github-cli">Authenticate GitHub CLI</h2>
<p>Authenticate CLI to access your GitHub account.</p>
<pre><code class="lang-bash">gh auth login
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681376462925/ec752011-11bd-4370-983f-761c9e3dfaaa.png" alt class="image--center mx-auto" /></p>
<p>Select <code>Login with a Web browser</code></p>
<pre><code class="lang-plaintext">$ gh auth login
? What account do you want to log into? GitHub.com
? What is your preferred protocol for Git operations? HTTPS
? Authenticate Git with your GitHub credentials? Yes
? How would you like to authenticate GitHub CLI? Login with a web browser

! First copy your one-time code: 1DD9-7BD3
Press Enter to open github.com in your browser... 
✓ Authentication complete.
- gh config set -h github.com git_protocol https
✓ Configured git protocol
✓ Logged in as pvishnuprasaath
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681376809577/a6f4dc62-bda2-41bd-8993-8b24475def8e.png" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-github-cli-command-struct"><strong>GitHub CLI Command Struct</strong></h2>
<p><code>gh</code> command is structured like a tree for grabbing easily. There are basically two levels of commands. The first level consists of the below commands:</p>
<ul>
<li><p><code>auth</code></p>
</li>
<li><p><code>browse</code></p>
</li>
<li><p><code>issue</code></p>
</li>
<li><p><code>pr</code></p>
</li>
<li><p><code>release</code></p>
</li>
<li><p><code>repo</code></p>
</li>
<li><p><code>codespace</code></p>
</li>
<li><p><code>gist</code></p>
</li>
</ul>
<p>Each command has a second level of command where you specify the operation to perform — such as <code>gh pr create</code> or <code>gh repo view</code>.</p>
<p>Let's dive deep into the most commonly used commands.</p>
<hr />
<h2 id="heading-github-repo-command"><strong>GitHub Repo Command</strong></h2>
<p>Cloning a repo with the <code>gh</code> command is easier than using the <code>git</code> command. You no longer need to type or copy-paste the long Git URL to clone</p>
<pre><code class="lang-bash">gh repo <span class="hljs-built_in">clone</span> OWNER/REPO
gh repo <span class="hljs-built_in">clone</span> mui/material-ui
</code></pre>
<p>You can also fork existing repositories to your account easily from the command line.</p>
<pre><code class="lang-bash">gh repo fork cli/cli
</code></pre>
<p>To view the description and README of a project hosted on GitHub use the <code>gh repo view</code> command.</p>
<pre><code class="lang-bash">gh repo view facebook/react
</code></pre>
<p>Let's create a new GitHub repository from the command line. First, we need to create a new project.</p>
<pre><code class="lang-bash">$ npx create-next-app sample-app
$ <span class="hljs-built_in">cd</span> sample-app
</code></pre>
<p>To create a repo from the command line, just run the following:</p>
<pre><code class="lang-bash">$ gh repo create --public
✓ Created repository pvishnuprasaath/sample-app on GitHub
✓ Added remote https://github.com/pvishnuprasaath/sample-app.git

<span class="hljs-comment"># Push your project code to your new remote repository</span>
$ git push -u origin main
</code></pre>
<hr />
<h2 id="heading-pull-request-command"><strong>Pull Request Command</strong></h2>
<p>If you know classic <strong>git flow</strong>, creating PR is quite an effort. GitHub CLI makes it easy to create PR directly from your terminal. After a <code>git commit</code>, you can execute <code>gh pr create</code>. It will prompt a couple of inputs. Post that, the PR link is displayed in the terminal.</p>
<p>Here’s the full output:</p>
<pre><code class="lang-bash">$ gh pr create
Creating pull request <span class="hljs-keyword">for</span> feature-1 into master <span class="hljs-keyword">in</span> pvishnuprasaath/sample-app
? Title Added new feature
? Body Implemented and testted new feature <span class="hljs-keyword">for</span> ABC
? What is  next? Submit
Enumerating objects: 6, <span class="hljs-keyword">done</span>.
Counting objects: 100% (6/6), <span class="hljs-keyword">done</span>.
Delta compression using up to 8 threads
Compressing objects: 100% (4/4), <span class="hljs-keyword">done</span>.
Writing objects: 100% (4/4), 328 bytes | 328.00 KiB/s, <span class="hljs-keyword">done</span>.
Total 4 (delta 2), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (2/2), completed with 2 <span class="hljs-built_in">local</span> objects.
remote:
remote: Create a pull request <span class="hljs-keyword">for</span> <span class="hljs-string">'feature-1'</span> on GitHub by visiting:
remote:      https://github.com/pvishnuprasaath/sample-app/pull/new/feature-1
remote:
To https://github.com/pvishnuprasaath/sample-app.git
* [new branch]      HEAD -&gt; feature-1
Branch <span class="hljs-string">'feature-1'</span> <span class="hljs-built_in">set</span> up to track
remote branch <span class="hljs-string">'feature-1'</span> from <span class="hljs-string">'origin'</span>.
https://github.com/pvishnuprasaath/sample-app/pull/3
</code></pre>
<p>A short version:</p>
<pre><code class="lang-bash">gh pr create --title <span class="hljs-string">"PR title"</span> --body <span class="hljs-string">"PR body"</span>
</code></pre>
<p>To view all the pull requests in the current repo, run <code>gh pr list</code></p>
<pre><code class="lang-bash">$ gh pr list
Showing 1 of 1 pull request <span class="hljs-keyword">in</span> pvishnuprasaath/sample-app
<span class="hljs-comment">#3  Added new feature  feature-1</span>
</code></pre>
<p>Use the command <code>gh pr checkout &lt;number&gt;</code> to checkout a PR. This command will pull the remote feature branch and switch to it. <code>gh pr diff</code> will show the delta for the current PR.</p>
<p>Let’s take a look at the <code>gh pr merge</code> command. As you’re probably aware, GitHub checks for vulnerabilities in your code and provides solutions via bump pull requests. Here’s an example:</p>
<p>Merging multiple PRs one by one is a tiring process. <code>gh pr merge</code> makes it easy to merge a particular PR directly from the terminal.</p>
<pre><code class="lang-bash">$ gh pr merge 4
? What merge method would you like to use? Create a merge commit
remote: Counting objects: 100% (1/1), <span class="hljs-keyword">done</span>.
remote: Counting objects: 100% (1/1), <span class="hljs-keyword">done</span>.
remote: Total 1 (delta 0), reused 0 (delta 0), pack-reused 0        
Unpacking objects: 100% (1/1), 624 bytes | 89.00 KiB/s, <span class="hljs-keyword">done</span>.       
From https://github.com/pvishnuprasaath/sample-app   
 * branch            main       -&gt; FETCH_HEAD
   09f8c52..7a8a3f2  main       -&gt; origin/main
Updating 09f8c52..7a8a3f2
Fast-forward
 src/data/data.ts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
✓ Deleted branch FixLink and switched to branch main
</code></pre>
<p>Additional <code>gh pr</code> commands</p>
<ul>
<li><p><a target="_blank" href="https://cli.github.com/manual/gh_pr_view"><code>gh pr view</code></a>: displays the title, body, and other information about a pull request.</p>
</li>
<li><p><a target="_blank" href="https://cli.github.com/manual/gh_pr_status"><code>gh pr status</code></a>: show the status of relevant pull requests.</p>
</li>
<li><p><a target="_blank" href="https://cli.github.com/manual/gh_pr_ready"><code>gh pr ready</code></a>: make a pull request as ready for review.</p>
</li>
<li><p><a target="_blank" href="https://cli.github.com/manual/gh_pr_review"><code>gh pr review</code></a>: add a review to a pull request.</p>
</li>
<li><p><a target="_blank" href="https://cli.github.com/manual/gh_pr_close"><code>gh pr close</code></a>: close a pull request.</p>
</li>
<li><p><a target="_blank" href="https://cli.github.com/manual/gh_pr_reopen"><code>gh pr reopen</code></a>: reopen a pull request.</p>
</li>
</ul>
<p>By now, there isn't a way to revert PR from the GitHub CLI yet :(</p>
<hr />
<h2 id="heading-issue-command"><strong>Issue Command</strong></h2>
<p><a target="_blank" href="https://guides.github.com/features/issues/"><strong>Issues</strong></a> are used to keep track of bugs, tasks and feature requests associated with a GitHub project repo. The command <code>gh issue create</code> is used to create a new issue via the terminal:</p>
<pre><code class="lang-bash">$ gh issue create
Creating issue <span class="hljs-keyword">in</span> pvishnuprasaath/sample-app
? Title Fix Docker skill link

? Title Fix Docker skill link
? Body &lt;Received&gt;
? What<span class="hljs-string">'s next? Submit
https://github.com/pvishnuprasaath/sample-app/issues/6</span>
</code></pre>
<p><code>gh issue list</code> command lists all issues in the current repo.</p>
<p>The rest of <code>gh issue</code> commands are quite similar to <code>gh pr</code> commands. Below is a quick summary:</p>
<ul>
<li><p><a target="_blank" href="https://cli.github.com/manual/gh_issue_view"><code>gh issue view</code></a>: displays the title, body, and other information about an issue.</p>
</li>
<li><p><a target="_blank" href="https://cli.github.com/manual/gh_issue_status"><code>gh issue status</code></a>: show the status of relevant issues.</p>
</li>
<li><p><a target="_blank" href="https://cli.github.com/manual/gh_issue_close"><code>gh issue close</code></a>: close an issue.</p>
</li>
<li><p><a target="_blank" href="https://cli.github.com/manual/gh_issue_reopen"><code>gh issue reopen</code></a>: reopen an issue.</p>
</li>
</ul>
<hr />
<h2 id="heading-github-cli-cheat-sheet">GitHub CLI Cheat Sheet</h2>
<p><strong>Creating, deleting and configuring repo</strong></p>
<pre><code class="lang-bash">gh repo create

gh repo create &lt;name_of_repo&gt; --public

gh repo create my-project --private --<span class="hljs-built_in">source</span>=. --remote=upstream

gh repo edit --visibility &lt;visibility-string&gt;

gh repo sync

gh repo create --disable-issues=<span class="hljs-literal">true</span> --public

gh repo list

gh repo delete &lt;name_of_repo&gt;

gh repo <span class="hljs-built_in">clone</span> &lt;name_of_repo&gt;

gh repo fork &lt;name_of_repo&gt;
</code></pre>
<p>To easily save a piece of code online use Gist:</p>
<p><strong>Creating a gist</strong></p>
<pre><code class="lang-bash">touch index.js // after create content <span class="hljs-keyword">for</span> it

gh gist create index.js --public

gh gist create -

gh gist edit &lt;gist_id&gt; 

gh gist list --public 

gh gist list --secret
</code></pre>
<p><strong>Handling issues</strong></p>
<pre><code class="lang-bash">gh issue create

gh issue list

gh issue status

git issue close &lt;<span class="hljs-comment">#number_issue&gt;</span>

gh list -A <span class="hljs-string">"&lt;name_issue&gt;"</span>
</code></pre>
<p><strong>Handling Pull requests</strong></p>
<pre><code class="lang-bash">gh pr create 

gh pr checkout &lt;name&gt;

gh pr diff &lt;<span class="hljs-comment">#number_of_pr&gt;</span>

gh review -c -b <span class="hljs-string">"nice work"</span>

gh pr close &lt;<span class="hljs-comment">#number_of_pr&gt; -d</span>

gh pr reopen &lt;<span class="hljs-comment">#number_of_pr&gt;</span>

gh pr status
</code></pre>
<p><code>gh</code> for sure saves up time in devflow. Gives additional hands to your terminal for managing the repository. Refer to the <a target="_blank" href="https://cli.github.com/manual/"><strong>official docs</strong></a> for new features and detailed info on using the existing commands.</p>
]]></content:encoded></item><item><title><![CDATA[GitHub Actions CI/CD for React app hosted in GitHub Pages]]></title><description><![CDATA[Let's create a simple GitHub Actions workflow that I use on my projects with React.
This workflow created on GitHub Actions will take care of automatically building and deploying the app on GitHub Pages. Can add testing and linting if needed. We will...]]></description><link>https://blog.vishnuprasaath.dev/github-actions-cicd-react</link><guid isPermaLink="true">https://blog.vishnuprasaath.dev/github-actions-cicd-react</guid><category><![CDATA[React]]></category><category><![CDATA[github-actions]]></category><category><![CDATA[ci-cd]]></category><category><![CDATA[GitHub]]></category><category><![CDATA[deployment]]></category><dc:creator><![CDATA[Vishnu Prasaath]]></dc:creator><pubDate>Wed, 12 Apr 2023 03:57:12 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1681242842648/60d26f49-21b8-4934-a0b6-ac3be77b6053.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Let's create a simple GitHub Actions workflow that I use on my projects with React.</p>
<p>This workflow created on <a target="_blank" href="https://github.com/features/actions">GitHub Actions</a> will take care of automatically building and deploying the app on <a target="_blank" href="https://pages.github.com/">GitHub Pages</a>. Can add testing and linting if needed. We will be triggering this workflow on every push event on the <strong>main/master branch</strong>.</p>
<p>Consider going over my prev <a target="_blank" href="https://pvishnuprasaath.hashnode.dev/host-react-app-in-github-pages">blog-post</a> on setting up your React app hosting on GitHub Pages.</p>
<h2 id="heading-configure-react-app">Configure React App</h2>
<p>A tiny bit of configuration is required on the React app side.</p>
<p>Add the below <code>homepage</code> property to your <code>package.json</code> file.</p>
<pre><code class="lang-yaml"><span class="hljs-string">For</span> <span class="hljs-string">free</span> <span class="hljs-string">GitHub</span> <span class="hljs-string">user</span> <span class="hljs-string">site,</span> <span class="hljs-attr">add this:</span> 
<span class="hljs-attr">"homepage":</span> <span class="hljs-string">"https://{username}.github.io"</span>

<span class="hljs-string">If</span> <span class="hljs-string">you</span> <span class="hljs-string">own</span> <span class="hljs-string">a</span> <span class="hljs-string">domain,</span> <span class="hljs-attr">add this:</span>
<span class="hljs-attr">"homepage":</span> <span class="hljs-string">"https://mydomainname.com"</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681030015020/bc19bfff-fb70-457e-b0ff-6a0e5a2ab97d.png?auto=compress,format&amp;format=webp" alt class="image--center mx-auto" /></p>
<p>Add both <strong>predeploy</strong> and <strong>deploy</strong> property scripts to the <code>package.json</code> as below</p>
<pre><code class="lang-yaml"><span class="hljs-attr">"predeploy":</span> <span class="hljs-string">"npm run build"</span><span class="hljs-string">,</span>
<span class="hljs-attr">"deploy":</span> <span class="hljs-string">"gh-pages -d build"</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681030290187/7fb123aa-6a9a-4864-9b67-b36cba2bbbf1.png?auto=compress,format&amp;format=webp" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-getting-started-with-github-actions-workflow">Getting Started with GitHub Actions WorkFlow</h2>
<p>First, create a <code>workflow.yml</code> file inside <code>.github\workflows</code> dir</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681236230142/0966325b-62b7-495c-b6b6-dcc088fd1c48.png" alt class="image--center mx-auto" /></p>
<p>The complete workflow is as below:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">Build</span> <span class="hljs-string">and</span> <span class="hljs-string">Deploy</span>

<span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">branches:</span> [<span class="hljs-string">"main"</span>]

<span class="hljs-attr">permissions:</span>
  <span class="hljs-attr">contents:</span> <span class="hljs-string">write</span>

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">build-deploy:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>

    <span class="hljs-attr">strategy:</span>
      <span class="hljs-attr">matrix:</span>
        <span class="hljs-attr">node-version:</span> [<span class="hljs-number">18.</span><span class="hljs-string">x</span>]

    <span class="hljs-attr">steps:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Checkout</span>
      <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v3</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Use</span> <span class="hljs-string">Node.js</span> <span class="hljs-string">${{</span> <span class="hljs-string">matrix.node-version</span> <span class="hljs-string">}}</span>
      <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-node@v3</span>
      <span class="hljs-attr">with:</span>
        <span class="hljs-attr">node-version:</span> <span class="hljs-string">${{</span> <span class="hljs-string">matrix.node-version</span> <span class="hljs-string">}}</span>
        <span class="hljs-attr">cache:</span> <span class="hljs-string">"npm"</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">Packages</span>
      <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">ci</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Build</span>
      <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">run</span> <span class="hljs-string">build</span>
    <span class="hljs-comment">#- name: Test</span>
    <span class="hljs-comment">#  run: npm test</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Deploy🚀</span>
      <span class="hljs-attr">uses:</span> <span class="hljs-string">JamesIves/github-pages-deploy-action@v4</span>
      <span class="hljs-attr">with:</span>
        <span class="hljs-attr">branch:</span> <span class="hljs-string">gh-pages</span>
        <span class="hljs-attr">folder:</span> <span class="hljs-string">build</span>
</code></pre>
<p>Let's understand each field put up here.</p>
<p>The <code>on</code> section describes the <strong>events</strong> which should trigger the job. In this workflow we want the jobs to be triggered whenever someone does a <code>push</code> into the <code>main</code> branch.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">branches:</span> [<span class="hljs-string">"main"</span>]
</code></pre>
<p>Our job needs write access to modify files in the <code>gh-pages</code> branch. The final build files are pushed into the gh-pages branch of your repo. Using GitHub Secrets can also help achieve the same result.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">permissions:</span>
  <span class="hljs-attr">contents:</span> <span class="hljs-string">write</span>
</code></pre>
<p>Let's get into the interesting section of defining the actual <strong>job</strong> to be executed. <em>build-deploy</em> is the user-defined name for the job.</p>
<p>We need to mention the type of <strong>runner</strong> on which the job needs to be executed. Pick <code>ubuntu-latest</code>.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">build-deploy:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
</code></pre>
<p>When we want the same job to be executed on multiple variants of the node version, we can use the <code>strategy matrix</code>. Here we will stick to just 1 node version.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">strategy:</span>
  <span class="hljs-attr">matrix:</span>
    <span class="hljs-attr">node-version:</span> [<span class="hljs-number">18.</span><span class="hljs-string">x</span>]
</code></pre>
<p>The first step in any job is to <strong>checkout</strong> the repo at that particular instance. This ensures we have the latest code base for the further process.</p>
<pre><code class="lang-yaml"><span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Checkout</span>
  <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v3</span>
</code></pre>
<p>Set up <strong>Node.js</strong> on the freshly brought-up runner. To optimize the workflow execution we can <strong>cache</strong> the npm packages.</p>
<pre><code class="lang-yaml"> <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Use</span> <span class="hljs-string">Node.js</span> <span class="hljs-string">${{</span> <span class="hljs-string">matrix.node-version</span> <span class="hljs-string">}}</span>
   <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-node@v3</span>
   <span class="hljs-attr">with:</span>
     <span class="hljs-attr">node-version:</span> <span class="hljs-string">${{</span> <span class="hljs-string">matrix.node-version</span> <span class="hljs-string">}}</span>
     <span class="hljs-attr">cache:</span> <span class="hljs-string">"npm"</span>
</code></pre>
<p>Then we instruct the job to perform <code>npm ci</code>, <code>npm run build</code>, <code>npm test</code>. This covers the <strong>Build</strong> and <strong>Test</strong> phase.</p>
<pre><code class="lang-yaml"><span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">Packages</span>
  <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">ci</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Build</span>
  <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">run</span> <span class="hljs-string">build</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Test</span>
  <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">test</span>
</code></pre>
<p>Finally, it's time to <strong>deploy</strong> and give life to the app. We will use the popular <code>JamesIves/github-pages-deploy-action@v4</code> action for deploying straight into the gh-pages. Specify the <strong>branch name</strong> on where the built files will be pushed to. Also, mention the <strong>source dir</strong> from where to find the built files. In our case, <code>npm run build</code> will dump files into the <code>./build</code> dir.</p>
<pre><code class="lang-yaml"><span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">🚀</span>
  <span class="hljs-attr">uses:</span> <span class="hljs-string">JamesIves/github-pages-deploy-action@v4</span>
  <span class="hljs-attr">with:</span>
    <span class="hljs-attr">branch:</span> <span class="hljs-string">gh-pages</span>
    <span class="hljs-attr">folder:</span> <span class="hljs-string">build</span>
</code></pre>
<p>In the <strong>Actions</strong> tab, we can see the execution status and log.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681271645127/d1988253-0749-41c4-a1e4-2a68cb25d8aa.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-references">References</h2>
<ul>
<li><p><a target="_blank" href="https://github.com/features/actions">https://github.com/features/actions</a></p>
</li>
<li><p><a target="_blank" href="https://pages.github.com/">https://pages.github.com/</a></p>
</li>
<li><p><a target="_blank" href="https://create-react-app.dev/docs/deployment#github-pages">https://create-react-app.dev/docs/deployment#github-pages</a></p>
</li>
<li><p><a target="_blank" href="https://help.github.com/pt/actions/configuring-and-managing-workflows/caching-dependencies-to-speed-up-workflows">https://help.github.com/pt/actions/configuring-and-managing-workflows/caching-dependencies-to-speed-up-workflows</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/actions/cache">https://github.com/actions/cache</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Dockerize React app for dev and prod]]></title><description><![CDATA[Okay, you have a frontend React app and you want to serve it via Docker. Let's do that!
In this wiki, we will dockerize both the development and production environment via separate Dockerfiles.
Step 1: Project setup
Initialized a pretty standard reac...]]></description><link>https://blog.vishnuprasaath.dev/dockerize-react-app-for-dev-and-prod</link><guid isPermaLink="true">https://blog.vishnuprasaath.dev/dockerize-react-app-for-dev-and-prod</guid><category><![CDATA[React]]></category><category><![CDATA[Docker]]></category><category><![CDATA[Docker compose]]></category><category><![CDATA[containers]]></category><dc:creator><![CDATA[Vishnu Prasaath]]></dc:creator><pubDate>Tue, 11 Apr 2023 04:59:51 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1681150476620/b3aebbac-81c6-480b-a978-4c5c21783939.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Okay, you have a frontend React app and you want to serve it via Docker. Let's do that!</p>
<p>In this wiki, we will dockerize both the development and production environment via separate Dockerfiles.</p>
<h2 id="heading-step-1-project-setup">Step 1: Project setup</h2>
<p>Initialized a pretty standard react project using the default <a target="_blank" href="https://github.com/facebook/create-react-app">create react app</a> (CRA) template. Or pick your existing React app. Below is the sample project folder structure.</p>
<pre><code class="lang-plaintext">├── node_modules
├── public
│   ├── favicon.ico
│   ├── index.html
│   ├── manifest.json
│   └── robots.txt
├── src
│   ├── App.css
│   ├── App.js
│   ├── index.css
│   ├── index.js
│   └── logo.svg
├── package.json
└── yarn.lock
</code></pre>
<hr />
<h2 id="heading-step-2-init-dockerignore">Step 2: Init .dockerignore</h2>
<p>Add a <code>.dockerignore</code> file, this will help us ignore <code>node_modules</code>, <code>.env</code> etc</p>
<pre><code class="lang-plaintext">.git
.gitignore
**/node_modules
**/npm-debug.log
build
</code></pre>
<hr />
<h2 id="heading-step-3-dockerize-development-env">Step 3: Dockerize Development env</h2>
<p><strong>Init Dockerfile</strong></p>
<p>Start by adding a <code>Dockerfile.dev</code></p>
<pre><code class="lang-plaintext">FROM node:14-alpine AS development
ENV NODE_ENV development

# Add a work directory
WORKDIR /app

# Cache and Install dependencies
COPY package.json .
COPY yarn.lock .

#RUN yarn install
RUN npm i

# Copy app files
COPY . .

# Expose port
EXPOSE 3000

# Start the app
CMD [ "yarn", "start" ]
</code></pre>
<p><strong>Init docker-compose</strong></p>
<p>Create a <code>docker-compose.dev.yml</code>. Additionally, we will mount our code in a <a target="_blank" href="https://www.cloudsavvyit.com/7500/what-are-docker-volumes-and-how-do-you-use-them/">volume</a> so that our code changes are in sync with the container during development.</p>
<pre><code class="lang-plaintext">version: "3.8"

services:
  app:
    container_name: app-dev-c
    image: app-dev-i
    build:
      context: .
      dockerfile: Dockerfile.dev
    volumes:
      - ./src:/app/src
    ports:
      - "3000:3000"
</code></pre>
<p>Let's start our React app for development!</p>
<pre><code class="lang-bash">docker-compose -f docker-compose.dev.yml up
</code></pre>
<p>To make life easier add docker-compose commands to <code>package.json</code></p>
<pre><code class="lang-json"><span class="hljs-string">"docker-dev-up"</span>: <span class="hljs-string">"docker-compose -f docker-compose.dev.yml up"</span>
<span class="hljs-string">"docker-dev-down"</span>: <span class="hljs-string">"docker-compose -f docker-compose.dev.yml down"</span>
</code></pre>
<p>Let's check our container!</p>
<pre><code class="lang-plaintext">&gt; docker ps

REPOSITORY          TAG                   IMAGE ID       CREATED              SIZE
app-dev            latest                5867f4e40c98   About a minute ago    436MB
</code></pre>
<p>Visit the app at <a target="_blank" href="http://localhost:3000"><code>http://localhost:3000</code></a></p>
<hr />
<h2 id="heading-step-4-dockerize-production-env">Step 4: Dockerize Production env</h2>
<p>Let's use <a target="_blank" href="https://www.nginx.com/">nginx</a> to serve our static assets and help resolve routes when we're using <a target="_blank" href="https://reactrouter.com/">React Router</a> or any kind of routing.</p>
<p><strong>Configure nginx</strong></p>
<p>Create a <code>nginx.conf</code> with the below content. This will help handle URI changes during routing.</p>
<pre><code class="lang-nginx"><span class="hljs-section">server</span> {
  <span class="hljs-attribute">listen</span> <span class="hljs-number">80</span>;

  <span class="hljs-attribute">location</span> / {
    <span class="hljs-attribute">root</span> /usr/share/nginx/html/;
    <span class="hljs-attribute">include</span> /etc/nginx/mime.types;
    <span class="hljs-attribute">try_files</span> <span class="hljs-variable">$uri</span> <span class="hljs-variable">$uri</span>/ /index.html;
  }
}
</code></pre>
<p><strong>Init Dockerfile</strong></p>
<p>Start by adding a <code>Dockerfile.prod</code></p>
<pre><code class="lang-plaintext">FROM node:14-alpine AS builder
ENV NODE_ENV production

# Add a work directory
WORKDIR /app

# Cache and Install dependencies
COPY package.json .
COPY yarn.lock .
RUN npm i

# Copy app files
COPY . .

# Build the app
RUN npm run build

# Bundle static assets with nginx
FROM nginx:1.21.0-alpine as production
ENV NODE_ENV production

# Copy built assets from builder
COPY --from=builder /app/build /usr/share/nginx/html

# Add your nginx.conf
COPY nginx.conf /etc/nginx/conf.d/default.conf

# Expose port
EXPOSE 80

# Start nginx
CMD ["nginx", "-g", "daemon off;"]
</code></pre>
<p><strong>Init docker-compose</strong></p>
<p>Add a <code>docker-compose.prod.yml</code> file</p>
<pre><code class="lang-plaintext">version: "3.8"

services:
  app:
    container_name: app-prod-c
    image: app-prod-i
    build:
      context: .
      dockerfile: Dockerfile.prod
    ports:
        - "8080:80"
</code></pre>
<p>Build production image</p>
<pre><code class="lang-plaintext">docker-compose -f docker-compose.prod.yml build
</code></pre>
<p>Let's check out our built production image</p>
<pre><code class="lang-plaintext">&gt; docker images

REPOSITORY          TAG                   IMAGE ID       CREATED              SIZE
app-prod           latest                c5db8d308bb9   About a minute ago   23.1MB
</code></pre>
<p>Start our production container on port <code>80</code> with the name <code>react-app</code></p>
<pre><code class="lang-plaintext">docker run -p 8080:80 --name react-app app-prod
</code></pre>
<p>Visit the app at <a target="_blank" href="http://localhost:3000"><code>http://localhost:</code></a><code>8080</code></p>
<p>Here is how the final project struct looks:</p>
<pre><code class="lang-plaintext">├── node_modules
├── public
│   ├── index.html
│   ...
│   └── manifest.json
├── src
│   ├── App.css
│   ...
│   └── index.js
├── package.json
├── yarn.lock
├── .dockerignore
├── Dockerfile.dev
├── Dockerfile.prod
├── docker-compose.dev.yml
└── docker-compose.prod.yml
</code></pre>
<p>Hurrayyy!! We can now use docker in our workflow and deploy our production images faster to any platform.</p>
]]></content:encoded></item><item><title><![CDATA[Host React app in GitHub pages]]></title><description><![CDATA[There is a lot of documentation out there to host your react app on GitHub pages for FREE, which is accessible via https://<git_user>.github.io/<repo_name>ex: adam.github.io/portfolio , vishnu.github.io/my-dev
But this doc will guide you to host reac...]]></description><link>https://blog.vishnuprasaath.dev/host-react-app-in-github-pages</link><guid isPermaLink="true">https://blog.vishnuprasaath.dev/host-react-app-in-github-pages</guid><category><![CDATA[React]]></category><category><![CDATA[GitHubPages]]></category><category><![CDATA[hosting]]></category><category><![CDATA[GitHub]]></category><dc:creator><![CDATA[Vishnu Prasaath]]></dc:creator><pubDate>Tue, 11 Apr 2023 04:11:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1681150651125/5ecc20a4-7ce3-4ee8-a9a7-3b695ff5de09.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>There is a lot of documentation out there to host your react app on GitHub pages for FREE, which is accessible via <code>https://&lt;git_user&gt;.github.io/&lt;repo_name&gt;</code><br /><strong>ex:</strong> <code>adam.github.io/portfolio</code> , <code>vishnu.github.io/my-dev</code></p>
<p>But this doc will guide you to host react app at <code>https://&lt;git_user&gt;.github.io</code> (no need to cling the repo name with URL)<br /><strong>ex:</strong> <code>adam.github.io</code> , <code>vishnu.github.io</code></p>
<p>This approach is preferred for hosting a portfolio or dev-profile website.</p>
<p>There are three types of GitHub Pages sites:</p>
<ol>
<li><p>User Site</p>
</li>
<li><p>Project Site</p>
</li>
<li><p>Organization Site</p>
</li>
</ol>
<p>This blog is inclined toward setting up a <strong>User Site</strong></p>
<p><strong>Let's get started!</strong></p>
<h3 id="heading-step-1-create-a-repo-on-github">Step 1 - Create a repo on GitHub</h3>
<p>Create a new <strong>GitHub repo</strong> named username.github.io (replace username with your current git user name) and make it <strong>Public</strong> (to host private repo in GH pages you need a GitHub Enterprise account)</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681028943747/a7b5d1b9-a715-4e76-8f62-5f486395f5be.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-step-2-create-react-app-and-push-to-repo">Step 2 - Create React app and Push to repo</h3>
<p>Create your react app following the official doc - <a target="_blank" href="https://create-react-app.dev/docs/getting-started/">https://create-react-app.dev/docs/getting-started/</a></p>
<p>Init <strong>git</strong> and <strong>push</strong> it to the above-created repo</p>
<pre><code class="lang-bash">git init
git commit -m <span class="hljs-string">"first commit"</span>
git branch -M main
git remote add origin https://github.com/username/username.github.io.git
git push -u origin main
</code></pre>
<hr />
<h3 id="heading-step-3-setup-gh-pages">Step 3 - Setup gh-pages</h3>
<p>The npm package <a target="_blank" href="https://www.npmjs.com/package/gh-pages">gh-pages</a> helps in configuring and deploying your app to GitHub pages</p>
<pre><code class="lang-bash">npm install gh-pages — save-dev
</code></pre>
<p><strong>Homepage property</strong></p>
<p>Add the below <code>homepage</code> property to your <code>package.json</code> file.</p>
<pre><code class="lang-json">For free GitHub user site, add this: 
<span class="hljs-string">"homepage"</span>: <span class="hljs-string">"https://{username}.github.io"</span>

If you own a domain, add this:
<span class="hljs-string">"homepage"</span>: <span class="hljs-string">"https://mydomainname.com"</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681030015020/bc19bfff-fb70-457e-b0ff-6a0e5a2ab97d.png" alt class="image--center mx-auto" /></p>
<p><strong>Deploy Script</strong></p>
<p>Add both <strong>predeploy</strong> and <strong>deploy</strong> property scripts to the <code>package.json</code> as below</p>
<pre><code class="lang-json"><span class="hljs-string">"predeploy"</span>: <span class="hljs-string">"npm run build"</span>,
<span class="hljs-string">"deploy"</span>: <span class="hljs-string">"gh-pages -d build"</span>
</code></pre>
<p><strong>predeploy</strong> - bundle the react application<br /><strong>deploy</strong> - deploy the bundled file.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681030290187/7fb123aa-6a9a-4864-9b67-b36cba2bbbf1.png" alt class="image--center mx-auto" /></p>
<p>Push these changes to the git repo</p>
<pre><code class="lang-bash">git commit -m <span class="hljs-string">"configure gh-pages"</span>
git push
</code></pre>
<hr />
<h3 id="heading-step-4-deploy-the-app-to-github-pages">Step 4 - Deploy the app to GitHub Pages</h3>
<p>Run the below command to deploy your react application to GitHub Pages</p>
<pre><code class="lang-bash">npm run deploy
</code></pre>
<hr />
<h3 id="heading-step-5-finally-access-the-deployed-site">Step 5 - Finally access the deployed site</h3>
<ul>
<li><p>Go to the GitHub repo</p>
</li>
<li><p>Click <strong>Settings</strong> menu</p>
</li>
<li><p>Go to the <strong>Code and Automation</strong> -&gt; <strong>Pages</strong> section</p>
</li>
<li><p>In the <strong>Build and Deployment</strong> section, select <strong>Source</strong> to <strong>Deploy from a branch</strong></p>
</li>
<li><p>Select the <strong>branch</strong> to <strong>"gh-pages"</strong> and click on the <strong>"Save"</strong> button</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681030949821/769b9096-2a16-4702-8a6a-03f0b1b632a5.png" alt class="image--center mx-auto" /></p>
<p>Visit <code>username.github.io</code> and check out your site.</p>
<p>Yayy!</p>
<p>Your website is hosted for FREEEE in GitHub Pages and accessible to the world.</p>
]]></content:encoded></item></channel></rss>