<?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[Raman Karki Blogs | Full Stack Developer]]></title><description><![CDATA[Are you ready to explore software development and related fields? My name is Raman Karki and I'm a Full Stack Developer with real world experience]]></description><link>https://blog.ramankarki.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1625418859214/JXwmBY0ZE.png</url><title>Raman Karki Blogs | Full Stack Developer</title><link>https://blog.ramankarki.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Thu, 23 Apr 2026 22:55:38 GMT</lastBuildDate><atom:link href="https://blog.ramankarki.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Journal: From Copilot Prompts to a Full Link Shortener App]]></title><description><![CDATA[Setting Up Copilot Agents with Custom Instructions
I started GitHub Copilot Beginner to Pro - AI for Coding & Development Udemy course and wanted to learn agentic coding. By following the course, I ad]]></description><link>https://blog.ramankarki.dev/journal-from-copilot-prompts-to-a-full-link-shortener-app</link><guid isPermaLink="true">https://blog.ramankarki.dev/journal-from-copilot-prompts-to-a-full-link-shortener-app</guid><dc:creator><![CDATA[Raman Karki]]></dc:creator><pubDate>Tue, 03 Mar 2026 18:13:37 GMT</pubDate><content:encoded><![CDATA[<h2>Setting Up Copilot Agents with Custom Instructions</h2>
<p>I started <a href="https://www.udemy.com/course/github-copilot/">GitHub Copilot Beginner to Pro - AI for Coding &amp; Development</a> Udemy course and wanted to learn agentic coding. By following the course, I added custom agents and prompts to the GitHub Copilot setup inside the profiler. Basically treating Copilot like a proper agentic coding partner for the first time.</p>
<p>The first prompt was simple:</p>
<blockquote>
<p>create a <code>/dashboard</code> page, no real content yet, just a placeholder.</p>
</blockquote>
<p>Then I layered in the standards — a follow-up prompt told it to make sure the dashboard page follows the authentication coding standard. What surprised me was that the agent actually went and read the <code>authentication.md</code> file inside the /docs folder on its own. No hand-holding needed.</p>
<p>I did the same for the home page, and again it read the relevant instruction doc. Then I asked it to make sure the sign-up and sign-in buttons follow the UI component coding standard — and it pulled up <code>ui-component.md</code>, read it, and updated the header accordingly using the <code>shadcn</code> component. That felt like a proper workflow clicking into place.</p>
<hr />
<h2>Tightening the Agent Instructions</h2>
<p>After watching the agent work, I realized the instruction chain needed to be more explicit. I gave it a prompt to update <code>AGENTS.md</code> to make it <em>crystal clear</em> that reading the relevant individual instruction files inside <code>/docs</code> before generating any code is non-negotiable.</p>
<p>The agent rewrote the <code>AGENTS.md</code> file — added a new critical section, listed all the directive documents, and restructured things so the priority order was obvious. Small prompt, meaningful change.</p>
<hr />
<h2>Signing Up for the Anthropic API</h2>
<p>Since I'm actively learning agentic coding, I went ahead and signed up for the Anthropic API. Bought $5 of credit to start experimenting with the models directly — coding, audio processing, that sort of thing.</p>
<hr />
<h2>Understanding Agent Types</h2>
<p>Took a moment to properly understand the different types of agents available:</p>
<ul>
<li><p><strong>Local agent</strong> — you give it a prompt and it runs directly on your device.</p>
</li>
<li><p><strong>Background agent</strong> — starts working in the background after receiving a prompt.</p>
</li>
<li><p><strong>Cloud agent</strong> — similar to GitHub Copilot's cloud-based execution model.</p>
</li>
</ul>
<p>Each has its own trade-offs depending on the task. Good to have the mental model straight before diving deeper.</p>
<hr />
<h2>Designing the Link Schema with Drizzle ORM</h2>
<p>Moved on to actual feature work. I needed a database table to store shortened links. Gave the agent a prompt to design a simple table schema and it created a schema file inside the <code>/db</code> folder using the Drizzle ORM.</p>
<p>The schema had the right fields: <code>id</code>, <code>shortcode</code>, <code>url</code>, <code>userId</code>, <code>createdAt</code>, and <code>updatedAt</code>. Table name: <code>links</code>. Clean and straightforward.</p>
<pre><code class="language-typescript">import { pgTable, text, varchar, timestamp } from 'drizzle-orm/pg-core';

export const links = pgTable('links', {
  id: text('id').primaryKey(),
  shortCode: varchar('short_code', { length: 20 }).notNull().unique(),
  originalUrl: text('original_url').notNull(),
  userId: text('user_id').notNull(),
  createdAt: timestamp('created_at').defaultNow().notNull(),
  updatedAt: timestamp('updated_at').defaultNow().notNull(),
});
</code></pre>
<p>I started with the <code>ask</code> agent type to let it design the schema first before committing to implementation. Once I was happy with it, I told the agent to start the implementation. I also asked it to properly declare and type the <code>id</code> fields.</p>
<p>Then came the sync step — I asked how to push the schema to the Neon platform. It walked me through:</p>
<ol>
<li><p><code>npx drizzle-kit generate</code> — generates the SQL migration file inside the <code>/drizzle</code> folder.</p>
</li>
<li><p><code>npx drizzle-kit push</code> — syncs the schema to the Neon database.</p>
</li>
</ol>
<p>Worked first try.</p>
<hr />
<h2>Using MCP Inside VS Code with Neon</h2>
<p>This was a new one for me. Learned how to connect an MCP (Model Context Protocol) extension in VS Code to an external service — in this case, Neon.</p>
<p>The flow is roughly:</p>
<ol>
<li><p>Install the Neon MCP extension in VS Code.</p>
</li>
<li><p>Connect your Neon account to the extension.</p>
</li>
<li><p>Configure which tools you want to expose to the Copilot chat.</p>
</li>
<li><p>Enable those tools and start prompting.</p>
</li>
</ol>
<p>Once connected, I could just type <code>list my Neon projects</code> and it would return actual project data from my Neon account. I also ran <code>list out tools you have with the Neon MCP</code> and got back the full list of available operations.</p>
<p>The most satisfying part: I asked it to generate 10 example link records following my schema, and it produced a JSON file with 10 properly structured entries. Then I told it to insert that data into my <code>links</code> table using my user ID — it generated a small script and ran it, populating the Neon database directly.</p>
<hr />
<h2>Switching to Native GitHub Copilot Instructions</h2>
<p>Found out that GitHub Copilot has a native instruction system built around the <code>.github/instructions/</code> folder. You put instruction files there, give each one a description in the front matter, and Copilot agents automatically pick up the right ones based on the description.</p>
<p>This is basically the same pattern I was already using with the <code>/docs</code> folder — but now it's native. A few things to note:</p>
<ul>
<li><p>All instruction files use the <code>.instructions.md</code> extension.</p>
</li>
<li><p>You write a <code>description</code> in the front matter — that's what the agent reads to decide if a file is relevant.</p>
</li>
<li><p>You no longer need to manually reference these files in <code>AGENTS.md</code>.</p>
</li>
</ul>
<p>I migrated my existing instruction files into <code>.github/instructions/</code> and that cleaned things up nicely.</p>
<hr />
<h2>Building the Dashboard — Links List View</h2>
<p>With the instructions in place, I gave the agent a real feature prompt: build out the dashboard page, query for the currently logged-in user's links, and display them as a list. I referenced the dashboard file directly using <code>#</code> in the prompt.</p>
<p>It updated the dashboard page, wired up the query, and the list rendered correctly — showing links tied to the logged-in user. There were a couple of UI issues after the first pass, but one follow-up prompt fixed them. Dashboard was functional.</p>
<hr />
<h2>Server Actions — Writing the Instruction File</h2>
<p>Before building out more features, I created a new instruction file specifically for server actions. The rules I put in:</p>
<ul>
<li><p>All data mutations go through server actions only.</p>
</li>
<li><p>Server actions must be called from the component that needs them.</p>
</li>
<li><p>Files must be named <code>action.ts</code> and live in the same directory as the calling component.</p>
</li>
<li><p>All incoming data must have proper TypeScript types — no <code>any</code>.</p>
</li>
<li><p>All data must be validated via Zod.</p>
</li>
<li><p>Always check for a logged-in user before touching the database.</p>
</li>
<li><p>Database operations go through helper functions (located in the <code>/db</code> directory) — server actions don't write raw queries.</p>
</li>
<li><p>Server actions must never throw. They return either <code>{ error: "..." }</code> or <code>{ success: "..." }</code>.</p>
</li>
</ul>
<hr />
<h2>Create, Edit, Delete, and Redirect</h2>
<p>With the standards locked in, I moved fast on features:</p>
<p><strong>Create:</strong> Prompted the agent to implement the link creation flow from the dashboard. It added a create button and the supporting logic.</p>
<p><strong>Refresh bug:</strong> After creating a link, the dashboard wasn't updating. Gave a prompt describing the bug and it traced it back to the codebase and fixed it.</p>
<p><strong>Edit &amp; Delete:</strong> One prompt — implement edit via a modal, delete via a confirmation dialog, referenced the dashboard file. It implemented both. There was a small typing bug in the edit modal's input field; another short prompt fixed it.</p>
<p><strong>Redirect:</strong> Asked it to implement the redirect functionality via an API route handler. Whenever someone hits <code>/l/[shortcode]</code>, they get redirected to the full URL. It created the route handler and it works.</p>
<hr />
<h2>Learning About Subagents</h2>
<p>Took a detour to understand subagents. The idea is:</p>
<p>When a task is large, the main agent's context window can fill up fast. Subagents are isolated agent instances spun up by the main agent to handle specific chunks of the work. Each subagent gets its own full context, so you're not cramming everything into one window.</p>
<p>They're especially useful for parallel tasks — things that don't depend on each other can run at the same time across separate subagents.</p>
<hr />
<h2>Skills and Context Management</h2>
<p>Related to the context problem — learned about "skills". The issue is that loading all instruction files and MCP tool definitions on every prompt burns through context quickly.</p>
<p>With skills, the agent only loads the <em>description</em> of each skill upfront. Based on the prompt, it decides which skills are actually needed, then loads only those specific instruction sets. It's lazy-loading for agent knowledge.</p>
<p>For a project with lots of directive files, this makes a real difference in how far you can go before the context fills up.</p>
<hr />
<h2>Wrapping Up — Course Done, Model Costs</h2>
<p>Finished the GitHub Copilot Beginner to Pro course today. The project — a working link shortener — turned out well. Honestly impressed with how capable agentic coding was throughout.</p>
<p><a href="https://github.com/ramankarki/link-shortner-vibe">Here is the final project</a>.</p>
<p>One thing I noticed along the way: the Claude Code model is noticeably more expensive than alternatives. Worth looking into <code>Minimax M2.5 AI</code> as cheaper options that apparently perform close to Claude. Planning to watch a few comparison videos on YouTube and also explore running the Qwen 3.5 AI model locally to see if I can get similar results without the cost.</p>
<hr />
<p><em>Total features shipped: dashboard, create/edit/delete links, redirect handler, server action standards, MCP-driven seed data.</em> <em>Next up: model cost comparison, local model experiments.</em></p>
]]></content:encoded></item><item><title><![CDATA[Journal: Traveling URL Shortener App, Stack Setup, Custom Agents]]></title><description><![CDATA[Travel Days (Low Output)
The past couple of days were mostly travel and life-admin. Couldn't get much done on anything. Today I was pretty tired coming back to it, so I decided to just continue with t]]></description><link>https://blog.ramankarki.dev/journal-traveling-bootstrapping-url-shortener-app-stack-setup-custom-agents</link><guid isPermaLink="true">https://blog.ramankarki.dev/journal-traveling-bootstrapping-url-shortener-app-stack-setup-custom-agents</guid><dc:creator><![CDATA[Raman Karki]]></dc:creator><pubDate>Sat, 28 Feb 2026 18:12:35 GMT</pubDate><content:encoded><![CDATA[<h2>Travel Days (Low Output)</h2>
<p>The past couple of days were mostly travel and life-admin. Couldn't get much done on anything. Today I was pretty tired coming back to it, so I decided to just continue with the course as much as I can and call it a day. No shame in that — slow progress is still progress.</p>
<h2>Getting the Project Off the Ground</h2>
<p>Started a new project today — a URL shortener app. The approach here is a bit different from how I'd normally do things: I'm using whiteboarding alongside a Udemy course called <em>GitHub Copilot Beginner to Pro</em> to build and treat this as a proof of concept at the same time.</p>
<p>First things first — scaffolded a new <strong>Next.js</strong> project.</p>
<hr />
<h2>Setting Up Authentication with Clerk</h2>
<p>Next up was signing up for <strong>Clerk</strong> for authentication. The process was pretty smooth — created an account, set up a notification, selected the framework, and copied the integration prompt that Clerk provides.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d9795b703d372ea06c7378/876b378b-e74e-49f0-955b-a7bd04be68ee.png" alt="" style="display:block;margin:0 auto" />

<p>The nice thing about Clerk is that it ships with a ready-made prompt you can just hand straight to GitHub Copilot Chat, and it handles the integration for you.</p>
<hr />
<h2>Database Setup — Neon.tech &amp; Drizzle ORM</h2>
<h3>Spinning up Neon</h3>
<p>Created an account on <a href="http://neon.com"><strong>neon.com</strong></a> and set up a new project there. Neon gives you a free-tier server-less Postgres database, which is perfect for this kind of proof-of-concept work. No overhead, no cost to get started.</p>
<h3>Drizzle ORM — The Manual Route</h3>
<p>This is where things got a little bumpy. The course has you follow all the steps manually to connect <strong>Drizzle ORM</strong> with Neon, and honestly — it felt off compared to how the Clerk section was handled.</p>
<p>Maybe the reason Clerk was smoother is that Clerk actually ships a ready-made integration prompt. Drizzle just doesn't have that, so there's nothing to hand off to the agent. That context makes it make sense, even if it slowed things down.</p>
<hr />
<h2>What I Learned Today — Custom Agents &amp; Instruction Files in VS Code</h2>
<p>The video I watched today was actually really useful. It walked through how to create <strong>custom agents and custom prompts inside VS Code</strong>, and then use those inside <strong>GitHub Copilot Chat</strong>.</p>
<p>The workflow goes something like this:</p>
<ol>
<li><p>Create custom prompts in VS Code</p>
</li>
<li><p>Use those prompts to generate <strong>instruction files</strong></p>
</li>
<li><p>Store instruction files inside a <code>/docs</code> folder in the project</p>
</li>
<li><p>Reference those files in <code>AGENTS.md</code> file so Copilot picks them up automatically</p>
</li>
</ol>
<p>This is actually a pretty powerful pattern. Instead of re-explaining the project context every time you open Copilot Chat, you bake the context into files that get pulled in automatically. It keeps the agent grounded in what the project actually is.</p>
<hr />
<h2>What's Next</h2>
<p>The plan for tomorrow is to start putting those instruction files to actual use — generate some real components and hopefully get the dashboard pages started. That's where things should start feeling like a real app rather than a setup exercise.</p>
]]></content:encoded></item><item><title><![CDATA[Journal: LangChain Deep Dive, Vector DBs, and a Clock Conversion Puzzle]]></title><description><![CDATA[LangChain Chains: Sequential vs. Routing
Spent the morning going through LangChain chaining. The core idea is straightforward — you build multiple prompt chains and wire them together so the output of]]></description><link>https://blog.ramankarki.dev/journal-langchain-deep-dive-vector-dbs-and-a-clock-conversion-puzzle</link><guid isPermaLink="true">https://blog.ramankarki.dev/journal-langchain-deep-dive-vector-dbs-and-a-clock-conversion-puzzle</guid><dc:creator><![CDATA[Raman Karki]]></dc:creator><pubDate>Wed, 25 Feb 2026 17:58:44 GMT</pubDate><content:encoded><![CDATA[<h2>LangChain Chains: Sequential vs. Routing</h2>
<p>Spent the morning going through LangChain chaining. The core idea is straightforward — you build multiple prompt chains and wire them together so the output of one feeds into the input of the next. Think of it as an assembly line for LLM calls. You kick off the first chain with raw user input, and by the end of the pipeline you've got a final, refined response.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d9795b703d372ea06c7378/450f6c57-42d6-410e-a5f9-5af018cd6878.svg" alt="" style="display:block;margin:0 auto" />

<p>The more interesting bit was the <strong>routing chain</strong>. The use case that clicked for me: imagine a chatbot that supports multiple domains — physics, math, history, science. Each domain has its own system prompt tuned for that subject. When a user asks something, the routing chain figures out which "expert" chain is the best fit, then passes the input there. There's also a fallback default prompt in case nothing matches.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60d9795b703d372ea06c7378/08dab30c-b022-46a0-be98-79ac6e035705.svg" alt="" style="display:block;margin:0 auto" />

<p>The routing chain actually makes two LLM calls: one to decide the route, and a second to get the actual answer using the matched system prompt. Took me a moment to internalize that it's two round-trips, not one.</p>
<hr />
<h2>RAG: Four Ways to Query Documents with a Vector Database</h2>
<p>Next up was a video on using vector databases to build a question-answering system over documents. The gist: you embed your document content into a vector store, then query it. But <em>how</em> you query and pass context to the LLM makes a big difference. There are four approaches covered:</p>
<ol>
<li><p><strong>Stuffing</strong> — Dump the entire document content into the context window and send it with the prompt in one shot. Simple, but falls apart with large docs.</p>
</li>
<li><p><strong>Map Reduce</strong> — Process each document chunk individually, passing each one along with the prompt to the LLM. The catch is the model only ever sees one chunk at a time, so it has no awareness of what came before or after. That limits the quality of answers that need cross-document context.</p>
</li>
<li><p><strong>Refine</strong> — Similar to Map Reduce, but each iteration carries a summary of the previous response forward. It builds up context progressively, which gives the model a better running picture of the document as a whole.</p>
</li>
<li><p><strong>Map Rerank</strong> — Each document chunk gets a relevance score when processed. After scoring all chunks, the highest-scoring one gets pulled and used as the context for the final answer. Good when you want the model to focus on the most relevant passage.</p>
</li>
</ol>
<img src="https://cdn.hashnode.com/uploads/covers/60d9795b703d372ea06c7378/7635f83b-25e1-452d-8c2c-96e7fe781dbb.svg" alt="" style="display:block;margin:0 auto" />

<hr />
<h2>AI Agents with LangChain — Moving On</h2>
<p>Finished the agents section of the course. The pattern is: wire up an LLM as the reasoning engine, attach tools to it, and you've got an agent. Nothing too surprising there conceptually.</p>
<p>Honestly, I got to the end of this course and realized I haven't found a concrete project to build with this yet. The knowledge is there, but nothing has clicked as an immediate "I can build this now" moment. Closing this one out and moving to the next course.</p>
<hr />
<h2>HackerRank Algorithms: Warmup Done, Then Hit a Real Problem</h2>
<p>Switched gears to HackerRank for some algorithm practice. The warmup subdomain had around 10-11 questions — all very beginner level. Knocked them all out in under 5 minutes, every piece of code running on the first try. Nothing worth writing home about.</p>
<p>Then the last question actually made me think. The task: convert a 12-hour AM/PM time string into 24-hour format. Sounds trivial. Wasn't quite.</p>
<hr />
<h2>Solving the 12-Hour to 24-Hour Clock Conversion</h2>
<p>The tricky part is the edge cases around 12:00. The conversion rules are:</p>
<ul>
<li><p><code>12:xx AM</code> → <code>00:xx</code> (midnight edge case)</p>
</li>
<li><p><code>1:xx AM</code> through <code>11:xx AM</code> → same hour, no change</p>
</li>
<li><p><code>12:xx PM</code> → <code>12:xx</code> (noon, stays as-is)</p>
</li>
<li><p><code>1:xx PM</code> through <code>11:xx PM</code> → add 12 to the hour</p>
</li>
</ul>
<p>My first pass extracted the hour, minutes, seconds, and the AM/PM suffix into separate variables. Then I wrote the conditions:</p>
<ol>
<li><p>If hour is <code>12</code> and it's <code>AM</code> → set hour to <code>00</code></p>
</li>
<li><p>If it's <code>AM</code> (and not 12) → keep the hour as-is</p>
</li>
<li><p>If it's <code>PM</code> → add 12 to the hour</p>
</li>
</ol>
<p>Ran it and immediately hit a bug. When the input was <code>12:xx PM</code>, my code was outputting <code>24</code> — because it was blindly adding 12 to 12. The fix was one extra condition: if the hour is already <code>12</code> and it's <code>PM</code>, just leave it at <code>12</code>. Don't add anything.</p>
<pre><code class="language-typescript">function timeConversion(s: string): string {
    const h = s[0] + s[1]
    const m = s[3] + s[4]
    const sec = s[6] + s[7]
    const isAM = s[8] + s[9] === 'AM'
    let fullHour = ''
    
    if (h === '12' &amp;&amp; isAM) fullHour = '00'
    else if (isAM) fullHour = h
    else if (h === '12') fullHour = '12'
    else fullHour = `${12 + +h}`
    
    fullHour += `:\({m}:\){sec}`
    return fullHour
}
</code></pre>
<blockquote>
<p>input <code>07:05:45PM</code><br />output <code>19:05:45</code></p>
</blockquote>
<p>That one edge case was the whole puzzle, really. After patching it, all test cases passed.</p>
<hr />
<h2>Up Next: GitHub Copilot for Agentic Coding</h2>
<p>Picked up a Udemy course by Tom Phillips on using GitHub Copilot for agentic coding workflows — how to use it to actually build applications, not just autocomplete snippets. Just getting started, carrying this into tomorrow.</p>
]]></content:encoded></item><item><title><![CDATA[Journal: Valid Parentheses, Interview Prep Pivot & LangChain Memory]]></title><description><![CDATA[Cracking Valid Parentheses with a Stack
Picked up LeetCode problem #20 today — Valid Parentheses. Honestly not a hard one once you recognize it's a classic stack problem. The core idea is simple: ever]]></description><link>https://blog.ramankarki.dev/journal-valid-parentheses-interview-prep-pivot-langchain-memory</link><guid isPermaLink="true">https://blog.ramankarki.dev/journal-valid-parentheses-interview-prep-pivot-langchain-memory</guid><dc:creator><![CDATA[Raman Karki]]></dc:creator><pubDate>Tue, 24 Feb 2026 04:45:00 GMT</pubDate><content:encoded><![CDATA[<h3>Cracking Valid Parentheses with a Stack</h3>
<p>Picked up LeetCode problem #20 today — Valid Parentheses. Honestly not a hard one once you recognize it's a classic stack problem. The core idea is simple: every time you see an opening bracket, push it onto the stack. When you hit a closing bracket, peek at the top of the stack and check if it's the matching opener.</p>
<p>I started by initializing an empty stack and a hash map that pairs each closing bracket to its corresponding opening bracket — so <code>}</code> maps to <code>{</code>, <code>]</code> to <code>[</code>, and <code>)</code> to <code>(</code>. Then I looped through every character in the string. If it's an opening bracket, push it and continue. If it's a closing bracket, pop the last element from the stack and check if it matches what the hash map expects. If it doesn't match, the string is invalid — return false right there.</p>
<p>After the loop, the final check is whether the stack is empty. If there are still elements sitting in it, that means some opening brackets were never closed, so it's still invalid. Empty stack means we're good.</p>
<pre><code class="language-typescript">function isValid(s: string): boolean {
    const stack = []
    const pair = {
        ')': '(',
        '}': '{',
        ']': '['
    }

    for (let bracket of s) {
        if (bracket === '(' || bracket === '{' || bracket === '[') {
            stack.push(bracket)
            continue
        }
        const lastBracket = stack.at(-1)
        if (lastBracket !== pair[bracket]) return false
        stack.pop()
    }

    return !stack.length
};
</code></pre>
<hr />
<h3>Why I'm Pausing LeetCode for HackerRank</h3>
<p>While browsing around today I ended up on HackerRank and spent some time thinking about interview prep strategy. A few of the bigger tech companies here in Nepal actually use HackerRank for their technical screening rounds, which I didn't realize before. That changes things a bit.</p>
<p>I'm going to put LeetCode on hold for now and shift focus to HackerRank. I also want to take the front-end developer certification they offer — and honestly any other relevant certification on the platform. Better to align prep with what companies are actually going to throw at me.</p>
<hr />
<h3>LangChain Memory — Four Types Worth Knowing</h3>
<p>Watched a couple of LangChain videos today. The first was mostly introductory stuff — how to set up the library, specify models, write prompts, and parse outputs. That level of detail is pretty well covered in the official docs anyway.</p>
<p>The second video was the more interesting one. It digs into how memory works in LangChain, which is really the core of building any useful chatbot.</p>
<ol>
<li><p><strong>Buffer Memory</strong> is the straightforward one — store the entire conversation history and feed it all back on each call. Simple, but it gets expensive fast.</p>
</li>
<li><p><strong>Buffer Window Memory</strong> is a smarter version — instead of keeping everything, you only retain the last <em>k</em> messages (say, 5 or 10). Anything older just gets dropped. Good for keeping token usage in check.</p>
</li>
<li><p><strong>Token Buffer Memory</strong> puts a hard cap on the number of tokens the model can use for context — something like 50 or 100 tokens max. It's a more granular way to manage cost vs. context tradeoff.</p>
</li>
<li><p><strong>Summary Memory</strong> is the one that actually excited me. After each exchange, you ask the model to summarize the conversation so far and store that summary instead of the raw messages. You're keeping the semantic content of the whole conversation without burning tokens on verbatim history. This feels like the most practical approach for real-world chatbots.</p>
</li>
<li><p><strong>Vector Data Memory</strong>. Instead of keeping conversation history in a list or summary, you store it in a vector database. When you need context, you query the DB for semantically relevant chunks rather than pulling everything. This is probably the most powerful option for long-running or knowledge-heavy applications.</p>
</li>
</ol>
<hr />
<p><em>Short day but productive across three different areas — algorithm practice, interview strategy, and AI tooling. The LangChain memory types are going to be useful soon.</em></p>
]]></content:encoded></item><item><title><![CDATA[Journal: Prompt Engineering Done, LangChain Started, and Finally Cracking LeetCode 42]]></title><description><![CDATA[Wrapping Up the Prompt Engineering Course
Finished the ChatGPT Prompt Engineering for Developers course on deeplearning.ai today — or at least got close enough to call it done. It's a beginner-level c]]></description><link>https://blog.ramankarki.dev/journal-prompt-engineering-done-langchain-started-and-finally-cracking-leetcode-42</link><guid isPermaLink="true">https://blog.ramankarki.dev/journal-prompt-engineering-done-langchain-started-and-finally-cracking-leetcode-42</guid><dc:creator><![CDATA[Raman Karki]]></dc:creator><pubDate>Mon, 23 Feb 2026 04:45:00 GMT</pubDate><content:encoded><![CDATA[<h2>Wrapping Up the Prompt Engineering Course</h2>
<p>Finished the <em>ChatGPT Prompt Engineering for Developers</em> course on <a href="http://deeplearning.ai">deeplearning.ai</a> today — or at least got close enough to call it done. It's a beginner-level course, but honestly it had a few good reminders worth writing down.</p>
<p>The core message of the whole thing boiled down to two rules: <strong>be as specific as possible</strong>, and <strong>give the model time to think</strong>. Everything else kind of builds on top of those two ideas.</p>
<p>For being specific, the course pushes you to:</p>
<ol>
<li><p>Use delimiters to structure your prompts</p>
</li>
<li><p>Provide the output format</p>
</li>
<li><p>Add conditions so you can verify whether the output actually satisfies what you were looking for</p>
</li>
</ol>
<p>Simple stuff on paper, but easy to forget when you're just throwing things at a model hoping something sticks.</p>
<p>The "give the model time to think" part was about breaking your prompt into explicit steps — basically treating the model like it needs a recipe, not a vague instruction. Specify each step, ask for output in a defined shape, and let the model work through it rather than expecting a magic one-liner to do everything.</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/60d9795b703d372ea06c7378/c8ec9d53-0eb9-479b-ac93-90e7204c4230.svg" alt="" style="display:block;margin:0 auto" />

<p>Beyond the prompting basics, the course walked through a handful of practical use cases: iterative prompting (start rough, refine gradually), summarizing content, inferring meaning, transforming text, expanding ideas from a seed concept, and finally building a chatbot. The chatbot section was probably the most useful — it showed how to use a list of messages with a system prompt at the start, then alternating user and assistant turns, to maintain context across a conversation.</p>
<hr />
<h2>Next Up: LangChain for LLM App Development</h2>
<p>Right after finishing the prompt engineering course, I jumped straight into the <em>LangChain for LLM Application Development</em> course. Haven't gotten far yet, but that's where the focus is moving next.</p>
<hr />
<h2>LeetCode 42 — Trapping Rain Water</h2>
<p>Took a break from courses and worked on a LeetCode problem. The problem gives you an array of heights and asks how many units of water the elevation map can trap between the bars after it rains. Classic.</p>
<p>For example: <code>[1, 0, 2]</code> can trap one unit of water in the dip at index 1. The goal is to figure out the total across the whole array.</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/60d9795b703d372ea06c7378/e8d7769c-70e3-4d22-b496-768757572348.png" alt="" style="display:block;margin:0 auto" />

<p>My first instinct was to go with a two-pointer setup and find the next greater element using a monotonic stack. The problem is, I couldn't remember exactly how the monotonic stack worked. I tried to reconstruct it from memory — empty array for the stack, another array for the output, fill with the same length as the input — but I got fuzzy pretty quickly.</p>
<p>I attempted it anyway. The rough idea was: for every element, if the current number is smaller than the top of the stack, pop it and push the new number. That gets rid of any smaller numbers and leaves you with the next greater elements. In theory. In practice, I was going in circles and not actually extracting anything useful.</p>
<hr />
<h2>First Real Attempt — Next Greater Element from Both Sides</h2>
<p>I stepped back and thought about it differently. The idea was to find the next greater element going left to right, and then separately going right to left. For every index, the water it can hold is determined by the minimum of those two "walls" minus the current height at that position.</p>
<pre><code class="language-plaintext">// Pseudocode sketch
for each index i:
    leftMax[i]  = max height to the left of i
    rightMax[i] = max height to the right of i
    minWall = min(leftMax[i], rightMax[i])
    if minWall &gt; height[i]:
        water += minWall - height[i]
</code></pre>
<p>I coded it up, but my output was off — expected 5, got 6, didn't match. The indexing or the boundary conditions were wrong somewhere. I decided to look at the algorithm more carefully instead of guessing.</p>
<hr />
<h2>Prefix Max Array Approach — The One That Actually Worked</h2>
<p>After reviewing, I found two clean approaches. Started with the prefix sum (or prefix max) array method.</p>
<p>The idea is straightforward: precompute an array <code>leftMax</code> where <code>leftMax[i]</code> is the highest bar seen so far from the left up to (but not including) <code>i</code>. Then do the same from the right with <code>rightMax[i]</code>. Once you have both, loop through every index and compute the water.</p>
<p>For the left pass, start from index 1 and at each step take the max of <code>leftMax[i-1]</code> and <code>height[i-1]</code>. For the right pass, start from index <code>height.length - 2</code> and move backwards, taking the max of <code>rightMax[i+1]</code> and <code>height[i+1]</code>.</p>
<p>I logged <code>leftMax</code> and <code>rightMax</code> first just to sanity-check they were right, and they looked good. Then I added the water calculation — only add if <code>minimum - currentHeight &gt; 0</code>, otherwise skip. Submitted. It worked.</p>
<p>The final code</p>
<pre><code class="language-typescript">function trap(height: number[]): number {
    const leftMax = new Array(height.length).fill(0)
    for (let i = 1; i &lt; height.length; i++) {
        leftMax[i] = Math.max(leftMax[i - 1], height[i - 1])
    }

    const rightMax = new Array(height.length).fill(0)
    for (let i = height.length - 2; i &gt;= 0; i--) {
        rightMax[i] = Math.max(rightMax[i + 1], height[i + 1])
    }

    let water = 0
    for (let i = 0; i &lt; height.length; i++) {
        const min = Math.min(leftMax[i], rightMax[i])
        if (min - height[i] &lt; 0) continue
        water += min - height[i]
    }

    return water
};
</code></pre>
<hr />
<h2>Monotonic Stack Approach — The Hard Way (and also working now)</h2>
<p>With the prefix sum solution accepted, I went back and made myself figure out the monotonic stack version properly.</p>
<p>The stack stores indices, not heights. You loop through every height, and before pushing the current index, you check: if the stack isn't empty and the current height is greater than the height at the top of the stack, that means you've found a "bowl" — a dip that can hold water.</p>
<p>When that happens:</p>
<ol>
<li><p>Pop the top of the stack — that's the <strong>bottom</strong> of the bowl.</p>
</li>
<li><p>If the stack is now empty, there's no left wall, so break out of the while loop.</p>
</li>
<li><p>The <strong>left wall</strong> is whatever is now at the top of the stack.</p>
</li>
<li><p>The <strong>right wall</strong> is the current index.</p>
</li>
<li><p>Compute the width: <code>currentIndex - leftIndex - 1</code></p>
</li>
<li><p>Compute the effective height: <code>min(height[left], height[current]) - height[bottom]</code></p>
</li>
<li><p>Water trapped in this segment: <code>height * width</code></p>
</li>
<li><p>Add to total and keep looping.</p>
</li>
</ol>
<p>The <code>-1</code> on the width tripped me up for a bit. If the left wall is at index 3 and the right wall is at index 5, the raw difference is 2, but there's only 1 cell in between (index 4). So you always subtract 1.</p>
<pre><code class="language-typescript">function trap(height: number[]): number {
    let water = 0
    const stack = []
    for (let i = 0; i &lt; height.length; i++) {
        while (stack.length &amp;&amp; height[i] &gt; height[stack.at(-1)]) {
            const gap = stack.pop()
            if (!stack.length) break
            const left = stack.at(-1)
            const width = i - left - 1
            const boundHeight = Math.min(height[left], height[i]) - height[gap]
            water += boundHeight * width
        }
        stack.push(i)
    }

    return water
};
</code></pre>
<p>The while loop runs inside the for loop, and the stack push happens after the while loop exits. That's the rhythm of the whole thing.</p>
<hr />
<h2>What I Took Away Today</h2>
<p>The prompt engineering course was a good foundation even if it felt basic — the iterative prompting section especially. For the LeetCode problem, the prefix sum approach is the easier one to reason about; the monotonic stack is more efficient in some ways but demands clean mental model to avoid off-by-one bugs. Got both working, which felt like a good ending to a long day.</p>
]]></content:encoded></item><item><title><![CDATA[Hashnode Multi-Site Bugs, Blog Architecture Rethink, and Cracking LeetCode #15 3Sum]]></title><description><![CDATA[Started the day with a job application, ended up down a rabbit hole
It started simple enough — I was going to apply for a senior software engineer position and needed to update my portfolio. But the m]]></description><link>https://blog.ramankarki.dev/hashnode-multi-site-bugs-blog-architecture-rethink-and-cracking-leetcode-15-3sum</link><guid isPermaLink="true">https://blog.ramankarki.dev/hashnode-multi-site-bugs-blog-architecture-rethink-and-cracking-leetcode-15-3sum</guid><dc:creator><![CDATA[Raman Karki]]></dc:creator><pubDate>Sat, 21 Feb 2026 18:15:00 GMT</pubDate><content:encoded><![CDATA[<h3>Started the day with a job application, ended up down a rabbit hole</h3>
<p>It started simple enough — I was going to apply for a senior software engineer position and needed to update my portfolio. But the moment I opened my blog site, I noticed something that had been bugging me for a while: my journals and my proper articles were sitting side by side on the same Hashnode blog, and they just didn't belong together.</p>
<p>My detailed, meaningful articles deserve a clean space. And my journals, well, anyone who wants to follow the day-to-day grind can read those separately. Mixing them together makes neither look good. So I decided to split them.</p>
<h3>Hashnode: multiple blogs, multiple headaches</h3>
<p>The plan was straightforward. Create two separate blogs on Hashnode and map my subdomains:</p>
<ul>
<li><p><code>blog.ramankarki.dev</code> → the real, polished articles</p>
</li>
<li><p><code>journal.ramankarki.dev</code> → the daily dev diary</p>
</li>
</ul>
<p>The blog site came up fine. The journal site, though? Nothing. It just wouldn't work properly. My best guess is there's a bug in Hashnode when you try to run multiple blogs under a single account. I couldn't pin it down exactly, but something is clearly broken there.</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/60d9795b703d372ea06c7378/f7a5077b-b14d-40be-8a32-177a308c9449.png" alt="" style="display:block;margin:0 auto" />

<p>On top of that, I ran into 3 more annoying issues on the platform:</p>
<p><strong>Bug #1 — Publication switch not working.</strong> There's supposed to be a way to switch between multiple blog publication, but clicking it did nothing for me. Posts just stayed as-is regardless of what I selected.</p>
<p><strong>Bug #2 — Date/time update broken.</strong> I tried to correct the publish date on a few journal entries. The date picker lets you set the date and time separately — I'd pick, say, February 18 at 9 PM — but after hitting update, it would save as February 18 at 12 AM. I confirmed this by right-clicking and checking the actual post data.</p>
<p><strong>Bug #3 — Inconsistent dates across views.</strong> There's also a mismatch between how the date appears on the homepage vs inside the article itself. One article showed February 18, 2026 on the listing, but February 17, 2026 when you actually opened it. I don't know what's going on there.</p>
<hr />
<h3>Looked at alternatives — Dev.to and Notion</h3>
<p>At this point I took a detour and looked at other platforms. Dev.to was the first one I checked, but it doesn't support custom domains and you're fully locked into their platform. That was a no-go — I want to own my content and my URLs.</p>
<p>Notion was next. You can technically turn Notion pages into a public-facing site, but the customization options feel too limited. I need full control over the UI and the ability to serve the journal and articles from clearly separate paths so readers don't get lost jumping between them.</p>
<p>Neither was the right fit.</p>
<hr />
<h3>Rethinking the whole approach: build a unified portfolio</h3>
<p>Here's where my thinking shifted. I originally wanted a super minimal portfolio — just a single page with my name, my job title, and links out to my blog and whatever else. Quick, clean, done.</p>
<p>But if I'm going to have two separate content sections (detailed blog posts and journals), making visitors bounce between two different sites creates a bad experience. Every time someone clicks a link, they're context-switching to a completely different domain.</p>
<p>The cleaner solution is to build a single platform that has everything in one place: a projects section, a blog section, and a journal section. All under one roof.</p>
<p>I've been resisting building a custom portfolio because it felt like time that wasn't directly productive. But now there's an actual reason for it beyond aesthetics. The plan is to get through a web development with AI course first so I can leverage that to build the site faster, then actually build it properly.</p>
<hr />
<h3>LeetCode #15 — Three Sum</h3>
<p>Later in the day I worked through LeetCode problem 15, Three Sum. The problem asks you to find all unique triplets in an array where the three numbers add up to zero, with no duplicate triplets in the result.</p>
<p>I'd solved a similar problem before — find a pair of numbers in a sorted array that sum to a target, using a two-pointer approach. Left pointer starts at index 0, right pointer starts at the last index, and you walk them inward based on whether the current sum is too high or too low.</p>
<p>Three Sum extends this by one dimension. The input isn't sorted, so first step is to sort it yourself. Then you loop over each element, fix it as the first number of the triplet, and run the two-pointer search on the rest of the array to find the other two.</p>
<p>The deduplication part is where things got interesting. To avoid returning the same triplet twice, I tracked already-found triplets using a map. I'd represent each triplet as a sorted array joined into a string, then check if that string already existed in the map before adding it.</p>
<p>Here's the rough flow:</p>
<pre><code class="language-plaintext">sort the input array

for each number (fixed as first of triplet):
    set left = next index, right = last index
    
    while left &lt; right:
        sum = fixed + nums[left] + nums[right]
        
        if sum == 0:
            build triplet string (sorted, joined)
            if not in map:
                add to output, store in map
            move both pointers inward
        
        elif sum &gt; 0:
            right--
        
        else:
            left++
</code></pre>
<p>I hit an infinite loop bug early on because I was checking for duplicates before checking if the sum equalled zero. The loop would find a sum of zero, see the triplet already in the map, and then just... break without moving the pointers. So it'd re-check the same indices over and over.</p>
<p>The fix was simple once I saw it: check if sum equals zero first, then check the map. If it's a duplicate, still increment and decrement the pointers before continuing. That way the loop always makes progress.</p>
<pre><code class="language-typescript">function threeSum(nums: number[]): number[][] {
    nums.sort((a,b) =&gt; a - b)
    const map = new Map()
    const output = []

    for (let i = 0; i &lt; nums.length; i++) {
        let left = i + 1;
        let right = nums.length - 1
        const num = nums[i]
        while (left &lt; right) {
            const sum = num + nums[left] + nums[right]
            if (sum === 0) {
                const triplet = [num, nums[left], nums[right]]
                const tripletKey = triplet.sort((a, b) =&gt; a - b).join('')
                if (map.has(tripletKey)) {
                    left++
                    right--
                    continue
                }
                output.push(triplet)
                map.set(tripletKey, true)
            }
            else if (sum &gt; 0) right--
            else left++
        }
    }

    return output
};
</code></pre>
<hr />
<h3>Day summary</h3>
<p>A day that started as a quick portfolio update turned into a platform architecture decision and a bug-hunting session. Hashnode's multi-blog support has some real rough edges. Might end up building my own thing sooner than expected. And Three Sum is solved — that infinite loop was a good reminder that control flow bugs hide in the order you check conditions, not just the conditions themselves.</p>
]]></content:encoded></item><item><title><![CDATA[Journal: Job screening, portfolio shipped, LeetCode unblocked, hexagonal arch explored]]></title><description><![CDATA[This article is part of my journal. Read more
Morning — Woke Up Late, First Screening Done
Started the day a bit slow — had a headache, woke up late. Despite that, I had my first screening interview w]]></description><link>https://blog.ramankarki.dev/journal-job-screening-portfolio-shipped-leetcode-unblocked-hexagonal-arch-explored</link><guid isPermaLink="true">https://blog.ramankarki.dev/journal-job-screening-portfolio-shipped-leetcode-unblocked-hexagonal-arch-explored</guid><dc:creator><![CDATA[Raman Karki]]></dc:creator><pubDate>Thu, 19 Feb 2026 18:15:00 GMT</pubDate><content:encoded><![CDATA[<p>This article is part of my journal. <a href="https://blog.ramankarki.dev/series/journal">Read more</a></p>
<h2>Morning — Woke Up Late, First Screening Done</h2>
<p>Started the day a bit slow — had a headache, woke up late. Despite that, I had my first screening interview with Progressive Lab Company, one of the companies I recently applied to. They asked around four or five questions. The first one was just introducing myself, which is always straightforward. The rest of the questions were mostly centered around AI — what my opinions are, and how AI is currently impacting software development. I gave my thoughts and that was it.</p>
<h2>Building My Portfolio Site</h2>
<p>After the interview, I remembered I still hadn't built my personal website. So I started brainstorming.</p>
<p>My idea was simple: a <strong>minimal single-page, single-screen website</strong> that just reflects who I am and what I do. Nothing bloated. Just my name, my job title, and links — GitHub, LinkedIn, Instagram, my blog, and my resume URL. That's it. And something to make it feel alive, like a 3D animation or an aesthetic theme.</p>
<p>I didn't want to build the whole thing from scratch, so I started brainstorming with Claude AI. I shared my idea, got a few theme suggestions back, and eventually landed on a <strong>space like theme</strong>. I liked it. Felt right.</p>
<p>From there, I gave Claude my latest resume and it helped me pull together the portfolio site. Once I was happy with it, I deployed it and connected my own domain. <a href="https://ramankarki.dev/">The site is live now</a>.</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/60d9795b703d372ea06c7378/3218c25e-ca4e-4a7c-87d0-0326f7c54280.png" alt="" style="display:block;margin:0 auto" />

<p>I still feel like it could use something more — maybe an interactive 3D animation, like a rotating globe with my tech stack on it, or something you can play with using the mouse. But for now, it's minimal, it's live, and I'm mostly satisfied with where it is.</p>
<h2>Later — LeetCode #11: Container With Most Water (Medium)</h2>
<p>Switched gears and picked up LeetCode problem #11 — <strong>Container With Most Water</strong>.</p>
<p>The problem gives you an array of integers where each value represents the height of a vertical line. You need to find two lines that, together with the x-axis, form a container that can hold the most water. Return that maximum amount.</p>
<p>My initial thinking: use the <strong>two-pointer pattern</strong>. Start with one pointer at the left and one at the right, loop while left is less than right, find the minimum height between the two, multiply it by the distance between the indices, and track the maximum.</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/60d9795b703d372ea06c7378/b5352073-d9dc-4e86-898d-2e45da103e90.svg" alt="" style="display:block;margin:0 auto" />

<p>The part I got stuck on was: after calculating the area, which index do I move? If I move both at once, I might skip a combination that gives the maximum water. For example, if I jump from index 0 to index 1 on both sides simultaneously, I might miss the best pair being index 0 and index 4.</p>
<p>After stepping back and thinking it through (had to revisit my earlier notes), the logic clicked: <strong>compare the two heights and increment the index of the smaller one.</strong> If the right height is greater, increment the left index. The reasoning is that since the smaller height is the limiting factor, there's no point keeping it — moving it gives us the only chance at finding something better.</p>
<pre><code class="language-typescript">function maxArea(height: number[]): number {
    let left = 0
    let right = height.length - 1
    let max = 0
    while (left &lt;= right) {
        const min = Math.min(height[left], height[right])
        const distance = right - left
        max = Math.max(max, distance * min)
        if (height[left] &gt; height[right]) right--
        else left++
    }
    return max
};
</code></pre>
<p>Once I implemented that final piece of logic, all the test cases passed. Felt good.</p>
<h2>Reading About Hexagonal Architecture</h2>
<p>I went through a Medium article about why senior developers prefer <strong>hexagonal architecture</strong> over the traditional layered architecture. It turned into a pretty solid reading session.</p>
<p><strong>Layered architecture</strong> is what most people are familiar with — and honestly what I've been using in most of the project with NestJS. You've got your controllers, your service files with the business logic, and your repository files for data access. Clean enough, but it has a real problem: <strong>tight coupling between layers</strong>. If something changes in the controller or service or data access layer, the ripple effect can spread through the whole thing.</p>
<p><strong>Hexagonal architecture</strong> (also called ports and adapters) handles this differently. The core domain logic sits in the middle and almost never changes. Around it are <strong>ports</strong> — think of these as interfaces in TypeScript. And then you have <strong>adapters</strong> that implement those interfaces. Your repository file is an adapter. Your REST API controller is an adapter on the other side.</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/60d9795b703d372ea06c7378/e56d6722-d130-4f45-acf0-b085ffaf34bb.svg" alt="" style="display:block;margin:0 auto" />

<p>So if your database changes, or you switch to a different third-party API, you just update the adapter. The core logic stays untouched. The article called this <strong>preserving the blast radius</strong> — changes in one place don't cascade everywhere else.</p>
<p>The article made a good point about <em>when</em> this architecture shines. In something like banking, the core business logic almost never changes. But the technology around it keeps evolving. Hexagonal architecture is a natural fit there.</p>
<p>Netflix came up as another example. Their UI is constantly shifting — smart TVs, mobile, web, different devices. Their database infrastructure also changes. But the core of what Netflix does — stream content — stays the same. Hexagonal architecture lets the outer layers change freely while the middle holds steady.</p>
<p>Translating this into NestJS terms: the use case files act like the service layer, the adapters map to repository and utility files, and the controllers serve as the REST API-facing adapters.</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/60d9795b703d372ea06c7378/c09c43e8-e9a1-476b-ae0b-a04d8b9fc117.svg" alt="" style="display:block;margin:0 auto" />

<p>It was a good read. Not switching everything over tomorrow, but it's the kind of pattern worth keeping in mind as projects grow.</p>
<hr />
<p><em>That was the day. Interview done, portfolio live, LeetCode solved, architecture concepts absorbed.</em></p>
]]></content:encoded></item><item><title><![CDATA[Journal: Valid Palindrome, Two Sum II, CQRS vs Read Replica]]></title><description><![CDATA[This article is part of my journal. Read more
LeetCode 125 — Valid Palindrome
Today I worked on LeetCode 125, the Valid Palindrome problem. The task is to check if a string is a palindrome after conve]]></description><link>https://blog.ramankarki.dev/dev-log-valid-palindrome-two-sum-ii-cqrs-vs-read-replica</link><guid isPermaLink="true">https://blog.ramankarki.dev/dev-log-valid-palindrome-two-sum-ii-cqrs-vs-read-replica</guid><dc:creator><![CDATA[Raman Karki]]></dc:creator><pubDate>Wed, 18 Feb 2026 18:15:00 GMT</pubDate><content:encoded><![CDATA[<p>This article is part of my journal. <a href="https://blog.ramankarki.dev/series/journal">Read more</a></p>
<h2>LeetCode 125 — Valid Palindrome</h2>
<p>Today I worked on LeetCode 125, the Valid Palindrome problem. The task is to check if a string is a palindrome after converting all uppercase letters to lowercase and keeping only alphanumeric characters.</p>
<p>My first instinct was to reverse the string and compare, but I quickly realized that approach would create problems because of special characters mixed in between. So instead, I decided to initialize a variable to keep track of the valid alphanumeric characters in straight order, then reverse it and check if both are equal.</p>
<p>I looped over every character, lowercased it first, checked if it was alphanumeric using a regex range (0–9 and a–z), and only then appended it to my string variable. The code was working. Then I moved the lowercase step upfront — before the loop — that made the code cleaner and a bit faster.</p>
<p>It was working, but only 10% of users ranked below me, which told me my solution was not optimal. One edge case tripped me up: I was using <code>\w</code> in my regex which includes underscores. I fixed that by manually defining the alphanumeric range as <code>0-9</code> and <code>a-z</code>. Since I had already lowercased the string, I didn't need to include capital letters separately. After that fix, it passed all test cases.</p>
<p>Here is the final code</p>
<pre><code class="language-typescript">function isPalindrome(s: string): boolean {
    let reverseStr = ''
    let str = ''
    for (let char of s) {
        const lowerCase = char.toLowerCase()
        if (/[0-9a-z]/.test(lowerCase)) {
            str += lowerCase
            reverseStr = lowerCase + reverseStr
        }
    }

    return str === reverseStr
};
</code></pre>
<h3>Optimizing the Approach</h3>
<p>Rather than creating a reversed copy of the string, I explored a two-pointer approach. The idea: lowercase the whole string once before the loop, replace all non-alphanumeric characters with an empty string, then use a <code>left</code> pointer starting at 0 and a <code>right</code> pointer starting at the last index. Loop while <code>left &lt; right</code>, and if the leftmost character does not equal the rightmost character, return false. Otherwise, increment left and decrement right.</p>
<p>One thing I learned along the way — in regex, using a caret (<code>^</code>) inside brackets means "does not match this range." That made it easy to strip out non-alphanumeric characters in one line.</p>
<p>I ran it and the runtime percentage jumped around — 20% one run, higher another. I concluded that comparing runtime percentages on LeetCode is not very reliable since results vary each run.</p>
<p>Here is the final code</p>
<pre><code class="language-typescript">function isPalindrome(s: string): boolean {
    s = s.toLowerCase().replace(/[^0-9a-z]/g, '')

    let left = 0
    let right = s.length - 1
    while (left &lt; right) {
        if (s[left] != s[right]) return false
        left++
        right--
    }
    return true
};
</code></pre>
<hr />
<h2>LeetCode 167 — Two Sum II (Input Array Is Sorted)</h2>
<p>Next I moved on to LeetCode 167. Given a sorted integer array in non-decreasing order, I needed to find two numbers that add up to a specific target and return their indices.</p>
<p>I used the two-pointer pattern. Left starts at index 0, right starts at the last index (<code>numbers.length - 1</code>). I loop while <code>left &lt; right</code>, compute the sum of the two pointed values, and check against the target. If the sum equals the target, I return the indices. If the sum is greater than the target, I decrement right. If the sum is smaller, I increment left.</p>
<p>My first test case failed because I forgot the question uses 1-based indexing. The answer needed to be <code>[1, 2]</code> instead of <code>[0, 1]</code>. Once I added 1 to both indices before returning, it passed.</p>
<p>Here is the final code</p>
<pre><code class="language-typescript">function twoSum(numbers: number[], target: number): number[] {
    let left = 0
    let right = numbers.length - 1

    while (left &lt; right) {
        const sum = numbers[left] + numbers[right]
        if (sum === target) return [left + 1, right + 1]
        else if (sum &gt; target) {
            right--
        } else {
            left++
        }
    }
    return []
};
</code></pre>
<hr />
<h2>Career Goals &amp; Personal Project</h2>
<p>I've been thinking about switching companies and targeting a top-tier company in Nepal. To prepare, I'm focused on three areas: refreshing my memory on DSA, design patterns, and advanced system design for a senior position.</p>
<p>I also realized I don't have a solid personal project to make an impression, so I've decided to build one. The idea is a <strong>budget management system</strong> — a combination of Splitwise and a money tracker app, so users can track both personal expenses and group expenses in the same place. I'm planning to use PostgreSQL as the database since I haven't used SQL based database in real world project. This project will give me the confidence that I need to get my carrier into the next level.</p>
<hr />
<h2>AI &amp; Generative AI Exploration</h2>
<p>I want to gain more knowledge in AI, so I've been going through AI content on YouTube. First priority is setting up a proper development environment for coding to improve productivity.</p>
<p>I also came across a repository from Karpathy — one of the founders of OpenAI — called <strong>microGPT</strong>. It shows how the core logic inside GenAI works, and the entire core codebase is only 200 lines of code. I'm going to dig into it to understand how AI works internally and strengthen my knowledge of generative AI.</p>
<p>I also found a video by Alex Jinskind where he talks about Claude Code and agentic coding — definitely going to watch that too.</p>
<hr />
<h2>System Design — CQRS vs Read Replica</h2>
<p>I watched a video by Core Opinion that cleared up a confusion I didn't even know I had: <strong>read replica is not the same as CQRS</strong>.</p>
<p><strong>CQRS (Command Query Responsibility Segregation)</strong> is a code-level pattern. When a feature involves expensive reads — say, multiple SQL joins — you create a separate read table where data is de-normalized and pre-computed. Write queries go to the original table. Read queries pull from the optimized read table. Many developers are probably already doing this without knowing it has a name.</p>
<p><strong>Read replica</strong>, on the other hand, is an infrastructure-level solution. You use it when you're hitting actual traffic and scaling issues at the database infrastructure level — not just slow queries in code.</p>
<p>The distinction is clearer now: CQRS is a code optimization, read replica is an infrastructure scaling strategy.</p>
<hr />
<p><em>End of day. Good progress on DSA, a clearer project direction, and a useful system design concept locked in.</em></p>
]]></content:encoded></item><item><title><![CDATA[Journal: Watch Me Struggle Through 4 LeetCode Problems]]></title><description><![CDATA[This article is part of my journal. Read more
Encode and Decode Strings (NeetCode)
Yesterday I started with a NeetCode problem: encode and decode strings. The idea was to take a list of strings, encod]]></description><link>https://blog.ramankarki.dev/watch-me-struggle-through-4-leetcode-problems</link><guid isPermaLink="true">https://blog.ramankarki.dev/watch-me-struggle-through-4-leetcode-problems</guid><dc:creator><![CDATA[Raman Karki]]></dc:creator><pubDate>Tue, 17 Feb 2026 18:15:00 GMT</pubDate><content:encoded><![CDATA[<p>This article is part of my journal. <a href="https://blog.ramankarki.dev/series/journal">Read more</a></p>
<h2>Encode and Decode Strings (NeetCode)</h2>
<p>Yesterday I started with a NeetCode problem: encode and decode strings. The idea was to take a list of strings, encode them into a single string, send that over the network, then decode it back to the original list.</p>
<p>The trick was figuring out how to tell where one string ended and the next began. What I landed on was a simple format: for each string, prefix it with its length followed by a special character as a separator — so something like <code>5:hello3:hey</code>. Concatenate all of them together and you had your encoded string.</p>
<p>Decoding worked by scanning for the special character. Whatever came before it was the length. I used that length to slice out the original string, then moved the pointer forward and repeated until everything was recovered.</p>
<p>Here is the final code</p>
<pre><code class="language-typescript">class Solution {
    /**
     * @param {string[]} strs
     * @returns {string}
     */
    encode(strs) {
        return strs.map(str =&gt; `\({str.length}:\){str}`).join('')
    }

    /**
     * @param {string} str
     * @returns {string[]}
     */
    decode(str) {
        const output = []
        let i = 0
        while (i &lt; str.length) {
            const delimiter = str.indexOf(':', i)
            const length = +str.slice(i, delimiter)
            output.push(str.slice(delimiter + 1, delimiter + 1 + length))
            i = delimiter + 1 + length
        }
        return output
    }
}
</code></pre>
<h2>Product of Array Except Self (LeetCode #238)</h2>
<p>Next up was LeetCode 238. The problem: given an array of numbers, return a new array where each index held the product of all the other numbers — no division allowed, O(n) time.</p>
<p>The solution used the prefix sum pattern, but with multiplication. I looped from start to end keeping a running left-side product, and assigned it to each index. Then did the same from right to left with a running right-side product, multiplying into what was already there.</p>
<p>I also worked out a trick to handle both directions in a single loop — using <code>length - currentIndex - 1</code> to get the mirrored index, so I could update from both ends simultaneously without two separate passes.</p>
<p>The key insight: the product of everything except the current element was just the product of everything to its left multiplied by everything to its right. Prefix products gave me exactly that.</p>
<p>Here is the final code</p>
<pre><code class="language-typescript">function productExceptSelf(nums: number[]): number[] {
    const ans = new Array(nums.length).fill(1)
    let leftProduct = 1
    let rightProduct = 1
    for (let i = 0; i &lt; nums.length; i++) {
        ans[i] *= leftProduct
        leftProduct *= nums[i]

        const rightI = nums.length - i - 1
        ans[rightI] *= rightProduct
        rightProduct *= nums[rightI]
    }
    return ans
};
</code></pre>
<h2>Valid Sudoku (LeetCode #36)</h2>
<p>Then I worked through LeetCode 36 — checking whether a Sudoku board was valid. Each row, column, and 3×3 box had to contain 1–9 with no repeats.</p>
<p>My approach was to initialize three 2D arrays — one for rows, one for columns, one for boxes — then loop through the grid with nested loops. If a cell was empty (marked as <code>.</code>) I skipped it. If it was a number, I subtracted 1 to get a zero-based index, then checked the corresponding slot in each tracking array. If it was already marked <code>true</code>, the board was invalid. Otherwise I marked it and moved on.</p>
<p>Rows and columns were straightforward. The tricky part was finding the correct box index. The formula I worked out:</p>
<pre><code class="language-plaintext">boxIndex = Math.floor(i / 3) * 3 + Math.floor(j / 3)
</code></pre>
<p>This took a while to reason through. Dividing the row index by 3 gave which box row I was in (0, 1, or 2). Multiplying by 3 scaled it so there was room for the column offset. Adding the column index divided by 3 gave the final box index from 0 to 8. I wrote a quick test loop to console log the output and verify it matched what I expected — and it clicked into place.</p>
<p>Here is the final code</p>
<pre><code class="language-typescript">function isValidSudoku(board: string[][]): boolean {
    const rows = Array.from({length: 9}, () =&gt; Array(9).fill(false))
    const cols = Array.from({length: 9}, () =&gt; Array(9).fill(false))
    const cube = Array.from({length: 9}, () =&gt; Array(9).fill(false))

    for (let i = 0; i &lt; 9; i++) {
        for (let j = 0; j &lt; 9; j++) {
            const value = board[i][j]
            if (value === '.') continue

            const index = +value - 1
            const boxIndex = Math.floor(i/3) * 3 + Math.floor(j / 3)
            if (rows[i][index] || cols[j][index] || cube[boxIndex][index]) return false
            rows[i][index] = cols[j][index] = cube[boxIndex][index] = true
        }
    }
    return true
};
</code></pre>
<h2>Longest Consecutive Sequence (LeetCode #128)</h2>
<p>The last problem of the day was LeetCode 128 — finding the longest consecutive sequence in an unsorted integer array. Had to run in O(n) time.</p>
<p>I converted the array to a Set to remove duplicates and allow O(1) lookups. Then looped through the set. For each number, I checked if <code>number - 1</code> existed. If it did, that number wasn't the start of a sequence — skip it. If it didn't exist, that number was the start. I began counting upward, kept incrementing and checking if the next number existed, tracking the count until the sequence broke. Then compared against the running max.</p>
<p>I caught a bug mid-implementation: I was looping over the original input array instead of the set. That meant doing redundant work on duplicate values. Once I switched to looping over the set, everything worked correctly.</p>
<p>Here is the final code</p>
<pre><code class="language-typescript">function longestConsecutive(nums: number[]): number {
    const set = new Set(nums)
    let longestSequence = 0
    for (let num of set) {
        if (!set.has(num - 1)) {
            let newLongest = 1
            while (set.has(num + newLongest)) {
                newLongest++
            }
            longestSequence = Math.max(longestSequence, newLongest)
        }
    }
    return longestSequence
};
</code></pre>
<hr />
<h2>Conclusion</h2>
<p>Four problems yesterday. Good mix of encoding tricks, array manipulation, grid logic, and set-based searching. The Sudoku box index formula was the most satisfying thing to work out.</p>
]]></content:encoded></item><item><title><![CDATA[How to render Notion pages content in React apps | Make your site content dynamic]]></title><description><![CDATA[Situation
I was working on a web project where most contents were static and were given to me by my client. Some pages were pretty plain and simple that could be written using markdown. But the problem was, my client frequently asked me to change tho...]]></description><link>https://blog.ramankarki.dev/how-to-render-notion-pages-content-in-react-apps-or-make-your-site-content-dynamic</link><guid isPermaLink="true">https://blog.ramankarki.dev/how-to-render-notion-pages-content-in-react-apps-or-make-your-site-content-dynamic</guid><category><![CDATA[React]]></category><category><![CDATA[markdown]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[full stack]]></category><category><![CDATA[cms]]></category><dc:creator><![CDATA[Raman Karki]]></dc:creator><pubDate>Wed, 13 Oct 2021 16:37:04 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1634142494651/3mekUIDoP.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="situation">Situation</h2>
<p>I was working on a web project where most contents were static and were given to me by my client. Some pages were pretty plain and simple that could be written using markdown. But the problem was, my client frequently asked me to change those static content and could be updated shortly again. So, I had to change those hard-coded contents frequently from React app, which was a bit boring.</p>
<p>I have been using <strong>Notion</strong> to keep my notes and documents for a long time. I wanted to use this tool like a <strong>CMS (Content Management System)</strong> to write those contents on the <strong>Notion</strong>, fetch contents using <strong>Notion API</strong>, and render them in my React app. By doing that, I could be free to frequently update my React code and push my code to GitHub.</p>
<p>I could hand over that <strong>Notion</strong> page, and they would have to write those contents themselves and change it whenever they want. Every time they change those contents, it would reflect in React app.</p>
<h3 id="quick-information-about-notionhttpsnotionso-if-you-are-new-to-this">💡 Quick information about <a target="_blank" href="https://notion.so">Notion</a> if you are new to this</h3>
<blockquote>
<p>The <strong>Notion</strong> is an application that provides components such as notes, databases, kanban boards, wikis, calendars, and reminders. Users can connect these components to create their systems for knowledge management, note-taking, data management, project management, among others. It's the all-in-one workspace for you and your team.</p>
</blockquote>
<p>So I started reading the <strong>Notion API</strong> documentation, and I tried using it. But the problem is, the <strong>API</strong> is in the <strong>Beta version</strong>, and the <strong>CORS (Cross Origin Resource Sharing)</strong> wasn't enabled either.</p>
<p>I started looking for alternate solutions, and I finally found one. I wasn't expecting this solution to be like this. But in the end, it worked, and my problem got solved.</p>
<h2 id="lets-render-our-notion-pages-in-our-react-apps">Let's render our <strong>Notion</strong> pages in our React apps. 🤩🤩</h2>
<h3 id="create-react-project">Create React project</h3>
<p>I have used <strong>Vite</strong> to create my React project instead of <strong>CRA (Create React App)</strong>. Learn <a target="_blank" href="https://ramankarki.hashnode.dev/react-project-setup-with-vite-for-faster-development-or-blazing-fast-server-startup-and-updates">more</a> about Vite.</p>
<h3 id="install-react-notion-npm-package">Install <code>react-notion</code> npm package</h3>
<pre><code class="lang-bash">npm install react-notion
</code></pre>
<p>A React renderer for <strong>Notion</strong> pages. We can use the <strong>Notion</strong> as a <strong>CMS (Content Management System) </strong>for our blog, documentation or personal site.</p>
<h3 id="create-a-notion-account-and-a-page-on-the-notion">Create a Notion account and a page on the Notion</h3>
<p>After you signup on the Notion, create a <strong>New page</strong> from the bottom-left of your screen and add title whatever you want.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1634135707244/p30aPETy1.png" alt="How to render Notion pages in React apps _ Make your site content dynamic.png" /></p>
<h3 id="make-your-notion-page-from-private-to-public">Make your <strong>Notion</strong> page from private to public</h3>
<p>It is an important step for fetching page content from our React app.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1634136165931/YYy1hWW_N.png" alt="How to render Notion pages in React apps _ Make your site content dynamic.png" /></p>
<h3 id="add-some-content">Add some content</h3>
<p>Add anything you want like paragraphs, images, lists, etc. We will fetch those content and render in our React app.</p>
<h3 id="copy-the-page-uuid-universally-unique-identity">Copy the page <strong>UUID (Universally Unique Identity)</strong></h3>
<p>It is required while making <strong>GET</strong> request for our page content. It should be at the end of your page <strong>URL</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1634138881593/KlgTpOl1i.png" alt="How to render Notion pages in React apps _ Make your site content dynamic.png" /></p>
<h3 id="change-your-appjsx-code">Change your <code>App.jsx</code> code</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-comment">// We installed earlier. This will render content data fetched from the Notion.</span>
<span class="hljs-keyword">import</span> { NotionRenderer } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-notion'</span>;

<span class="hljs-comment">// For styling markdown content</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'react-notion/src/styles.css'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'./App.css'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [data, setData] = useState({});

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// notion-api-worker</span>
    fetch(
      <span class="hljs-string">'https://notion-api.splitbee.io/v1/page/&lt;your page UUID&gt;'</span>
    )
      .then(<span class="hljs-function">(<span class="hljs-params">res</span>) =&gt;</span> res.json())
      .then(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> setData(data));
  }, []);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>
        How to render Notion pages in React apps | Make your site content
        dynamic
      <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

      {/* Mount NotionRenderer and pass in data to render */}
      <span class="hljs-tag">&lt;<span class="hljs-name">NotionRenderer</span> <span class="hljs-attr">blockMap</span>=<span class="hljs-string">{data}</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>We have used <a target="_blank" href="https://github.com/splitbee/notion-api-worker">notion-api-worker</a> that has <strong>CORS (Cross Origin Resource Sharing)</strong> enabled to fetch the <strong>Notion</strong> page content. And <code>react-notion</code> npm package to render those fetched data into our React app.</p>
<p><a target="_blank" href="https://github.com/splitbee/notion-api-worker"><code>notion-api-worker</code></a> is a <strong>serverless</strong> wrapper for the private <strong>Notion API</strong>. It provides fast and easy access to your <strong>Notion</strong> content. Ideal to make <strong>Notion</strong> your <strong>CMS</strong>.</p>
<h3 id="change-your-appcss-code">Change your <code>App.css</code> code</h3>
<p>Just for basic styling.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.App</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">700px</span>;
  <span class="hljs-attribute">margin</span>: auto;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">1.5rem</span>;
}

<span class="hljs-selector-tag">h1</span> {
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">2rem</span> <span class="hljs-number">0</span>;
}
</code></pre>
<h3 id="start-your-development-server">Start your development server</h3>
<pre><code><span class="hljs-comment">// if you used CRA</span>
<span class="hljs-selector-tag">npm</span> <span class="hljs-selector-tag">start</span>

<span class="hljs-comment">// if you used Vite</span>
<span class="hljs-selector-tag">npm</span> <span class="hljs-selector-tag">run</span> <span class="hljs-selector-tag">dev</span>
</code></pre><p>You should have a page running that looks like this,</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1634140808747/Bbn1c7K9k.png" alt="How to render Notion pages in React apps _ Make your site content dynamic.png" /></p>
<h3 id="update-your-content-on-the-notion">Update your content on the Notion</h3>
<p>Try updating your <strong>Notion</strong> page content, save it, and refresh your browser tab once or twice. You should have updated content on your React app.</p>
<h2 id="conclusion">Conclusion</h2>
<p>So, now we have the <strong>Notion</strong> as our <strong>CMS (Content Management System)</strong>. And our content is rendering on our React app dynamically. Let me know if I missed something. </p>
<p>Thank you for reading my blog/article. ❤️❤️</p>
]]></content:encoded></item><item><title><![CDATA[A better way to structure your React & Redux projects.]]></title><description><![CDATA[Situation
While learning React, we all started our journey with this kind of file structure.
test
├── README.md
├── node_modules
├── package-lock.json
├── package.json
├── public
│   ├── favicon.ico
│   ├── index.html
│   ├── logo192.png
│   ├── logo...]]></description><link>https://blog.ramankarki.dev/a-better-way-to-structure-your-react-and-redux-projects</link><guid isPermaLink="true">https://blog.ramankarki.dev/a-better-way-to-structure-your-react-and-redux-projects</guid><category><![CDATA[React]]></category><category><![CDATA[Redux]]></category><category><![CDATA[files]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[best practices]]></category><dc:creator><![CDATA[Raman Karki]]></dc:creator><pubDate>Fri, 08 Oct 2021 05:03:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1633670181917/fP8S1Cmal.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="situation">Situation</h2>
<p>While learning React, we all started our journey with this kind of file structure.</p>
<pre><code><span class="hljs-selector-tag">test</span>
├── <span class="hljs-selector-tag">README</span><span class="hljs-selector-class">.md</span>
├── <span class="hljs-selector-tag">node_modules</span>
├── <span class="hljs-selector-tag">package-lock</span><span class="hljs-selector-class">.json</span>
├── <span class="hljs-selector-tag">package</span><span class="hljs-selector-class">.json</span>
├── <span class="hljs-selector-tag">public</span>
│   ├── <span class="hljs-selector-tag">favicon</span><span class="hljs-selector-class">.ico</span>
│   ├── <span class="hljs-selector-tag">index</span><span class="hljs-selector-class">.html</span>
│   ├── <span class="hljs-selector-tag">logo192</span><span class="hljs-selector-class">.png</span>
│   ├── <span class="hljs-selector-tag">logo512</span><span class="hljs-selector-class">.png</span>
│   ├── <span class="hljs-selector-tag">manifest</span><span class="hljs-selector-class">.json</span>
│   └── <span class="hljs-selector-tag">robots</span><span class="hljs-selector-class">.txt</span>
└── <span class="hljs-selector-tag">src</span>
    ├── <span class="hljs-selector-tag">App</span><span class="hljs-selector-class">.css</span>
    ├── <span class="hljs-selector-tag">App</span><span class="hljs-selector-class">.js</span>
    ├── <span class="hljs-selector-tag">App</span><span class="hljs-selector-class">.test</span><span class="hljs-selector-class">.js</span>
    ├── <span class="hljs-selector-tag">actions</span>
    │   ├── <span class="hljs-selector-tag">action1</span><span class="hljs-selector-class">.js</span>
    │   └── <span class="hljs-selector-tag">action2</span><span class="hljs-selector-class">.js</span>
    ├── <span class="hljs-selector-tag">components</span>
    │   ├── <span class="hljs-selector-tag">Contact</span>
    │   │   └── <span class="hljs-selector-tag">index</span><span class="hljs-selector-class">.jsx</span>
    │   └── <span class="hljs-selector-tag">Home</span>
    │       └── <span class="hljs-selector-tag">index</span><span class="hljs-selector-class">.jsx</span>
    ├── <span class="hljs-selector-tag">index</span><span class="hljs-selector-class">.css</span>
    ├── <span class="hljs-selector-tag">index</span><span class="hljs-selector-class">.js</span>
    ├── <span class="hljs-selector-tag">logo</span><span class="hljs-selector-class">.svg</span>
    ├── <span class="hljs-selector-tag">reducers</span>
    │   └── <span class="hljs-selector-tag">index</span><span class="hljs-selector-class">.js</span>
    ├── <span class="hljs-selector-tag">reportWebVitals</span><span class="hljs-selector-class">.js</span>
    └── <span class="hljs-selector-tag">setupTests</span><span class="hljs-selector-class">.js</span>
</code></pre><p>It could be used for small projects. But it can create a problem for large-scale projects to organize files and make re-usable components. Every component can't be kept in a single <code>components</code> folder. It will be hard for everyone to search for several files and follow the <strong>DRY (Do Not Repeat)</strong> principle. I tried multiple ways to organize my file structure for my React projects, and here is what I came up with.</p>
<h2 id="a-better-way-to-structure-your-react-and-redux-projects">A better way to structure your React &amp; Redux projects.</h2>
<p>We will create PWA (Progressive Web App) with CRA (Create React App) template. <a target="_blank" href="https://create-react-app.dev/docs/making-a-progressive-web-app/">Read more</a></p>
<pre><code class="lang-bash">npx create-react-app my-app --template cra-template-pwa
</code></pre>
<p><a target="_blank" href="https://github.com/ramankarki/react-project-structure">Here</a> is my boilerplate for our final file structure. You will probably have to look over the code while reading this article.</p>
<p>Let's see an overview of our final file structure. And then, we will go through each file and folder in detail.</p>
<pre><code><span class="hljs-selector-tag">react-project-structure</span>
├── <span class="hljs-selector-tag">package-lock</span><span class="hljs-selector-class">.json</span>
├── <span class="hljs-selector-tag">package</span><span class="hljs-selector-class">.json</span>
├── <span class="hljs-selector-tag">public</span>
│   ├── <span class="hljs-selector-tag">assets</span>
│   │   └── <span class="hljs-selector-tag">code</span><span class="hljs-selector-class">.jpg</span>
│   ├── <span class="hljs-selector-tag">favicon</span><span class="hljs-selector-class">.ico</span>
│   ├── <span class="hljs-selector-tag">index</span><span class="hljs-selector-class">.html</span>
│   ├── <span class="hljs-selector-tag">logo192</span><span class="hljs-selector-class">.png</span>
│   ├── <span class="hljs-selector-tag">logo512</span><span class="hljs-selector-class">.png</span>
│   ├── <span class="hljs-selector-tag">manifest</span><span class="hljs-selector-class">.json</span>
│   └── <span class="hljs-selector-tag">robots</span><span class="hljs-selector-class">.txt</span>
└── <span class="hljs-selector-tag">src</span>
    ├── <span class="hljs-selector-tag">App</span><span class="hljs-selector-class">.js</span>
    ├── <span class="hljs-selector-tag">App</span><span class="hljs-selector-class">.scss</span>
    ├── <span class="hljs-selector-tag">Routes</span>
    │   ├── <span class="hljs-selector-tag">lazyPages</span><span class="hljs-selector-class">.js</span>
    │   ├── <span class="hljs-selector-tag">PageWrapper</span><span class="hljs-selector-class">.jsx</span>
    │   ├── <span class="hljs-selector-tag">constants</span><span class="hljs-selector-class">.js</span>
    │   ├── <span class="hljs-selector-tag">index</span><span class="hljs-selector-class">.jsx</span>
    │   ├── <span class="hljs-selector-tag">routes</span><span class="hljs-selector-class">.js</span>
    │   └── <span class="hljs-selector-tag">routesHelper</span><span class="hljs-selector-class">.js</span>
    ├── _<span class="hljs-selector-tag">variables</span><span class="hljs-selector-class">.scss</span>
    ├── <span class="hljs-selector-tag">actions</span>
    │   ├── <span class="hljs-selector-tag">constants</span><span class="hljs-selector-class">.js</span>
    │   ├── <span class="hljs-selector-tag">helper</span><span class="hljs-selector-class">.js</span>
    │   ├── <span class="hljs-selector-tag">onDelete</span><span class="hljs-selector-class">.js</span>
    │   ├── <span class="hljs-selector-tag">onGet</span><span class="hljs-selector-class">.js</span>
    │   ├── <span class="hljs-selector-tag">onPatch</span><span class="hljs-selector-class">.js</span>
    │   └── <span class="hljs-selector-tag">onPost</span><span class="hljs-selector-class">.js</span>
    ├── <span class="hljs-selector-tag">appState</span>
    │   ├── <span class="hljs-selector-tag">auth</span><span class="hljs-selector-class">.js</span>
    │   ├── <span class="hljs-selector-tag">index</span><span class="hljs-selector-class">.js</span>
    │   └── <span class="hljs-selector-tag">user</span><span class="hljs-selector-class">.js</span>
    ├── <span class="hljs-selector-tag">components</span>
    │   ├── <span class="hljs-selector-tag">ErrorBoundary</span>
    │   │   ├── <span class="hljs-selector-tag">index</span><span class="hljs-selector-class">.jsx</span>
    │   │   └── <span class="hljs-selector-tag">index</span><span class="hljs-selector-class">.scss</span>
    │   └── <span class="hljs-selector-tag">PageLoadingSpinner</span>
    │       ├── <span class="hljs-selector-tag">index</span><span class="hljs-selector-class">.jsx</span>
    │       └── <span class="hljs-selector-tag">index</span><span class="hljs-selector-class">.scss</span>
    ├── <span class="hljs-selector-tag">configureStore</span><span class="hljs-selector-class">.js</span>
    ├── <span class="hljs-selector-tag">index</span><span class="hljs-selector-class">.js</span>
    ├── <span class="hljs-selector-tag">pages</span>
    │   ├── <span class="hljs-selector-tag">Dashboard</span>
    │   │   └── <span class="hljs-selector-tag">index</span><span class="hljs-selector-class">.jsx</span>
    │   ├── <span class="hljs-selector-tag">Home</span>
    │   │   └── <span class="hljs-selector-tag">index</span><span class="hljs-selector-class">.jsx</span>
    │   ├── <span class="hljs-selector-tag">Login</span>
    │   │   └── <span class="hljs-selector-tag">index</span><span class="hljs-selector-class">.jsx</span>
    │   ├── <span class="hljs-selector-tag">PageNotFound</span>
    │   │   └── <span class="hljs-selector-tag">index</span><span class="hljs-selector-class">.jsx</span>
    │   └── <span class="hljs-selector-tag">Signup</span>
    │       └── <span class="hljs-selector-tag">index</span><span class="hljs-selector-class">.jsx</span>
    ├── <span class="hljs-selector-tag">reducers</span>
    │   └── <span class="hljs-selector-tag">HOFreducer</span><span class="hljs-selector-class">.js</span>
    ├── <span class="hljs-selector-tag">service-worker</span><span class="hljs-selector-class">.js</span>
    ├── <span class="hljs-selector-tag">serviceWorkerRegistration</span><span class="hljs-selector-class">.js</span>
    ├── <span class="hljs-selector-tag">templates</span>
    │   ├── <span class="hljs-selector-tag">Footer</span>
    │   │   └── <span class="hljs-selector-tag">index</span><span class="hljs-selector-class">.jsx</span>
    │   ├── <span class="hljs-selector-tag">Form</span>
    │   │   └── <span class="hljs-selector-tag">index</span><span class="hljs-selector-class">.jsx</span>
    │   └── <span class="hljs-selector-tag">Header</span>
    │       └── <span class="hljs-selector-tag">index</span><span class="hljs-selector-class">.jsx</span>
    └── <span class="hljs-selector-tag">utils</span>
        ├── <span class="hljs-selector-tag">API</span><span class="hljs-selector-class">.js</span>
        ├── <span class="hljs-selector-tag">actionLogger</span><span class="hljs-selector-class">.js</span>
        ├── <span class="hljs-selector-tag">dynamicReducers</span><span class="hljs-selector-class">.js</span>
        ├── <span class="hljs-selector-tag">getQueryObj</span><span class="hljs-selector-class">.js</span>
        └── <span class="hljs-selector-tag">monitorReducers</span><span class="hljs-selector-class">.js</span>
</code></pre><h2 id="public">public/</h2>
<p>Inside <code>public</code> folder we create <code>assets</code> folder and store static assets like images, fonts, etc. We also keep our <code>favicon.png</code>, <code>logo192.png</code>, <code>logo512.png</code>, <code>manifest.json</code>, <code>robots.txt</code>, etc. inside our <code>public</code> folder.</p>
<p>We setup our manifest to make <strong>PWA</strong> that looks something like this,</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"short_name"</span>: <span class="hljs-string">"Shortcut app name"</span>,
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"App name"</span>,
  <span class="hljs-attr">"icons"</span>: [
    {
      <span class="hljs-attr">"src"</span>: <span class="hljs-string">"favicon.png"</span>,
      <span class="hljs-attr">"sizes"</span>: <span class="hljs-string">"64x64 32x32 24x24 16x16"</span>,
      <span class="hljs-attr">"type"</span>: <span class="hljs-string">"image/x-icon"</span>
    },
    {
      <span class="hljs-attr">"src"</span>: <span class="hljs-string">"logo192.png"</span>,
      <span class="hljs-attr">"type"</span>: <span class="hljs-string">"image/png"</span>,
      <span class="hljs-attr">"sizes"</span>: <span class="hljs-string">"192x192"</span>
    },
    {
      <span class="hljs-attr">"src"</span>: <span class="hljs-string">"logo512.png"</span>,
      <span class="hljs-attr">"type"</span>: <span class="hljs-string">"image/png"</span>,
      <span class="hljs-attr">"sizes"</span>: <span class="hljs-string">"512x512"</span>
    }
  ],
  <span class="hljs-attr">"start_url"</span>: <span class="hljs-string">"./index.html"</span>,
  <span class="hljs-attr">"display"</span>: <span class="hljs-string">"standalone"</span>,
  <span class="hljs-attr">"theme_color"</span>: <span class="hljs-string">"#000000"</span>,
  <span class="hljs-attr">"background_color"</span>: <span class="hljs-string">"#ffffff"</span>
}
</code></pre>
<h2 id="srcroutes">src/Routes/</h2>
<p>We keep all our files and coding logic related to routes inside this folder. The crucial files here are <code>constants.js</code> and <code>routes.js</code> in this folder.</p>
<h3 id="constantsjs">constants.js</h3>
<p>We create path constants like this,</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> ROOT = <span class="hljs-string">'/'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> SIGNUP_PAGE = <span class="hljs-string">'/auth/signup'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> LOGIN_PAGE = <span class="hljs-string">'/auth/login'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> DASHBOARD_PAGE = <span class="hljs-string">'/dashboard'</span>;

<span class="hljs-comment">/*
  Add more path down
*/</span>

<span class="hljs-comment">/*
  Add more path up
*/</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> PAGE_NOT_FOUND = <span class="hljs-string">'/*'</span>;
</code></pre>
<p>These can be used in multiple components to redirect the user to another page or update history. We should do it in this way because if we hard code these path names and make any spelling mistakes, it can be hard for us to debug. But if we import this file and make a typo while using these constant variables, we can find that error more quickly.</p>
<h3 id="routesjs">routes.js</h3>
<p>we create route object like this,</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> {
  DASHBOARD_PAGE,
  LOGIN_PAGE,
  PAGE_NOT_FOUND,
  ROOT,
  SIGNUP_PAGE,
} <span class="hljs-keyword">from</span> <span class="hljs-string">'./constants'</span>;

<span class="hljs-keyword">const</span> routes = {
  [ROOT]: {
    <span class="hljs-attr">private</span>: <span class="hljs-literal">false</span>,
    <span class="hljs-attr">pageName</span>: <span class="hljs-string">'Home'</span>,
  },

  [SIGNUP_PAGE]: {
    <span class="hljs-attr">private</span>: <span class="hljs-literal">false</span>,
    <span class="hljs-attr">pageName</span>: <span class="hljs-string">'Signup'</span>,
  },

  [LOGIN_PAGE]: {
    <span class="hljs-attr">private</span>: <span class="hljs-literal">false</span>,
    <span class="hljs-attr">pageName</span>: <span class="hljs-string">'Login'</span>,
  },

  [DASHBOARD_PAGE]: {
    <span class="hljs-attr">private</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">pageName</span>: <span class="hljs-string">'Dashboard'</span>,
  },

  <span class="hljs-comment">// Add your routes here</span>

  [PAGE_NOT_FOUND]: {
    <span class="hljs-attr">private</span>: <span class="hljs-literal">false</span>,
    <span class="hljs-attr">pageName</span>: <span class="hljs-string">'PageNotFound'</span>,
  },
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> routes;
</code></pre>
<p>We export a routes object which has <code>key</code> as <code>path</code> and <code>value</code> as <code>Object</code>. The <code>Object</code> has two fields:</p>
<ul>
<li><code>private</code> - true if route is protected.</li>
<li><code>pageName</code> - name of the folder you created under <code>pages</code> while creating new page component.</li>
</ul>
<p>The point of creating <code>Routes</code> folder is to get rid of the code that looks something like this,</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { connect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-redux"</span>;
<span class="hljs-keyword">import</span> { HashRouter, Route } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;
<span class="hljs-keyword">import</span> {
  root,
  login,
  signup,
  forgotpassword,
  resetpassword,
  emailConfirmation,
  activateAccount,
  conversations,
  updateProfile,
  changePassword,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"../utils/Routes"</span>;

<span class="hljs-keyword">import</span> Signup <span class="hljs-keyword">from</span> <span class="hljs-string">"./AuthComponent/Signup"</span>;
<span class="hljs-keyword">import</span> Login <span class="hljs-keyword">from</span> <span class="hljs-string">"./AuthComponent/Login"</span>;
<span class="hljs-keyword">import</span> Forgotpassword <span class="hljs-keyword">from</span> <span class="hljs-string">"./AuthComponent/Forgotpassword"</span>;
<span class="hljs-keyword">import</span> Resetpassword <span class="hljs-keyword">from</span> <span class="hljs-string">"./AuthComponent/Resetpassword"</span>;
<span class="hljs-keyword">import</span> EmailConfirmation <span class="hljs-keyword">from</span> <span class="hljs-string">"./AuthComponent/EmailConfirmation"</span>;
<span class="hljs-keyword">import</span> ActivateAccount <span class="hljs-keyword">from</span> <span class="hljs-string">"./AuthComponent/ActivateAccount"</span>;
<span class="hljs-keyword">import</span> Conversations <span class="hljs-keyword">from</span> <span class="hljs-string">"./Conversations"</span>;
<span class="hljs-keyword">import</span> Homepage <span class="hljs-keyword">from</span> <span class="hljs-string">"./Homepage/Homepage"</span>;
<span class="hljs-keyword">import</span> Profile <span class="hljs-keyword">from</span> <span class="hljs-string">"./Profile"</span>;
<span class="hljs-keyword">import</span> ChangePassword <span class="hljs-keyword">from</span> <span class="hljs-string">"./ChangePassword"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./App.scss"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">HashRouter</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">{root}</span> <span class="hljs-attr">exact</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{Homepage}</span> /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">{login}</span> <span class="hljs-attr">exact</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Login</span> /&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">Route</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">{signup}</span> <span class="hljs-attr">exact</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Signup</span> /&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">Route</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">{forgotpassword}</span> <span class="hljs-attr">exact</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Forgotpassword</span> /&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">Route</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">{resetpassword}</span> <span class="hljs-attr">exact</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Resetpassword</span> /&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">Route</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">{emailConfirmation}</span> <span class="hljs-attr">exact</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{EmailConfirmation}</span> /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">{activateAccount}</span> <span class="hljs-attr">exact</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ActivateAccount</span> /&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">Route</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">{conversations}</span> <span class="hljs-attr">exact</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{Conversations}</span> /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">{updateProfile}</span> <span class="hljs-attr">exact</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{Profile}</span> /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">{changePassword}</span> <span class="hljs-attr">exact</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{ChangePassword}</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">HashRouter</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>Every time we needed to add a new route for our new page, we had to add a new <code>Route</code> component manually and was tricky to manage. That's why we separated our routing logic into a different folder that will generate those routes for us.</p>
<p><em>Let's talk about other files inside <code>src/Routes/</code>.</em></p>
<h3 id="lazypagesjs">lazyPages.js</h3>
<p>This file has a default export of an <code>Object</code>, which has <code>key</code> as <code>page</code> name and value as <code>lazy</code> loading page component. You can see the <a target="_blank" href="https://github.com/ramankarki/react-project-structure/blob/main/src/Routes/lazyPages.js">code</a> to know how pages are loaded lazily.</p>
<h3 id="routeshelperjs">routesHelper.js</h3>
<p>This file also has a default export of an <code>Object</code>. It has code to merge object returned from <code>src/Routes/lazyPages.js</code> and <code>src/Routes/routes.js</code> which will be imported and used by <code>src/Routes/index.jsx</code>.</p>
<h3 id="pagewrapperjsx">PageWrapper.jsx</h3>
<p>It is a react component that will have the logic to prevent access to protected routes from unauthenticated users. If the user is logged in and private property in route object true, they can access the protected routes, or else they will be redirected to the login page. You will be writing that logic on your own.</p>
<h3 id="indexjsx">index.jsx</h3>
<p>And finally, a react component that will loop over the object returned from <code>routesHelper.js</code> and return array of <code>Routes</code> component wrapped inside <code>HashRouter</code> component. The component will be imported and mounted in the <code>App.js</code> component. You will see that in just a moment. </p>
<h2 id="adding-new-route-for-new-page-component">Adding new route for new page component</h2>
<p><em>We will see our way of managing components down below.</em></p>
<ul>
<li>Create new page component inside <code>pages</code>.</li>
</ul>
<pre><code class="lang-file">react-project-structure
└── src
    └── pages
         └── NewPage
              └── index.jsx
</code></pre>
<ul>
<li>Add new path in <code>/src/Routes/constants.js</code>.</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> NEW_PAGE = <span class="hljs-string">'/new-page'</span>
</code></pre>
<ul>
<li><p>import <code>NEW_PAGE</code> const variable inside <code>/src/Routes/routes.js</code>.</p>
</li>
<li><p>Add new route object in <code>/src/Routes/routes.js</code>.</p>
</li>
</ul>
<pre><code class="lang-javascript">  <span class="hljs-comment">// Add your routes here</span>
[NEW_PAGE]: {
    <span class="hljs-attr">private</span>: <span class="hljs-literal">false</span>,
    <span class="hljs-attr">pageName</span>: <span class="hljs-string">'NewPage'</span>,
  }
</code></pre>
<p><em><code>pageName</code> should be the same as the folder name inside <code>pages</code> folder.</em></p>
<h2 id="srcappjs">src/App.js</h2>
<p>We don't need to do anything here. Just import <code>Routes</code> and wrap with <code>lazy</code> and <code>ErrorBoundary</code>.</p>
<pre><code><span class="hljs-keyword">import</span> { lazy, Suspense } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">import</span> ErrorBoundary <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/ErrorBoundary'</span>;
<span class="hljs-keyword">import</span> PageLoadingSpinner <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/PageLoadingSpinner'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'./App.scss'</span>;

<span class="hljs-keyword">const</span> Routes = lazy(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./Routes'</span>));

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ErrorBoundary</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Suspense</span> <span class="hljs-attr">fallback</span>=<span class="hljs-string">{PageLoadingSpinner()}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Routes</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Suspense</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">ErrorBoundary</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre><p>This will show <code>PageLoadingSpinner</code> until page files gets loaded.</p>
<h2 id="srcvariablesscss">src/_variables.scss</h2>
<p>We add all the variables used in our projects like colors, container width, font sizes, font weights, media breakpoints, box-shadows, etc.</p>
<h2 id="srcactions">src/actions/</h2>
<p>We will add all the action types in <code>constants.js</code> and import them wherever it is required. The reason is the same as adding a new path in <code>src/Routes/constants.js</code> as you read above.</p>
<h4 id="some-tips-for-creating-action-creator">Some tips for creating action creator:</h4>
<ul>
<li><p>Try to write your action creator functions in their own file, i.e. authentication action creators in <code>auth.js</code>.</p>
</li>
<li><p>Try to use single <code>onGet</code> action creator to make all the <code>@GET</code> request. Same goes for other request methods.</p>
</li>
<li><p>Try to use <code>helper.js</code> to write your common code as a function to make it re-usable for other action creators.</p>
</li>
<li><p>Try to write <strong>HOF (Higher Order Functions)</strong> if you have similar logic and need to create multiple action creators.</p>
</li>
</ul>
<h2 id="srcappstate">src/appState/</h2>
<h3 id="context">context</h3>
<p>In large web applications, it is often desirable to split up the app code into multiple JS bundles that can be loaded on-demand. This strategy, called <code>code splitting</code>, helps to increase performance of your application by reducing the size of the initial JS payload that must be fetched.</p>
<p>Most applications deal with multiple types of data, which can be broadly divided into three categories:</p>
<ul>
<li><strong>Domain data</strong>: This should be like a mini-database. Data returned from server should be stored in this reducer and <a target="_blank" href="https://redux.js.org/usage/deriving-data-selectors">selectors</a> can be used to extract required data from the store.</li>
<li><strong>App state</strong>: Data that is specific to the application's behavior (such as 'there is a request in progress to fetch Todos').</li>
<li><strong>UI state</strong>: Data that represents how the UI is currently displayed (such as 'The EditTodo modal dialog is currently open' or 'state of a login form').</li>
</ul>
<p><a target="_blank" href="https://redux.js.org/usage/structuring-reducers/basic-reducer-structure">Read more in detail</a></p>
<h3 id="back-to-appstate">Back to appState</h3>
<p>We have written app state in separate files inside <code>appState</code> folder. It will be used as an initial state for <code>APP_STATE_ACTION_TYPES</code> while dynamically injecting reducers. If we write all the reducers and combine them while creating store, our JS bundle size will grow more larger on build time. That's why we did this to have dynamic reducers. Only required reducers for <code>page</code> will exists on redux store on mount. <a target="_blank" href="https://github.com/ramankarki/react-project-structure/blob/main/src/pages/Dashboard/index.jsx">See the usage</a>.</p>
<p>You can do this with Domain and UI state, Injecting required reducers on <code>page</code> component on mount.</p>
<h2 id="srcreducers">src/reducers/</h2>
<p>As an application grows, common patterns in reducer logic will start to emerge. You may find several parts of your reducer logic doing the same kinds of work for different types of data, and want to reduce duplication by reusing the same common logic for each data type. For that, we can use <strong>HOF (Higher Order Function)</strong> reducer. We can also call them as a "reducer factory".</p>
<p>The two most common ways to write a <strong>HOF</strong> reducer are to generate new action constants with a given prefix or suffix, or to attach additional info inside the action object.</p>
<p><a target="_blank" href="https://github.com/ramankarki/react-project-structure/blob/main/src/reducers/HOFreducer.js">This</a> is how we wrote our <strong>HOF</strong> reducer, and you can write on your own for your project.</p>
<h2 id="srcutils">src/utils/</h2>
<p>The crucial files here are <code>actionLogger.js</code>, <code>dynamicReducers.js</code>, <code>monitorReducers.js</code>. Other files are straightforward. You can explore on your own and change if you want.</p>
<p><code>actionLogger.js</code> and <code>monitorReducers.js</code> were setup from <a target="_blank" href="https://redux.js.org/usage/configuring-your-store#extending-redux-functionality">Redux official site</a>. These will be used to configure redux store.</p>
<p><code>dynamicReducers.js</code> returns a function that will be used as a redux store enhancer and will be used while configuring redux store.</p>
<blockquote>
<p>NOTE: Middleware adds extra functionality to the Redux dispatch function; enhancers add extra functionality to the Redux store.</p>
</blockquote>
<h2 id="srcconfigurestorejs">src/configureStore.js</h2>
<p>This file was setup with <a target="_blank" href="https://redux.js.org/usage/configuring-your-store#the-solution-configurestore">Redux official site</a> as well. You can have a look if you want to read in detail.</p>
<h3 id="why-configure-redux-store-like-this">Why configure redux store like this?</h3>
<ul>
<li><p>Dynamic reducers with <strong>HMR (Hot Module Replacement)</strong>. Helps in reducing JS bundle size.</p>
</li>
<li><p>Wraps middleware, enhancers, and redux dev tools.</p>
</li>
<li><p>Logs state each time redux dispatches any action.</p>
</li>
</ul>
<h2 id="srcservice-workerjs-and-srcserviceworkerregistrationjs">src/service-worker.js &amp; src/serviceWorkerRegistration.js</h2>
<p>These two files were generated by <strong>CRA (Create React App) PWA (Progressive Web App)</strong> template. We don't need to touch these files.</p>
<p><em>Finally comes the folders where we will write our components.</em></p>
<h2 id="srccomponents">src/components/</h2>
<p>Here, we will keep our tiny components which will be used more commonly in our templates or pages. For example: </p>
<ul>
<li>Buttons</li>
<li>Responsive images</li>
<li>Input fields</li>
<li>Badges</li>
<li>Tabs</li>
<li>Progress bar</li>
<li>Spinners</li>
<li>Tool tips</li>
</ul>
<h2 id="srctemplates">src/templates/</h2>
<p>Here, we will keep our templates which will be used in multiple pages. For example:</p>
<ul>
<li>Header</li>
<li>Footer</li>
<li>Form</li>
<li>Grid layout</li>
<li>Card</li>
<li>Modal</li>
</ul>
<h2 id="srcpages">src/pages/</h2>
<p>Here, we will keep our final pages that will be passed as a component on <code>Route</code> (component of a <code>react-router-dom</code>) and will be rendered in our browser. For example:</p>
<ul>
<li>Home</li>
<li>Signup</li>
<li>Login</li>
<li>Contact</li>
</ul>
<h2 id="difference-between-components-templates-and-pages">Difference between <code>components</code>, <code>templates</code>, and <code>pages</code></h2>
<p>In our file structure, the <code>components</code> folder will contain only small components which may have one or two elements inside them and won't have their own state.</p>
<p>On the other hand, the <code>templates</code> folder will contain the components which may have multiple elements and tiny components inside them and may or may not have their own state.</p>
<p>And finally, the <code>pages</code> folder will contain the components which are made of using multiple elements, templates, and tiny components. It is the last component and will be passed on <code>Route</code> and won't be re-used elsewhere.</p>
<p>Think of it as an atoms, molecules, and organs.</p>
<h2 id="conclusion">Conclusion</h2>
<p>It is not the only file structure and may not fit on every project. You can explore how others have managed their file structure and make changes if you want. Let me know if I missed something.</p>
<p>Thank you for reading my blog/article. ❤️❤️</p>
]]></content:encoded></item><item><title><![CDATA[How to Use the React useState Hook: Multiple Approaches for Your Projects]]></title><description><![CDATA[While I was learning React and building projects, I found multiple ways of using React useState hook in our projects.
So I wanted to share with my fellow developers and myself in future cause I will be working on multiple libraries, So I may forget t...]]></description><link>https://blog.ramankarki.dev/how-to-use-the-react-usestate-hook-multiple-approaches-for-your-projects</link><guid isPermaLink="true">https://blog.ramankarki.dev/how-to-use-the-react-usestate-hook-multiple-approaches-for-your-projects</guid><category><![CDATA[React]]></category><category><![CDATA[ReactHooks]]></category><category><![CDATA[Reactive Programming]]></category><category><![CDATA[JSX]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Raman Karki]]></dc:creator><pubDate>Fri, 01 Oct 2021 09:16:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1633079700507/UTGaKwfgu.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>While I was learning React and building projects, I found multiple ways of using React <code>useState</code> hook in our projects.</p>
<p>So I wanted to share with my fellow developers and myself in future cause I will be working on multiple libraries, So I may forget these things 😂😂</p>
<h2 id="heading-what-is-react-hook">What is React hook?</h2>
<p>Hooks are a new addition in React 16.8. They let you use state and other React features without writing a class.</p>
<h3 id="heading-example">Example:</h3>
<p>Just like we used states in our <strong>Class Based Components</strong>,</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Test</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{
  <span class="hljs-keyword">constructor</span>(props) {
    <span class="hljs-built_in">super</span>(props);
    <span class="hljs-built_in">this</span>.state = { <span class="hljs-attr">test</span>: <span class="hljs-string">'This is state'</span> };
  }

  onClick = <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">this</span>.setState({ <span class="hljs-attr">test</span>: <span class="hljs-string">'State changed on click'</span> });

  render() {
    <span class="hljs-keyword">return</span> (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Hello, world!<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{this.onClick}</span>&gt;</span>{this.state.test}<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    );
  }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Test;
</code></pre>
<p>We initialize states in <strong>Functional components</strong> like this,</p>
<pre><code class="lang-plaintext">import { useState } from 'react';

function Test() {
  const [state, setState] = useState('This is state');

  const onClick = () =&gt; setState('State changed on click');

  return (
    &lt;div&gt;
      &lt;h1&gt;Hello, world!&lt;/h1&gt;
      &lt;button onClick={onClick}&gt;{state}&lt;/button&gt;
    &lt;/div&gt;
  );
}

export default Test;
</code></pre>
<p>Just so you know, We can initialize multiples states with <code>useState</code>,</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Test</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [state, setState] = useState(<span class="hljs-string">'This is state'</span>);
  <span class="hljs-keyword">const</span> [state1, setState1] = useState(<span class="hljs-string">'This is another state'</span>);
  <span class="hljs-keyword">const</span> [state2, setState2] = useState(<span class="hljs-string">'And another state'</span>);

  <span class="hljs-keyword">const</span> onClick = <span class="hljs-function">() =&gt;</span> setState(<span class="hljs-string">'State changed on click'</span>);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Hello, world!<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{onClick}</span>&gt;</span>{state}<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>This was pretty simple and straight forward way of using <code>useState</code> React hook.</p>
<hr />
<h3 id="heading-some-important-points-to-keep-in-mind">💡 Some important points to keep in mind:</h3>
<ul>
<li>We never update states directly.</li>
</ul>
<pre><code class="lang-js">state = <span class="hljs-string">'whatever'</span>
</code></pre>
<p>This won't re-render our component. Hence, it won't be reflected in our browser.</p>
<ul>
<li>State updates are asynchronous. So we can't update state in some like of loops, conditions, or nested functions. React development server will through an error.</li>
</ul>
<p>``` Uncaught (in promise) Invariant Violation: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops. ```</p>
<ul>
<li><p>Only call Hooks from React functional components or our own custom Hooks.</p>
</li>
<li><p>React hooks doesn't work inside <strong>Class Based Components</strong>.</p>
</li>
</ul>
<p>🥳🥳 <em>Let's see some other ways of using</em> <code>useState</code> hook in our projects.</p>
<h2 id="heading-passing-callback-function-inside-setstate-function">Passing callback function inside <code>setState</code> function</h2>
<p>Let me explain how we can use callback function inside <code>setState</code> function. Let's build a simple todo list that looks something like this,</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1633072365877/OP5bvYfut.png" alt="todo list.png" /></p>
<p><em>There is no styling, just plane html syntax.</em></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Test</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [list, setList] = useState([]);
  <span class="hljs-keyword">const</span> [input, setInput] = useState(<span class="hljs-string">''</span>);

  <span class="hljs-keyword">const</span> onSubmit = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
    event.preventDefault();
    setList(<span class="hljs-function">(<span class="hljs-params">prev</span>) =&gt;</span> [...prev, input]);
    setInput(<span class="hljs-string">''</span>);
  };

  <span class="hljs-keyword">const</span> onChange = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> setInput(event.target.value);

  <span class="hljs-keyword">const</span> onDelete = <span class="hljs-function">(<span class="hljs-params">index</span>) =&gt;</span> <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span>
    setList(<span class="hljs-function">(<span class="hljs-params">prev</span>) =&gt;</span> [...prev.slice(<span class="hljs-number">0</span>, index), ...prev.slice(index + <span class="hljs-number">1</span>)]);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Hello, world!<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
        {list.map((list, index) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{list</span> + <span class="hljs-attr">index</span>}&gt;</span>
            {list} <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{onDelete(index)}</span>&gt;</span>x<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        ))}
      <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{onSubmit}</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{input}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{onChange}</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>Add<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Test;
</code></pre>
<p><em>We can initialize state value with any valid datatype.</em></p>
<p>We usually pass a value and that value becomes the new state. But <code>setState</code> function also takes a callback function that receives previous state as an argument and whatever the function returns will the next value for that state.</p>
<h2 id="heading-passing-setstate-function-as-a-props-for-child-component">Passing <code>setState</code> function as a props for child component</h2>
<p>This technique is mainly useful for lifting child state in its parent component.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// parent.jsx</span>
<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> Child <span class="hljs-keyword">from</span> <span class="hljs-string">'./child'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parent</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [parent, setParent] = useState(<span class="hljs-string">'hello'</span>);
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{parent}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Child</span> <span class="hljs-attr">setParent</span>=<span class="hljs-string">{setParent}</span> /&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> parent;
</code></pre>
<pre><code class="lang-plaintext">// child.jsx
import { useState, useEffect } from 'react';

function child(props) {
  const [child, setChild] = useState('whatever');

  useEffect(() =&gt; {
    props.setParent(child);
  }, []);

  return &lt;h3&gt;{child}&lt;/h3&gt;;
}

export default child;
</code></pre>
<p>If you try to run these files, Both <code>h1</code> and <code>h3</code> will render 'whatever'. The reason is, initially the parent state value is 'hello', But when child component gets mounted,</p>
<pre><code class="lang-javascript">  useEffect(<span class="hljs-function">() =&gt;</span> {
    props.setParent(child);
  }, []);
</code></pre>
<p>this code gets executed and <code>setParent</code> state function which is passed as a props in its child component, sets the parent state value same as the child state value. Therefore, both the child and parent component renders the same value as 'whatever'.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p><code>useState</code> hook is one of the most important hook for functional component based projects. There are many more ways of using <code>useState</code> hook in our projects. This is just the beginning. I have just covered the important use cases. So, that's it on this topic. Let me know if I missed something.</p>
<p>Thank you for reading this blog. ❤️❤️</p>
]]></content:encoded></item><item><title><![CDATA[React project setup with Vite for faster development | Blazing fast server startup and updates]]></title><description><![CDATA[Situation
We are working on a large project using React with many routes, and we have a deadline.
CRA takes too much time to create a new project in an average specs device. We want our new project and development server ready in seconds.
We are star...]]></description><link>https://blog.ramankarki.dev/react-project-setup-with-vite-for-faster-development-or-blazing-fast-server-startup-and-updates</link><guid isPermaLink="true">https://blog.ramankarki.dev/react-project-setup-with-vite-for-faster-development-or-blazing-fast-server-startup-and-updates</guid><category><![CDATA[React]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[webpack]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[continuous deployment]]></category><dc:creator><![CDATA[Raman Karki]]></dc:creator><pubDate>Wed, 29 Sep 2021 16:36:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1632836898396/CSztsxiAl.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="situation">Situation</h2>
<p>We are working on a large project using React with many routes, and we have a deadline.</p>
<p>CRA takes too much time to create a new project in an average specs device. We want our new project and development server ready in seconds.</p>
<p>We are starting to build more and more ambitious applications. The amount of JavaScript we are dealing with also increased exponentially. It is common for large-scale projects to contain thousands of modules. </p>
<p>We are starting to hit a performance bottleneck for JavaScript-based tooling. It can often take an unreasonably long wait (sometimes up to minutes!) to spin up a dev server. And even file edits can take a couple of seconds to be reflected in the browser.</p>
<p><em>Let's see what Vite can do for us.</em></p>
<hr />
<h2 id="some-of-the-features-of-vite">Some of the features of Vite.</h2>
<h3 id="npm-dependency-resolving-and-pre-bundling">NPM Dependency Resolving and Pre-Bundling</h3>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { someMethod } <span class="hljs-keyword">from</span> <span class="hljs-string">'my-dep'</span>
</code></pre>
<p>Vite will detect such bare module imports in all served source files and perform the following:</p>
<ul>
<li>Pre-bundle them to improve page loading speed and convert CommonJS / UMD modules to ESM. The pre-bundling step is performed with esbuild and makes Vite's cold start time significantly faster than any JavaScript-based bundler.</li>
<li>Rewrite the imports to valid URLs like <code>/node_modules/.vite/my-dep.js?v=f3sf2ebd</code> so that the browser can import them properly.</li>
<li>Vite caches dependency requests via HTTP headers.</li>
</ul>
<h3 id="hot-module-replacement">Hot Module Replacement</h3>
<p>Frameworks with <strong>HMR</strong> (Hot Module Replacement) capabilities can leverage the API to provide instant, precise updates without reloading the page or blowing away application state.</p>
<h3 id="typescript">TypeScript</h3>
<p>Vite supports importing <code>.ts</code> files out of the box. However, Some configuration fields under <code>compilerOptions</code> in <code>tsconfig.json</code> require special attention. <a target="_blank" href="https://vitejs.dev/guide/features.html#typescript-compiler-options">Checkout more</a> if you use TypeScript.</p>
<p>Vite uses <code>esbuild</code> to transpile TypeScript into JavaScript which is about 20~30x faster than vanilla <code>tsc</code>, and HMR updates can reflect in the browser in under 50ms.</p>
<h3 id="jsx">JSX</h3>
<p><code>.jsx</code> and <code>.tsx</code> files are also supported out of the box.</p>
<h3 id="css">CSS</h3>
<p>Importing <code>.css</code> files will inject its content to the page via a <code>&lt;style&gt;</code> tag with HMR support. You can also retrieve the processed CSS as a string as the module's default export.</p>
<h3 id="css-modules">CSS Modules</h3>
<p>Any CSS file ending with <code>.module.css</code> is considered a CSS modules file. Importing such a file will return the corresponding module object:</p>
<pre><code class="lang-css"><span class="hljs-comment">/* example.module.css */</span>
<span class="hljs-selector-class">.red</span> {
  <span class="hljs-attribute">color</span>: red;
}
</code></pre>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> classes <span class="hljs-keyword">from</span> <span class="hljs-string">'./example.module.css'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.red}</span>&gt;</span>Hello world<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
}
</code></pre>
<p>CSS modules behavior can be configured via the <code>css.modules</code> option.</p>
<p>If <code>css.modules.localsConvention</code> is set to <code>camelCaseOnly</code>, you can also use named imports:</p>
<pre><code class="lang-js"><span class="hljs-comment">/* vite.config.js */</span>

<span class="hljs-keyword">import</span> { defineConfig } <span class="hljs-keyword">from</span> <span class="hljs-string">'vite'</span>;
<span class="hljs-keyword">import</span> react <span class="hljs-keyword">from</span> <span class="hljs-string">'@vitejs/plugin-react'</span>;

<span class="hljs-comment">// https://vitejs.dev/config/</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> defineConfig({
  <span class="hljs-attr">plugins</span>: [react()],
  <span class="hljs-attr">css</span>: {
    <span class="hljs-attr">modules</span>: {
      <span class="hljs-attr">localsConvention</span>: <span class="hljs-string">'camelCaseOnly'</span>,
    },
  },
});
</code></pre>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { red } <span class="hljs-keyword">from</span> <span class="hljs-string">'./example.module.css'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{red}</span>&gt;</span>Hello world<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
}
</code></pre>
<h3 id="css-pre-processors">CSS Pre-processors</h3>
<p>Good news for developers if you are a <strong>Sass</strong> user like me. Vite also provide built-in support for <code>.scss</code>, <code>.sass</code>, <code>.less</code>, <code>.styl</code> and <code>.stylus</code> files. There is no need to install Vite-specific plugins for them, but the corresponding pre-processor itself must be installed:</p>
<pre><code class="lang-sh"><span class="hljs-comment"># .scss and .sass</span>
npm install sass --save-dev

<span class="hljs-comment"># .less</span>
npm install less --save-dev

<span class="hljs-comment"># .styl and .stylus</span>
npm install stylus --save-dev
</code></pre>
<p>You can also use CSS modules combined with pre-processors by prepending <code>.module</code> to the file extension, for example <code>style.module.scss</code>.</p>
<h3 id="static-assets">Static Assets</h3>
<p>Importing a static asset will return the resolved public URL when it is served:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> imgUrl <span class="hljs-keyword">from</span> <span class="hljs-string">'./img.png'</span>
<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'hero-img'</span>).src = imgUrl
</code></pre>
<p>Special queries can modify how assets are loaded:</p>
<pre><code class="lang-js"><span class="hljs-comment">// Explicitly load assets as URL</span>
<span class="hljs-keyword">import</span> assetAsURL <span class="hljs-keyword">from</span> <span class="hljs-string">'./asset.js?url'</span>

<span class="hljs-comment">// Load assets as strings</span>
<span class="hljs-keyword">import</span> assetAsString <span class="hljs-keyword">from</span> <span class="hljs-string">'./shader.glsl?raw'</span>

<span class="hljs-comment">// Load Web Workers</span>
<span class="hljs-keyword">import</span> Worker <span class="hljs-keyword">from</span> <span class="hljs-string">'./worker.js?worker'</span>

<span class="hljs-comment">// Web Workers inlined as base64 strings at build time</span>
<span class="hljs-keyword">import</span> InlineWorker <span class="hljs-keyword">from</span> <span class="hljs-string">'./worker.js?worker&amp;inline'</span>
</code></pre>
<p><strong>Dynamic URLs</strong></p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getImageUrl</span>(<span class="hljs-params">name</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> URL(<span class="hljs-string">`./dir/<span class="hljs-subst">${name}</span>.png`</span>, <span class="hljs-keyword">import</span>.meta.url).href
}
</code></pre>
<p><code>import.meta.url</code> is a native ESM feature that exposes the current module's URL. Combining it with the native <code>URL</code> constructor, we can obtain the full, resolved URL of a static asset using relative path from a JavaScript module.</p>
<blockquote>
<p><strong>NOTE:</strong>  Does not work with SSR.</p>
</blockquote>
<p>This pattern does not work if you are using Vite for Server-Side Rendering, because <code>import.meta.url</code> have different semantics in browsers vs. Node.js. The server bundle also cannot determine the client host URL ahead of time.</p>
<h3 id="json">JSON</h3>
<p>JSON files can be directly imported - named imports are also supported:</p>
<pre><code class="lang-js"><span class="hljs-comment">// import the entire object</span>
<span class="hljs-keyword">import</span> json <span class="hljs-keyword">from</span> <span class="hljs-string">'./example.json'</span>

<span class="hljs-comment">// import a root field as named exports - helps with treeshaking!</span>
<span class="hljs-keyword">import</span> { field } <span class="hljs-keyword">from</span> <span class="hljs-string">'./example.json'</span>
</code></pre>
<h3 id="css-code-splitting">CSS Code-Splitting</h3>
<p>Vite automatically extracts the CSS used by modules in an async chunk and generates a separate file for it. The CSS file is automatically loaded via a <code>&lt;link&gt;</code> tag when the associated async chunk is loaded, and the async chunk is guaranteed to only be evaluated after the CSS is loaded to avoid FOUC.</p>
<h3 id="preload-directives-generation">Preload Directives Generation</h3>
<p>Vite automatically generates <code>&lt;link rel="modulepreload"&gt;</code> directives for entry chunks and their direct imports in the built HTML.</p>
<h3 id="env-variables">Env Variables</h3>
<p>Vite exposes env variables on the special <code>import.meta.env</code> object. Some built-in variables are available in all cases:</p>
<ul>
<li><code>import.meta.env.MODE</code>: {string} the mode the app is running in.</li>
<li><code>import.meta.env.BASE_URL</code>: {string} the base url the app is being served from. This is determined by the <code>base</code> config option.</li>
<li><code>import.meta.env.PROD</code>: {boolean} whether the app is running in production.</li>
<li><code>import.meta.env.DEV</code>: {boolean} whether the app is running in development (always the opposite of <code>import.meta.env.PROD</code>)</li>
</ul>
<h3 id="env-files"><code>.env</code> Files</h3>
<p>Only variables prefixed with <code>VITE_</code> are exposed to your Vite-processed code. e.g. the following file:</p>
<pre><code class="lang-env">DB_PASSWORD=foobar
VITE_SOME_KEY=123
</code></pre>
<p>Only <code>VITE_SOME_KEY</code> will be exposed as <code>import.meta.env.VITE_SOME_KEY</code> to your client source code, but <code>DB_PASSWORD</code> will not.</p>
<p>If you want to customize env variables prefix, see <a target="_blank" href="https://vitejs.dev/config/index.html#envprefix"><code>envPrefix</code></a> option.</p>
<p>❤️❤️ <em>These were the important features of Vite. </em></p>
<h2 id="now-lets-create-our-react-project-with-vite">Now let's create our React project with Vite.</h2>
<ul>
<li>Run <code>npm init vite@latest</code> and enter you project name.</li>
</ul>
<pre><code class="lang-bash">$ npm init vite@latest
? Project name: › vite-project
</code></pre>
<ul>
<li>Select your framework supported by Vite.</li>
</ul>
<pre><code class="lang-bash">✔ Project name: … vite-project
? Select a framework: › - Use arrow-keys. Return to submit.
❯   vanilla
    vue
    react
    preact
    lit
    svelte
</code></pre>
<ul>
<li>Select your variant.</li>
</ul>
<pre><code class="lang-bash">✔ Project name: … vite-project
✔ Select a framework: › react
? Select a variant: › - Use arrow-keys. Return to submit.
❯   react
    react-ts
</code></pre>
<pre><code class="lang-bash">✔ Project name: … vite-project
✔ Select a framework: › react
✔ Select a variant: › react

Scaffolding project <span class="hljs-keyword">in</span> /home/raman/Documents/vite-project...

Done. Now run:

  <span class="hljs-built_in">cd</span> vite-project
  npm install
  npm run dev
</code></pre>
<ul>
<li><p>By now your project should be ready. Now change your current directory with <code>cd vite-project</code> and just install dependencies with <code>npm install</code>.</p>
</li>
<li><p>After installing dependencies, spin up your dev server with <code>npm run dev</code>.</p>
</li>
</ul>
<blockquote>
<p>NOTE: <code>npm start</code> doesn't work with Vite.</p>
</blockquote>
<pre><code><span class="hljs-attr">vite v2.5.10 dev server running at:</span>

<span class="hljs-string">&gt;</span> <span class="hljs-attr">Local:</span> <span class="hljs-string">http://localhost:3000/</span>
<span class="hljs-string">&gt;</span> <span class="hljs-attr">Network:</span> <span class="hljs-string">use</span> <span class="hljs-string">`--host`</span> <span class="hljs-string">to</span> <span class="hljs-string">expose</span>

<span class="hljs-string">ready</span> <span class="hljs-string">in</span> <span class="hljs-string">1049ms.</span>
</code></pre><p>If you don't believe this message, try on your own 😂😂.
I was blown away myself when I saw this message.</p>
<h3 id="deploying-a-static-site">Deploying a static site</h3>
<p>Command for creating static files for production is <code>npm run build</code>. But Vite creates our static files inside <code>/dist</code> folder instead of <code>/build</code>.</p>
<p>So if you use <a target="_blank" href="https://www.netlify.com/">Netlify</a> for deploying your React apps like me, Remember to setup:</p>
<ul>
<li><strong>Build Command</strong>: <code>npm run build</code></li>
<li><strong>Publish directory</strong>: <code>dist</code></li>
</ul>
<h4 id="checkout-more-for-deploying-with-other-hosting-services">Checkout more for deploying with other hosting services:</h4>
<ul>
<li><a target="_blank" href="https://vitejs.dev/guide/static-deploy.html#github-pages">GitHub Pages</a></li>
<li><a target="_blank" href="https://vitejs.dev/guide/static-deploy.html#github-pages-and-travis-ci">GitHub Pages and Travis CI</a></li>
<li><a target="_blank" href="https://vitejs.dev/guide/static-deploy.html#gitlab-pages-and-gitlab-ci">GitLab Pages and GitLab CI</a></li>
<li><a target="_blank" href="https://vitejs.dev/guide/static-deploy.html#google-firebase">Google Firebase</a></li>
<li><a target="_blank" href="https://vitejs.dev/guide/static-deploy.html#surge">Surge</a></li>
<li><a target="_blank" href="https://vitejs.dev/guide/static-deploy.html#heroku">Heroku</a></li>
<li><a target="_blank" href="https://vitejs.dev/guide/static-deploy.html#vercel">Vercel</a></li>
<li><a target="_blank" href="https://vitejs.dev/guide/static-deploy.html#azure-static-web-apps">Azure Static Web Apps</a></li>
</ul>
<hr />
<p>So, that's it on this topic. Hope you found this tool helpful.</p>
<p>Let me know if I missed something.</p>
<p>Thank you for reading this blog. ❤️❤️</p>
]]></content:encoded></item><item><title><![CDATA[What is SSH | Why it is useful | How to setup SSH keys on GitHub and Bitbucket]]></title><description><![CDATA[Usually, working on our project, we clone our repository using HTTPS. Something like this,
raman@raman-Inspiron-15-3552:~/Documents$ git clone https://github.com/ramankarki/portfolio.git
Cloning into 'portfolio'...
remote: Enumerating objects: 586, d...]]></description><link>https://blog.ramankarki.dev/what-is-ssh-or-why-it-is-useful-or-how-to-setup-ssh-keys-on-github-and-bitbucket</link><guid isPermaLink="true">https://blog.ramankarki.dev/what-is-ssh-or-why-it-is-useful-or-how-to-setup-ssh-keys-on-github-and-bitbucket</guid><category><![CDATA[GitHub]]></category><category><![CDATA[ssh]]></category><category><![CDATA[Bitbucket]]></category><category><![CDATA[#howtos]]></category><dc:creator><![CDATA[Raman Karki]]></dc:creator><pubDate>Sat, 25 Sep 2021 13:31:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1632568735794/59tzhqLel.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Usually, working on our project, we clone our repository using <strong>HTTPS</strong>. Something like this,</p>
<pre><code><span class="hljs-attribute">raman</span>@raman-Inspiron-<span class="hljs-number">15</span>-<span class="hljs-number">3552</span>:~/Documents$ git clone https://github.com/ramankarki/portfolio.git
<span class="hljs-attribute">Cloning</span> into 'portfolio'...
<span class="hljs-attribute">remote</span>: Enumerating objects: <span class="hljs-number">586</span>, done.
<span class="hljs-attribute">remote</span>: Counting objects: <span class="hljs-number">100</span>% (<span class="hljs-number">586</span>/<span class="hljs-number">586</span>), done.
<span class="hljs-attribute">remote</span>: Compressing objects: <span class="hljs-number">100</span>% (<span class="hljs-number">392</span>/<span class="hljs-number">392</span>), done.
<span class="hljs-attribute">remote</span>: Total <span class="hljs-number">586</span> (delta <span class="hljs-number">263</span>), reused <span class="hljs-number">512</span> (delta <span class="hljs-number">192</span>), pack-reused <span class="hljs-number">0</span>
<span class="hljs-attribute">Receiving</span> objects: <span class="hljs-number">100</span>% (<span class="hljs-number">586</span>/<span class="hljs-number">586</span>), <span class="hljs-number">4</span>.<span class="hljs-number">59</span> MiB | <span class="hljs-number">2</span>.<span class="hljs-number">05</span> MiB/s, done.
<span class="hljs-attribute">Resolving</span> deltas: <span class="hljs-number">100</span>% (<span class="hljs-number">263</span>/<span class="hljs-number">263</span>), done.
<span class="hljs-attribute">raman</span>@raman-Inspiron-<span class="hljs-number">15</span>-<span class="hljs-number">3552</span>:~/Documents$
</code></pre><p>We make changes and try to push our commits like this,</p>
<pre><code>raman@raman-Inspiron-<span class="hljs-number">15</span>-<span class="hljs-number">3552</span><span class="hljs-symbol">:~/Documents/portfolio</span>$ git push
Username <span class="hljs-keyword">for</span> <span class="hljs-string">'https://github.com'</span><span class="hljs-symbol">:</span>
</code></pre><h3 id="the-problem">The problem:</h3>
<p>Every time we try to push our code, we have to enter our username and password. And that can be frustrating while we are working on our project for long hours.</p>
<h3 id="the-solution">The solution:</h3>
<p>If you didn't notice, let me tell you.
There are two ways of cloning your repository. </p>
<ul>
<li><strong>HTTPS</strong> - This is what you saw above.</li>
<li><strong>SSH</strong> - This is our solution to this problem. We setup once and never have to enter our credentials.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1632570584766/ugqk_5xBR.png" alt="screen shot of github.png" /></p>
<h2 id="what-is-ssh">What is SSH?</h2>
<p>Secure Shell (SSH) is a cryptographic network protocol for operating network services securely over an unsecured network. Typical applications include remote command-line, login, and remote command execution, but any network service can be secured with SSH.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1632572662306/hu4MN9Q-a.png" alt="ssh authentication.png" /></p>
<p>So now we know about SSH and its use case.</p>
<h2 id="lets-setup-our-ssh-keys-locally">Let's setup our SSH keys locally.</h2>
<p>To begin with, we create SSH keys in our terminal. Enter <code>ssh-keygen -C "yourmail@gmail.com"</code> and just press enter on each prompt you get.</p>
<pre><code>raman@raman-Inspiron<span class="hljs-number">-15</span><span class="hljs-number">-3552</span>:~$ ssh-keygen -C <span class="hljs-string">"yourmail@gmail.com"</span>
Generating public/private rsa key pair.
Enter file <span class="hljs-keyword">in</span> which to save the key (<span class="hljs-regexp">/home/raman/</span>.ssh/id_rsa): 
Created directory <span class="hljs-string">'/home/raman/.ssh'</span>.
Enter passphrase (empty <span class="hljs-keyword">for</span> <span class="hljs-literal">no</span> passphrase): 
Enter same passphrase again: 
Your identification has been saved <span class="hljs-keyword">in</span> <span class="hljs-regexp">/home/raman/</span>.ssh/id_rsa
Your public key has been saved <span class="hljs-keyword">in</span> <span class="hljs-regexp">/home/raman/</span>.ssh/id_rsa.pub
The key fingerprint is:
SHA256:UZ4+fPyPB1MMh7ko2Z6GErZkHusEF5/PbDM2IjltcP0 raman@raman-Inspiron<span class="hljs-number">-15</span><span class="hljs-number">-3552</span>
The key<span class="hljs-string">'s randomart image is:
+---[RSA 3072]----+
|          .    o |
|        .o .  + .|
|        .oo= . = |
|      . O+*.+ . o|
|       BSX+Boo . |
|        X =o&amp;.E  |
|       o = = +.o |
|        .      o.|
|              ...|
+----[SHA256]-----+
raman@raman-Inspiron-15-3552:~$</span>
</code></pre><p>By default your private key will be saved in '<strong>.ssh/id_rsa</strong>' file and public key in '<strong>.ssh/id_rsa. pub</strong>'.</p>
<p>With SSH keys, if someone gains access to your computer, they also gain access to every system that uses that key. To add an extra layer of security, you can add a passphrase to your SSH key. A passphrase is similar to a password. But in our case, we didn't add any passphrase. It's ok if our device won't be used by anyone. But if you are working on a team, you should definitely add one.</p>
<h2 id="now-we-setup-ssh-keys-on-github">Now we setup SSH keys on GitHub</h2>
<ul>
<li>Just go to your <strong>GitHub settings</strong> page and move to <a target="_blank" href="https://github.com/settings/keys"><strong>SSH and GPG keys tab</strong></a></li>
</ul>
<p><em>Page looks something like this,</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1632572965200/63rbvB6p5.png" alt="github settings page.png" /></p>
<ul>
<li>Click on the <strong>New SSH key</strong> button</li>
<li>Move to your terminal and enter <code>cat .ssh/id_rsa.pub</code><pre><code><span class="hljs-attribute">raman</span>@raman-Inspiron-<span class="hljs-number">15</span>-<span class="hljs-number">3552</span>:~$ cat .ssh/id_rsa.pub 
<span class="hljs-attribute">ssh</span>-rsa AAAAB<span class="hljs-number">3</span>NzaC<span class="hljs-number">1</span>yc<span class="hljs-number">2</span>EAAAADAQABAAABgQDDMH<span class="hljs-number">4</span>lNfHFGF<span class="hljs-number">0</span>G<span class="hljs-number">0</span>F<span class="hljs-number">7</span>kYvrVOKjSMfzKwYb+gttcSUQbbBSD/<span class="hljs-number">3</span>xq<span class="hljs-number">3</span>XkduZkx<span class="hljs-number">6</span>eQ+j<span class="hljs-number">6</span>HtBMbAV<span class="hljs-number">0</span>uqO<span class="hljs-number">2</span>VQDK<span class="hljs-number">7</span>XIXM<span class="hljs-number">2</span>mvn<span class="hljs-number">7</span>btKM<span class="hljs-number">7</span>oQDBftGX<span class="hljs-number">1</span>Xtrw<span class="hljs-number">8</span>oE<span class="hljs-number">3</span>UnUiorQVZkOlF<span class="hljs-number">76</span>ApX<span class="hljs-number">5</span>xgLFr<span class="hljs-number">1</span>eT<span class="hljs-number">6</span>QTFhdgdGT<span class="hljs-number">6</span>s<span class="hljs-number">3</span>yw<span class="hljs-number">1</span>zNIa/cjia<span class="hljs-number">9</span>j<span class="hljs-number">29</span>P<span class="hljs-number">7</span>tnNy<span class="hljs-number">7</span>voUyLdBUVG<span class="hljs-number">8</span>S<span class="hljs-number">6</span>sRI<span class="hljs-number">9</span>SC<span class="hljs-number">229</span>AFP<span class="hljs-number">3</span>XEyp<span class="hljs-number">7</span>sefydTfI/cEJXcEBbEG<span class="hljs-number">71</span>YNhkCqHnywALoTrq+PztpdZlZu+SVeidaIK<span class="hljs-number">76</span>rz<span class="hljs-number">7</span>Iqta/TnfymYvhqs<span class="hljs-number">830</span>eGNE<span class="hljs-number">5</span>hbHYjnZELyViRnFWeLAlzXa<span class="hljs-number">3</span>zjCf<span class="hljs-number">0</span>l<span class="hljs-number">62</span>jMhKfz<span class="hljs-number">7</span>lnOxPp<span class="hljs-number">5</span>Go<span class="hljs-number">5</span>We<span class="hljs-number">30</span>rNWKgj<span class="hljs-number">5</span>z<span class="hljs-number">1</span>shEAcbp<span class="hljs-number">1</span>L<span class="hljs-number">3</span>iWQO+OJvghNT<span class="hljs-number">3</span>RZBpqRm<span class="hljs-number">5</span>sEwzNGNrH<span class="hljs-number">4</span>V<span class="hljs-number">1</span>r<span class="hljs-number">518</span>QeQsPSSMVsXaoelyI<span class="hljs-number">7</span>siKD<span class="hljs-number">2</span>P<span class="hljs-number">4</span>i<span class="hljs-number">3</span>HFs<span class="hljs-number">5</span>EjAtKmI<span class="hljs-number">1</span>eVGGdugrZ<span class="hljs-number">2</span>zVoAi+Moue<span class="hljs-number">7</span>QGWNeTSz<span class="hljs-number">4</span>Ks<span class="hljs-number">5</span>TgeDdtrhVTqRpRnAFW<span class="hljs-number">7</span>jaA<span class="hljs-number">3</span>KGtnOUjgJBP<span class="hljs-number">8</span>KW<span class="hljs-number">4</span>u<span class="hljs-number">7</span>vc= raman@raman-Inspiron-<span class="hljs-number">15</span>-<span class="hljs-number">3552</span>
<span class="hljs-attribute">raman</span>@raman-Inspiron-<span class="hljs-number">15</span>-<span class="hljs-number">3552</span>:~$
</code></pre><em>You should see a long random string, That's your public SSH key</em></li>
<li>Copy everything that appeared on your terminal, starting from 'ssh-rsa'</li>
<li>Move to your browser (same GitHub settings page) and enter <strong>Title</strong> whatever you want it doesn't matter.</li>
<li>Paste your public <strong>SSH</strong> key on <strong>Key</strong> field and click <strong>Add SSH key</strong> button.</li>
</ul>
<p><em>GitHub should have redirected you to enter your password for confirmation.</em></p>
<p>And with that all done, Our SSH keys setup is complete. From today we clone our repository using SSH.</p>
<h2 id="lets-test-it-out">Let's test it out 🥳🥳</h2>
<p>We clone and push our commits using SSH.</p>
<ul>
<li>Go to your repository and choose <strong>SSH</strong> option for cloning.<pre><code><span class="hljs-attribute">raman</span>@raman-Inspiron-<span class="hljs-number">15</span>-<span class="hljs-number">3552</span>:~$ git clone git@github.com:ramankarki/portfolio.git
<span class="hljs-attribute">Cloning</span> into 'portfolio'...
<span class="hljs-attribute">The</span> authenticity of host 'github.com (<span class="hljs-number">13.250.177.223</span>)' can't be established.
<span class="hljs-attribute">RSA</span> key fingerprint is SHA<span class="hljs-number">256</span>:nThbg<span class="hljs-number">6</span>kXUpJWGl<span class="hljs-number">7</span>E<span class="hljs-number">1</span>IGOCspRomTxdCARLviKw<span class="hljs-number">6</span>E<span class="hljs-number">5</span>SY<span class="hljs-number">8</span>.
<span class="hljs-attribute">Are</span> you sure you want to continue connecting (yes/no/[fingerprint])? yes
<span class="hljs-attribute">Warning</span>: Permanently added 'github.com,<span class="hljs-number">13.250.177.223</span>' (RSA) to the list of known hosts.
<span class="hljs-attribute">remote</span>: Enumerating objects: <span class="hljs-number">586</span>, done.
<span class="hljs-attribute">remote</span>: Counting objects: <span class="hljs-number">100</span>% (<span class="hljs-number">586</span>/<span class="hljs-number">586</span>), done.
<span class="hljs-attribute">remote</span>: Compressing objects: <span class="hljs-number">100</span>% (<span class="hljs-number">392</span>/<span class="hljs-number">392</span>), done.
<span class="hljs-attribute">remote</span>: Total <span class="hljs-number">586</span> (delta <span class="hljs-number">263</span>), reused <span class="hljs-number">512</span> (delta <span class="hljs-number">192</span>), pack-reused <span class="hljs-number">0</span>
<span class="hljs-attribute">Receiving</span> objects: <span class="hljs-number">100</span>% (<span class="hljs-number">586</span>/<span class="hljs-number">586</span>), <span class="hljs-number">4</span>.<span class="hljs-number">59</span> MiB | <span class="hljs-number">1</span>.<span class="hljs-number">97</span> MiB/s, done.
<span class="hljs-attribute">Resolving</span> deltas: <span class="hljs-number">100</span>% (<span class="hljs-number">263</span>/<span class="hljs-number">263</span>), done.
<span class="hljs-attribute">raman</span>@raman-Inspiron-<span class="hljs-number">15</span>-<span class="hljs-number">3552</span>:~$
</code></pre></li>
<li>Make some changes and try to push your code.<pre><code><span class="hljs-attribute">raman</span>@raman-Inspiron-<span class="hljs-number">15</span>-<span class="hljs-number">3552</span>:~/portfolio$ git push
<span class="hljs-attribute">Warning</span>: Permanently added the RSA host key for IP address '<span class="hljs-number">20.205.243.166</span>' to the list of known hosts.
<span class="hljs-attribute">Enumerating</span> objects: <span class="hljs-number">7</span>, done.
<span class="hljs-attribute">Counting</span> objects: <span class="hljs-number">100</span>% (<span class="hljs-number">7</span>/<span class="hljs-number">7</span>), done.
<span class="hljs-attribute">Delta</span> compression using up to <span class="hljs-number">2</span> threads
<span class="hljs-attribute">Compressing</span> objects: <span class="hljs-number">100</span>% (<span class="hljs-number">4</span>/<span class="hljs-number">4</span>), done.
<span class="hljs-attribute">Writing</span> objects: <span class="hljs-number">100</span>% (<span class="hljs-number">4</span>/<span class="hljs-number">4</span>), <span class="hljs-number">375</span> bytes | <span class="hljs-number">375</span>.<span class="hljs-number">00</span> KiB/s, done.
<span class="hljs-attribute">Total</span> <span class="hljs-number">4</span> (delta <span class="hljs-number">2</span>), reused <span class="hljs-number">0</span> (delta <span class="hljs-number">0</span>)
<span class="hljs-attribute">remote</span>: Resolving deltas: <span class="hljs-number">100</span>% (<span class="hljs-number">2</span>/<span class="hljs-number">2</span>), completed with <span class="hljs-number">2</span> local objects.
<span class="hljs-attribute">To</span> github.com:ramankarki/portfolio.git
 <span class="hljs-attribute">c85c73f</span>..<span class="hljs-number">348</span>bbb<span class="hljs-number">1</span>  master -&gt; master
<span class="hljs-attribute">raman</span>@raman-Inspiron-<span class="hljs-number">15</span>-<span class="hljs-number">3552</span>:~/portfolio$
</code></pre></li>
</ul>
<p><em>Your code should have pushed on GitHub without prompting you to enter you username and password.</em></p>
<h2 id="adding-our-same-public-ssh-key-on-bitbucket">Adding our same public SSH key on Bitbucket</h2>
<ul>
<li>Go to your <strong>Bitbucket settings page</strong> and move to <a target="_blank" href="https://bitbucket.org/account/settings/ssh-keys/"><strong>SSH keys tab</strong></a>.</li>
<li>Add your public <strong>SSH</strong> key like you did on GitHub and clone your repository using <strong>SSH</strong>.</li>
</ul>
<h2 id="common-problems">Common problems ⛔</h2>
<p>There are some common problems that we see while using <strong>SSH</strong> and here is one.</p>
<pre><code><span class="hljs-attribute">The</span> authenticity of host 'github.com (<span class="hljs-number">20.205.243.166</span>)' can't be established.
<span class="hljs-attribute">RSA</span> key fingerprint is SHA<span class="hljs-number">256</span>:nThbg<span class="hljs-number">6</span>kXUpJWGl<span class="hljs-number">7</span>E<span class="hljs-number">1</span>IGOCspRomTxdCARLviKw<span class="hljs-number">6</span>E<span class="hljs-number">5</span>SY<span class="hljs-number">8</span>.
<span class="hljs-attribute">Are</span> you sure you want to continue connecting (yes/no/[fingerprint])? 
<span class="hljs-attribute">Host</span> key verification failed.
<span class="hljs-attribute">fatal</span>: Could not read from remote repository.

<span class="hljs-attribute">Please</span> make sure you have the correct access rights
<span class="hljs-attribute">and</span> the repository exists.
</code></pre><p>It prevents you from performing any action with <strong>GitHub</strong> thinking that you might be the intruder. The simple solution for this is to make a <strong>SSH key scanning</strong> manually. Something like this,</p>
<pre><code class="lang-bash">ssh-keyscan github.com &gt;&gt; ~/.ssh/known_hosts
</code></pre>
<p>This will do some testing for <strong>SSH Authentication</strong>. And after that, you will be able to perform any action with GitHub normally. Now, try pushing your code on GitHub and you should see some logs on your terminal.</p>
<pre><code class="lang-bash">Warning: Permanently added the RSA host key <span class="hljs-keyword">for</span> IP address <span class="hljs-string">'20.205.243.166'</span> to the list of known hosts.
Enumerating objects: 5, <span class="hljs-keyword">done</span>.
Counting objects: 100% (5/5), <span class="hljs-keyword">done</span>.
Delta compression using up to 2 threads
Compressing objects: 100% (3/3), <span class="hljs-keyword">done</span>.
Writing objects: 100% (3/3), 505 bytes | 505.00 KiB/s, <span class="hljs-keyword">done</span>.
Total 3 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), completed with 1 <span class="hljs-built_in">local</span> object.
To github.com:ramankarki/easy-stationary.git
   008b49f..e3b941c  main -&gt; main
</code></pre>
<hr />
<p>So, that's it on this topic. Hope you fixed your problem. </p>
<p>Let me know if I missed something.</p>
<p>Thank you for reading this blog. ❤️❤️</p>
]]></content:encoded></item><item><title><![CDATA[Journey to be a Professional Web Developer and Technical Content Writer | Web Developer from Nepal]]></title><description><![CDATA[Another newbie writer. 😂
Yup, I know that. Don't worry about me. I will get better someday. I promise. Anyway,
Hi everyone! 👋👋
My name is Raman Karki from Biratnagar, Nepal. I'm an 18 years old high school student pursuing technical education. I h...]]></description><link>https://blog.ramankarki.dev/journey-to-be-a-professional-web-developer-and-technical-content-writer-or-web-developer-from-nepal</link><guid isPermaLink="true">https://blog.ramankarki.dev/journey-to-be-a-professional-web-developer-and-technical-content-writer-or-web-developer-from-nepal</guid><category><![CDATA[newbie]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Web Design]]></category><category><![CDATA[Story]]></category><category><![CDATA[Learning Journey]]></category><dc:creator><![CDATA[Raman Karki]]></dc:creator><pubDate>Thu, 01 Jul 2021 13:34:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1634881520969/3UM7FOSEa.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-another-newbie-writer">Another newbie writer. 😂</h3>
<p>Yup, I know that. Don't worry about me. I will get better someday. I promise. Anyway,</p>
<p><strong>Hi everyone! 👋👋</strong></p>
<p>My name is Raman Karki from Biratnagar, Nepal. I'm an 18 years old high school student pursuing technical education. I have a passion for programming and solving problems. I have been thinking about this for quite some time now. Finally, I think it's time to get into it.</p>
<h3 id="heading-im-really-excited-to-start-writing-articles-let-me-tell-you-the-objective-of-my-articles-and-my-goals">I'm really excited to start writing articles. Let me tell you the objective of my articles and my goals.</h3>
<p><em>But first, Story time about me. Let's travel back in time.</em></p>
<p>I have been an average student and an introvert in all my school time. Therefore, I didn't use to have many friends. I didn't hate school but didn't like it either. I was just doing the things I was told to do by my parents without thinking anything. I was soo dumb.</p>
<h3 id="heading-but-time-will-help-us-grow">But time will help us grow.</h3>
<p>However, after starting high school, I was bored studying these subjects such as physics, mathematics, chemistry. But I loved computers, mainly software parts. I wanted to be a software developer though I didn't know if it was possible without studying Physics and Chemistry.</p>
<p>And I didn't want to go to college either because I had already given up on high school. I was just passing the school exams.</p>
<h3 id="heading-so-i-started-searching-on-google-how-to-become-a-software-developer">So, I started searching on google how to become a software developer.</h3>
<p><em>What else could I do, right?</em></p>
<p>I found many articles and online courses to guide me through the path to becoming a software developer. I was surprised to see those courses and articles that could teach me to become a software developer cause I had never seen such a thing before.</p>
<p>I saw many people on Youtube videos. They were all learning to code on their own and getting a job at the top tech companies.</p>
<p>And that's what motivated me to learn to code on my own too. My only objective was to learn to code and get a job.</p>
<h3 id="heading-what-else-could-a-lost-teenager-want-right">What else could a lost teenager want, right?</h3>
<p><em>By the way, I am still a teenager.</em> 😂</p>
<p>By the time I was searching for online courses and programming languages. I found the python programming language to be popular and easy to learn for a beginner. Also, It had many supporting developer groups that could help me grow faster.</p>
<p>I remember taking some free courses on the python programming language on Udemy. I was so happy to learn to code and to solve programming problems also to fix bugs.</p>
<p>But I found that only writing small scripts and learning to code wasn't enough to be a python developer. You have to build some actual projects to show.</p>
<h3 id="heading-so-i-wanted-to-build-some-awesome-projects-while-having-fun">So, I wanted to build some awesome projects while having fun.</h3>
<p>I was using Linux OS cause I found they are better for programming. I decided to build some desktop games. So, I began to learn the pygame library to make some desktop games.</p>
<p>I had a great experience learning the pygame library and building some games like Flappy Bird. It took me some days to figure out how to make that game and to code, but I had fun during the whole time.</p>
<p>I also read some books on the python language and solved problems given in those books. I learned about GUI (Graphical User Interface) and wrote some scripts with GUI-based libraries.</p>
<h3 id="heading-a-couple-of-months-passed-while-i-was-learning-python-i-came-across-hacking">🕑 A couple of months passed. While I was learning python, I came across hacking.</h3>
<p>I found hacking to be more fun and interesting, and I started watching Youtube videos on hacking and top hackers. I was continuously watching hacking videos and reading articles, and Before I knew it, I was already into hacking. So, I started searching for ethical hacking courses and began learning.</p>
<p>Later, I realized that you should have expertise with UNIX-like OS, networking, scripting, programming language, databases, and web technologies to be a hacker. It was too much. I was trying to learn all those things, literally all of them.</p>
<h3 id="heading-i-was-stupid-i-know-that">I was stupid, I know that.</h3>
<p>However, After a couple of months, I got overwhelmed and realized that I wasn't progressing on anything. I was confused and spent some time thinking about what to do. I read some articles, watched youtube videos, and later discovered that,</p>
<blockquote>
<p>If you will try to learn everything, you will master nothing.</p>
</blockquote>
<h3 id="heading-so-finally">So finally,</h3>
<p>I decided to stick with one. I found web development more exciting, and it had more job possibilities. I was so motivated to work with other developers in a group. </p>
<p>And that's what caused me to learn web technologies like Html, CSS, JavaScript. After learning for a few months, I began to build projects like landing pages and games like tic-tac-toe.</p>
<h3 id="heading-after-learning-those-for-a-couple-of-months">After learning those for a couple of months,</h3>
<p>I began learning React and the Redux library. It helps in building fast and scalable web apps. Then, I started to build web apps like a weather app, to-do list, job search, etc.</p>
<h3 id="heading-i-started-feeling-a-bit-confident">I started feeling a bit confident.</h3>
<p>Later, I wanted to build full-stack apps like a chat app or social media app. So to develop an API for those projects, I needed to learn backend technologies like Nodejs, Express, and MongoDB.</p>
<h3 id="heading-after-learning-those-technologies-and-building-projects-i-began-to-feel-overconfident">After learning those technologies and building projects, I began to feel overconfident.</h3>
<p><em>And you know what happens if you get overconfident.</em> </p>
<p>I thought that I was ready for a job. So, I started to build a portfolio. I designed my portfolio in Figma and began to build with React and hosted with Netlify. I didn't take much time to think about my portfolio and immediately jumped for hunting. I looked for jobs in some tech organizations. However, every one of them requested a degree which I didn't have.</p>
<h3 id="heading-after-investing-such-a-lot-of-time-and-energy-on-learning-and-building-yet-didnt-land-any-position">After investing such a lot of time and energy on learning and building yet didn't land any position,</h3>
<p>I was discouraged and didn't know what to do. I tried freelancing on Fiverr. But it felt like it wasn't for me. I wasted 2 - 3 months doing nothing. I wasn't studying at school and wasn't building any projects. I was only watching youtube videos and anime. I got bored and started searching <strong>"how to make money online"</strong> on YouTube. Most of them were all shi*.</p>
<h3 id="heading-how-do-i-know">How do I know?</h3>
<p>Well, I tried all of them. And it didn't work. I wasted so much time searching for shortcuts to make money. But I did learn many things and found some legit long-term ways like Blogging, Digital marketing, Affiliate marketing, selling products and services online, and building own brand.</p>
<p>But as I said before, one can't master everything at once. So I decided to stick with one. And that was to be a Web developer and write articles about whatever I learn or know about. AKA Technical content writer.</p>
<p>I realized,</p>
<blockquote>
<p>There is no shortcut for making any progress or money. And if there is, It won't last long.</p>
</blockquote>
<p>I also realized that I had many bad habits and a poor mindset which could stop me from meeting my goals. So, I decided to work on it and share my experiences with you and myself in the future. And that's what motivated me to start blogging. I wish I had known about blogging when I had just started to code.</p>
<p>Now back to the previous question,</p>
<h3 id="heading-why-am-i-blogging">Why am I blogging?</h3>
<p>There is a saying,</p>
<blockquote>
<p>The best way to learn anything is to teach others.</p>
</blockquote>
<p>That's why I have started blogging to explain whatever I learn by simplifying as much as possible to help you and myself in the future so that we can grow together.</p>
<h3 id="heading-what-are-my-future-articles-going-to-be">What are my future articles going to be?</h3>
<p>My upcoming articles will be about Web development and related fields. I may also share some of my personal experiences. </p>
<h3 id="heading-what-are-my-goals">What are my goals?</h3>
<ul>
<li>To be a web developer and a Technical content writer,</li>
<li>Build projects that could solve our problems,</li>
<li>Share knowledge with others, </li>
</ul>
<p>So, that was my story about how I started programming and the reason to start blogging and writing articles. I wish to learn, share and grow together who are like me.</p>
<p>Thank you for reading this article. If you have something to share or want me to blog on any topic,</p>
<p><strong>please leave your comment below. 💬 🔽</strong></p>
<p>I would love to hear your story about how you started programming.</p>
]]></content:encoded></item></channel></rss>