<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Victor Maina</title>
    <description>The latest articles on DEV Community by Victor Maina (@jvicmaina).</description>
    <link>https://dev.to/jvicmaina</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F488101%2F08138ca0-c609-49f0-9138-ccf804567a3d.jpg</url>
      <title>DEV Community: Victor Maina</title>
      <link>https://dev.to/jvicmaina</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jvicmaina"/>
    <language>en</language>
    <item>
      <title>How I Fixed WSL2's "100% Packet Loss" Networking Bug in Under 10 Minutes</title>
      <dc:creator>Victor Maina</dc:creator>
      <pubDate>Mon, 06 Jul 2026 23:53:18 +0000</pubDate>
      <link>https://dev.to/jvicmaina/how-i-fixed-wsl2s-100-packet-loss-networking-bug-in-under-10-minutes-110d</link>
      <guid>https://dev.to/jvicmaina/how-i-fixed-wsl2s-100-packet-loss-networking-bug-in-under-10-minutes-110d</guid>
      <description>&lt;p&gt;If you've ever launched &lt;strong&gt;Ubuntu in WSL2&lt;/strong&gt; only to discover there's &lt;strong&gt;no internet connection&lt;/strong&gt;—&lt;code&gt;ping&lt;/code&gt; fails, DNS doesn't resolve, and &lt;code&gt;apt update&lt;/code&gt; hangs forever—you're not alone.&lt;/p&gt;

&lt;p&gt;I recently ran into this issue while my &lt;strong&gt;Windows host had a perfectly working internet connection&lt;/strong&gt;, yet my WSL2 instance behaved as if it were completely offline.&lt;/p&gt;

&lt;p&gt;After trying nearly every solution recommended online, the fix turned out to be surprisingly simple.&lt;/p&gt;

&lt;p&gt;This post explains what didn't work, what actually fixed it, and why.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Inside my &lt;strong&gt;WSL2 Ubuntu 24.04&lt;/strong&gt; instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ping 8.8.8.8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;returned:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;100% packet loss
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Trying DNS wasn't any better:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ping google.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;produced:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Temporary failure in name resolution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even basic package management failed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It simply timed out because the Linux environment had no network connectivity.&lt;/p&gt;

&lt;p&gt;Meanwhile...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Windows could browse the web normally.&lt;/li&gt;
&lt;li&gt;✅ Wi-Fi was connected.&lt;/li&gt;
&lt;li&gt;✅ Other Windows applications had internet access.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The problem existed &lt;strong&gt;only inside WSL2&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Didn't Work
&lt;/h2&gt;

&lt;p&gt;Like many developers, I followed the usual troubleshooting advice first.&lt;/p&gt;

&lt;p&gt;Unfortunately, none of these solved the issue:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Editing &lt;code&gt;/etc/resolv.conf&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Making &lt;code&gt;resolv.conf&lt;/code&gt; immutable using &lt;code&gt;chattr&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Running:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;netsh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;winsock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;reset&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Running:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;netsh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;reset&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Restarting WSL&lt;/li&gt;
&lt;li&gt;Restarting Windows&lt;/li&gt;
&lt;li&gt;Manually configuring DNS servers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are common fixes for &lt;strong&gt;DNS problems&lt;/strong&gt;, but in my case the issue was much deeper.&lt;/p&gt;

&lt;p&gt;The real culprit wasn't DNS.&lt;/p&gt;

&lt;p&gt;It was the &lt;strong&gt;virtual networking layer that WSL2 uses&lt;/strong&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  The Fix: Enable Mirrored Networking
&lt;/h1&gt;

&lt;p&gt;The solution was adding a &lt;code&gt;.wslconfig&lt;/code&gt; file in my Windows user profile.&lt;/p&gt;

&lt;p&gt;Open &lt;strong&gt;PowerShell as Administrator&lt;/strong&gt; and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;notepad&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;USERPROFILE&lt;/span&gt;&lt;span class="s2"&gt;\.wslconfig"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[wsl2]&lt;/span&gt;
&lt;span class="py"&gt;networkingMode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;mirrored&lt;/span&gt;
&lt;span class="py"&gt;dnsTunneling&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;firewall&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the file.&lt;/p&gt;

&lt;p&gt;Then completely shut down WSL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;wsl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--shutdown&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, start WSL again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;wsl&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it.&lt;/p&gt;

&lt;p&gt;Immediately afterwards:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ping 8.8.8.8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;returned:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;3 packets transmitted, 3 received, 0% packet loss
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Network connectivity was restored.&lt;/p&gt;




&lt;h1&gt;
  
  
  Why This Works
&lt;/h1&gt;

&lt;p&gt;By default, &lt;strong&gt;WSL2 uses a NAT-based virtual network adapter&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Think of it as a virtual switch sitting between Windows and Linux.&lt;/p&gt;

&lt;p&gt;Normally this works well, but it can become corrupted or misconfigured after:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Windows updates&lt;/li&gt;
&lt;li&gt;Sleep and wake cycles&lt;/li&gt;
&lt;li&gt;VPN usage&lt;/li&gt;
&lt;li&gt;Firewall changes&lt;/li&gt;
&lt;li&gt;Hyper-V networking issues&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When that virtual switch breaks, your Linux instance loses its route to the outside world—even though Windows itself still has internet access.&lt;/p&gt;

&lt;p&gt;Setting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="py"&gt;networkingMode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;mirrored&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;changes how WSL2 connects to the network.&lt;/p&gt;

&lt;p&gt;Instead of relying on a separate virtual NAT adapter, WSL2 mirrors the Windows host's network interface directly.&lt;/p&gt;

&lt;p&gt;Adding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="py"&gt;dnsTunneling&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;allows DNS queries to flow through the Windows networking stack, avoiding many name-resolution issues.&lt;/p&gt;

&lt;p&gt;In my case, disabling the WSL firewall with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="py"&gt;firewall&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;also eliminated the remaining networking restrictions.&lt;/p&gt;

&lt;p&gt;The result was a stable connection that survived restarts and behaved much more reliably than the default NAT configuration.&lt;/p&gt;




&lt;h1&gt;
  
  
  Verify the Fix
&lt;/h1&gt;

&lt;p&gt;After restarting WSL, test a few commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ping 8.8.8.8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ping google.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If all four work, your networking stack has been restored successfully.&lt;/p&gt;




&lt;h1&gt;
  
  
  Key Takeaway
&lt;/h1&gt;

&lt;p&gt;If:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Windows has internet,&lt;/li&gt;
&lt;li&gt;WSL2 does not,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ping 8.8.8.8&lt;/code&gt; fails,&lt;/li&gt;
&lt;li&gt;and every DNS tutorial you've tried hasn't helped,&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;there's a good chance the problem &lt;strong&gt;isn't DNS at all&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It's the virtual networking layer.&lt;/p&gt;

&lt;p&gt;Enabling &lt;strong&gt;mirrored networking&lt;/strong&gt; through &lt;code&gt;.wslconfig&lt;/code&gt; solved the issue instantly for me, and it's now one of the first things I'll check whenever WSL2 suddenly loses connectivity.&lt;/p&gt;

&lt;p&gt;Hopefully, it saves you the same hours of troubleshooting it saved me.&lt;/p&gt;




&lt;h2&gt;
  
  
  Have you run into other WSL2 networking issues?
&lt;/h2&gt;

&lt;p&gt;I'm curious to hear what caused them and how you fixed them. Share your experience in the comments—your solution might help the next developer searching for "WSL2 no internet."&lt;/p&gt;

</description>
      <category>linux</category>
      <category>networking</category>
      <category>wsl2</category>
    </item>
    <item>
      <title>How to Find a Lost AI-Generated Project on Windows: A Developer's Forensics Guide</title>
      <dc:creator>Victor Maina</dc:creator>
      <pubDate>Tue, 30 Jun 2026 10:21:05 +0000</pubDate>
      <link>https://dev.to/jvicmaina/i-forgot-which-ai-tool-built-my-project-so-i-investigated-like-a-detective-3ooa</link>
      <guid>https://dev.to/jvicmaina/i-forgot-which-ai-tool-built-my-project-so-i-investigated-like-a-detective-3ooa</guid>
      <description>&lt;h2&gt;
  
  
  "Lost track of which AI tool built your project? Use this Windows command to find any Vite/React project by date no folder name needed."
&lt;/h2&gt;

&lt;p&gt;A few days ago I had a small panic moment that I think a lot of developers juggling multiple AI coding tools will recognize.&lt;/p&gt;

&lt;p&gt;I'm building a membership and matchday platform for &lt;strong&gt;Mugutha FC&lt;/strong&gt;, a community football club in Ruiru, Kenya playing in the Mt. Kenya Regional League. Somewhere in the blur of late-night builds across different AI assistants, I lost track of &lt;em&gt;where&lt;/em&gt; one specific version of the dashboard actually lived on my machine.&lt;/p&gt;

&lt;p&gt;I had a screenshot. I had a vague memory of a localhost URL. That's it.&lt;/p&gt;

&lt;p&gt;Here's how I found it — and the small forensic trick that cracked it open.&lt;/p&gt;

&lt;h2&gt;
  
  
  The clue I had
&lt;/h2&gt;

&lt;p&gt;The only solid evidence was a screenshot of the dashboard running in my browser:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;URL bar: &lt;code&gt;127.0.0.1:5173&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A timestamp visible in the Windows taskbar clock: &lt;code&gt;6/25/2026, 12:09 AM&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Sidebar items: Dashboard, Members, Fixtures, Broadcasts, Templates, Analytics, Settings&lt;/li&gt;
&lt;li&gt;A "Welcome, Wakili Eric" greeting and KPI cards for Active Members, Messages Sent, Fixtures This Month, and Expiring Soon&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Port &lt;code&gt;5173&lt;/code&gt; was the first real clue. That's Vite's default dev server port — so whatever this was, it was a React or Vue project scaffolded with Vite, running locally, not deployed anywhere.&lt;/p&gt;

&lt;p&gt;But which folder? I have a habit of spinning up project folders across different AI coding assistants while comparing approaches, and frankly I'd lost track of which tool had generated which version.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turning a screenshot into a search query
&lt;/h2&gt;

&lt;p&gt;The breakthrough was realizing the timestamp in the screenshot wasn't just a "nice to have" — it was a search filter.&lt;/p&gt;

&lt;p&gt;Windows has a built-in command called &lt;code&gt;forfiles&lt;/code&gt; that can filter files by modification date. Combined with a recursive search and a keyword filter, I could ask Windows: &lt;em&gt;"show me every project file touched on or after this exact date."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;First attempt — search by filename:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;forfiles /P "C:\Users\%USERNAME%" /S /M *mugutha* /D +0 /C "cmd /c echo @path @fdate @ftime" 2&amp;gt;nul
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This searches for any file with "mugutha" in the name. It's a reasonable first guess, but it has an obvious flaw — it only works if the &lt;em&gt;folder itself&lt;/em&gt; was named with "mugutha" in it. If an AI tool had scaffolded the project into something generic like &lt;code&gt;dashboard-app&lt;/code&gt; or a sandboxed temp folder, this search would find nothing.&lt;/p&gt;

&lt;p&gt;So I pivoted to searching by &lt;strong&gt;what a Vite project actually contains&lt;/strong&gt;, rather than what it's named:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;forfiles /P "C:\Users" /S /D +06/24/2026 /C "cmd /c echo @path @fdate @ftime" 2&amp;gt;nul | findstr /I "package.json vite.config"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Breaking that down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/P "C:\Users"&lt;/code&gt; — start the search at the Users directory&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/S&lt;/code&gt; — search recursively, including all subfolders&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/D +06/24/2026&lt;/code&gt; — only files modified &lt;strong&gt;on or after&lt;/strong&gt; this date&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/C "cmd /c echo @path @fdate @ftime"&lt;/code&gt; — for every match, print its full path, date, and time&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;findstr /I "package.json vite.config"&lt;/code&gt; — pipe the results through a filter that only keeps lines mentioning &lt;code&gt;package.json&lt;/code&gt; or &lt;code&gt;vite.config&lt;/code&gt;, the two files that exist in basically every Vite project root&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the key idea: instead of guessing a project name, I searched for the &lt;strong&gt;fingerprint of the technology&lt;/strong&gt; — files that are guaranteed to exist if a Vite project exists, regardless of what anyone called the folder.&lt;/p&gt;

&lt;h2&gt;
  
  
  What came back
&lt;/h2&gt;

&lt;p&gt;The output was immediately interesting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"C:\Users\CodexSandboxOffline\.codex\.sandbox\cwd\c01195b0e0a02dfa\package.json" 6/24/2026 8:22:03 PM
"C:\Users\CodexSandboxOffline\.codex\.sandbox\cwd\c01195b0e0a02dfa\node_modules\.vite\deps\package.json" ...
"C:\Users\CodexSandboxOffline\.codex\.sandbox\cwd\c01195b0e0a02dfa\node_modules\@vitejs\plugin-react\package.json" ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And there it was. Not in any of my normal project folders. Not in &lt;code&gt;Desktop\projects\Mugutha_MembersClub&lt;/code&gt;. It was sitting inside a completely separate Windows user profile: &lt;strong&gt;&lt;code&gt;CodexSandboxOffline&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That folder name told me everything. This particular version of the dashboard hadn't been hand-built by me in a normal project directory — it had been generated and run inside an isolated sandbox environment created by &lt;strong&gt;OpenAI Codex&lt;/strong&gt;, complete with its own user account, its own &lt;code&gt;node_modules&lt;/code&gt;, and a dependency tree showing &lt;code&gt;@vitejs/plugin-react&lt;/code&gt;, &lt;code&gt;lightningcss&lt;/code&gt;, &lt;code&gt;rolldown&lt;/code&gt;, and &lt;code&gt;lucide-react&lt;/code&gt; — a modern, fast Vite + React toolchain.&lt;/p&gt;

&lt;p&gt;Mystery solved. The dashboard in my screenshot wasn't from a different session of the same tool I'd been using elsewhere — it was a different AI assistant entirely, sandboxed in its own corner of the filesystem the whole time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The actual lesson here
&lt;/h2&gt;

&lt;p&gt;The interesting part of this story isn't really about Codex or sandboxes specifically. It's a pattern worth remembering if you work across multiple AI coding tools:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A screenshot timestamp is a search filter, not just a memory aid.&lt;/strong&gt; Once I treated the clock in the corner of my screenshot as a literal date filter for &lt;code&gt;forfiles&lt;/code&gt;, the search went from "guess the folder name" to "show me everything touched in this exact window" — which is a much more reliable way to search.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Search by what a project &lt;em&gt;contains&lt;/em&gt;, not what it's &lt;em&gt;called&lt;/em&gt;.&lt;/strong&gt; I didn't know the folder name. I did know it had to contain &lt;code&gt;package.json&lt;/code&gt; and likely &lt;code&gt;vite.config&lt;/code&gt;. Searching for the signature of the toolchain found it in seconds, in a location I never would have guessed to look — a separate sandboxed Windows user profile I didn't even know existed on my own machine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Different AI coding assistants can leave very different fingerprints on disk.&lt;/strong&gt; Some generate plain project folders in your normal workspace. Others, like Codex's sandbox mode, isolate themselves into entirely separate environments — different user accounts, different &lt;code&gt;node_modules&lt;/code&gt;, different everything. If you're switching between tools, it's worth knowing where each one actually puts its files.&lt;/p&gt;

&lt;h2&gt;
  
  
  The command, if you need it
&lt;/h2&gt;

&lt;p&gt;If you're in the same situation — you know roughly &lt;em&gt;when&lt;/em&gt; something was built but not &lt;em&gt;where&lt;/em&gt; — here's the general-purpose version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;forfiles /P "C:\Users" /S /D +MM/DD/YYYY /C "cmd /c echo @path @fdate @ftime" 2&amp;gt;nul | findstr /I "package.json vite.config"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Swap &lt;code&gt;package.json&lt;/code&gt; and &lt;code&gt;vite.config&lt;/code&gt; for whatever filename fingerprint matches your stack — &lt;code&gt;requirements.txt&lt;/code&gt; for Python, &lt;code&gt;Cargo.toml&lt;/code&gt; for Rust, &lt;code&gt;composer.json&lt;/code&gt; for PHP. The principle is the same: search for the file that's guaranteed to exist, not the folder name you might have forgotten.&lt;/p&gt;

&lt;p&gt;Once you find a candidate, confirm it before getting too excited:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd path\to\folder
type package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That one command tells you the project name, dependencies, and scripts — enough to know immediately whether you've found the right thing.&lt;/p&gt;




&lt;p&gt;Small investigation, but a satisfying one. Sometimes debugging isn't about the code at all — it's about reconstructing your own past actions from whatever digital breadcrumbs you left behind.&lt;/p&gt;

&lt;p&gt;"What AI tool do you use? Share your tips below!"&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>windows</category>
      <category>debugging</category>
    </item>
    <item>
      <title>How to Automate Image CAPTCHA Solving Using 2Captcha API with Python &amp; Selenium</title>
      <dc:creator>Victor Maina</dc:creator>
      <pubDate>Wed, 23 Jul 2025 21:33:50 +0000</pubDate>
      <link>https://dev.to/jvicmaina/how-to-automate-image-captcha-solving-using-2captcha-api-with-python-selenium-3ka5</link>
      <guid>https://dev.to/jvicmaina/how-to-automate-image-captcha-solving-using-2captcha-api-with-python-selenium-3ka5</guid>
      <description>&lt;p&gt;CAPTCHAs are a common security measure to prevent bots from accessing websites. While they serve a legitimate purpose, they can be a hurdle for automation tasks. In this guide, we'll explore how to automate solving image-based CAPTCHAs using the 2Captcha API with Python and Selenium.&lt;/p&gt;

&lt;p&gt;Prerequisites&lt;br&gt;
Before we begin, ensure you have:&lt;/p&gt;

&lt;p&gt;Python installed (3.6+ recommended)&lt;/p&gt;

&lt;p&gt;A 2Captcha API key &lt;a href="https://2captcha.com/2captcha-api" rel="noopener noreferrer"&gt;(Sign up here)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Basic knowledge of Selenium WebDriver&lt;/p&gt;

&lt;p&gt;Required Python packages:&lt;/p&gt;

&lt;p&gt;bash&lt;br&gt;
&lt;code&gt;pip install selenium requests pillow python-dotenv twocaptcha-python&lt;/code&gt;&lt;br&gt;
Step 1: Setting Up the Environment&lt;br&gt;
1.1 Install Required Libraries&lt;br&gt;
bash&lt;br&gt;
&lt;code&gt;pip install selenium requests pillow python-dotenv twocaptcha&lt;/code&gt;&lt;br&gt;
1.2 Store API Key in .env&lt;br&gt;
Create a .env file:&lt;/p&gt;

&lt;p&gt;env&lt;br&gt;
&lt;code&gt;APIKEY=your_2captcha_api_key_here&lt;/code&gt;&lt;br&gt;
1.3 Initialize Selenium WebDriver&lt;br&gt;
python&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager

def create_browser(headless=False):
    options = Options()
    options.add_argument("--disable-blink-features=AutomationControlled")
    options.add_argument("--no-sandbox")
    options.add_argument("--disable-dev-shm-usage")

    if headless:
        options.add_argument("--headless=new")

    driver = webdriver.Chrome(
        service=Service(ChromeDriverManager().install()),
        options=options
    )
    return driver
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 2: Extracting the CAPTCHA Image&lt;br&gt;
We need to locate the CAPTCHA image and download it for processing.&lt;/p&gt;

&lt;p&gt;python&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import base64
import requests

def get_captcha_image(driver):
    try:
        captcha_img = WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.XPATH, 
                "//img[contains(@src, 'captcha') or contains(@src, 'code')]"))
        )

        img_src = captcha_img.get_attribute('src')
        if img_src.startswith('data:image'):
            img_data = base64.b64decode(img_src.split(',')[1])
        else:
            img_data = requests.get(img_src).content

        with open('captcha.jpg', 'wb') as f:
            f.write(img_data)

        return 'captcha.jpg'
    except Exception as e:
        print(f"❌ Failed to get CAPTCHA: {str(e)}")
        return None
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 3: Solving CAPTCHA Using 2Captcha API&lt;br&gt;
Now, we'll send the CAPTCHA image to 2Captcha and retrieve the solution.&lt;/p&gt;

&lt;p&gt;python&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from twocaptcha import TwoCaptcha
from dotenv import load_dotenv
import os

load_dotenv()
API_KEY = os.getenv("APIKEY")
solver = TwoCaptcha(API_KEY)

def solve_captcha(image_path):
    try:
        result = solver.normal(image_path, numeric=0, minLen=4, maxLen=6)
        return result['code']
    except Exception as e:
        print(f"❌ CAPTCHA solving failed: {str(e)}")
        return None
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 4: Submitting the Solved CAPTCHA&lt;br&gt;
Once we have the solution, we fill the input field and submit the form.&lt;/p&gt;

&lt;p&gt;python&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def submit_captcha_solution(driver, solution):
    try:
        input_field = WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.XPATH, 
                "//input[contains(@name, 'captcha') or contains(@id, 'captcha')]"))
        )
        input_field.clear()
        input_field.send_keys(solution)

        submit_button = WebDriverWait(driver, 10).until(
            EC.element_to_be_clickable((By.XPATH, "//button[@type='submit']"))
        )
        submit_button.click()
        return True
    except Exception as e:
        print(f"❌ Failed to submit CAPTCHA: {str(e)}")
        return False
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 5: Putting It All Together&lt;br&gt;
Now, let's combine all steps into a single workflow.&lt;/p&gt;

&lt;p&gt;python&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def automate_captcha_solving(driver, url):
    driver.get(url)

    # Step 1: Get CAPTCHA image
    captcha_image = get_captcha_image(driver)
    if not captcha_image:
        return False

    # Step 2: Solve CAPTCHA
    solution = solve_captcha(captcha_image)
    if not solution:
        return False

    # Step 3: Submit solution
    return submit_captcha_solution(driver, solution)

# Example Usage
if __name__ == "__main__":
    driver = create_browser(headless=False)
    success = automate_captcha_solving(driver, "https://example.com/captcha-page")
    print("✅ CAPTCHA solved successfully!" if success else "❌ Failed to solve CAPTCHA")
    driver.quit()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Common Issues &amp;amp; Fixes&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;CAPTCHA Not Detected
Fix: Adjust the XPath to match the website’s CAPTCHA element.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;python&lt;br&gt;
&lt;code&gt;"//img[contains(@class, 'captcha-img')]"&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;2Captcha API Fails
Fix: Check your API key balance and ensure the image is clear.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Enhance image quality before sending:&lt;/p&gt;

&lt;p&gt;python&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from PIL import Image, ImageFilter, ImageEnhance

def enhance_image(image_path):
    img = Image.open(image_path)
    img = img.convert('L')  # Grayscale
    enhancer = ImageEnhance.Contrast(img)
    img = enhancer.enhance(2.0)  # Increase contrast
    img.save('enhanced_captcha.jpg')
    return 'enhanced_captcha.jpg'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Submit Button Not Clickable
Fix: Use JavaScript click as a fallback:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;python&lt;br&gt;
&lt;code&gt;driver.execute_script("arguments[0].click();", submit_button)&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
Conclusion&lt;br&gt;
By using 2Captcha API with Selenium, we can automate CAPTCHA solving efficiently. This method is useful for:&lt;/p&gt;

&lt;p&gt;Web scraping (where CAPTCHAs block data extraction)&lt;/p&gt;

&lt;p&gt;Automated testing (bypassing CAPTCHAs in test environments)&lt;/p&gt;

&lt;p&gt;Bot automation (for repetitive tasks requiring login)&lt;/p&gt;

&lt;p&gt;Final Thoughts&lt;br&gt;
While automation is powerful, always respect website policies and use this method ethically. Some websites may block automated CAPTCHA-solving attempts, so use it responsibly.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Create and Publish a VS Code Extension</title>
      <dc:creator>Victor Maina</dc:creator>
      <pubDate>Sat, 19 Jul 2025 23:47:50 +0000</pubDate>
      <link>https://dev.to/jvicmaina/how-to-create-and-publish-a-vs-code-extension-jlm</link>
      <guid>https://dev.to/jvicmaina/how-to-create-and-publish-a-vs-code-extension-jlm</guid>
      <description>&lt;p&gt;📦 Step 1: Install Required Tools&lt;br&gt;
We started by installing the Yeoman generator for VS Code:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install -g yo generator-code&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
Then we used the generator to scaffold a new extension:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;yo code&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
💡 This gives you multiple options like creating a TypeScript/JavaScript extension, web extension, or even a theme/snippet pack. We selected the basic TypeScript extension for this demo.&lt;/p&gt;

&lt;p&gt;⚙️ Step 2: Install the VSCE Publisher Tool&lt;br&gt;
VSCE (Visual Studio Code Extension) is the CLI tool used to package and publish your extension to the marketplace.&lt;/p&gt;

&lt;p&gt;We installed it using:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install -g @vscode/vsce&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;⚠️ If you see a warning like EBADENGINE, it means your Node.js version is slightly outdated. VSCE is asking for Node &amp;gt;=20.18.1, while you have v20.17.0. Consider updating Node.js if issues persist.&lt;/p&gt;

&lt;p&gt;🔐 Step 3: Get a Personal Access Token (PAT)&lt;br&gt;
To publish to the VS Code Marketplace, you need a Personal Access Token (PAT) from your Microsoft account via Azure DevOps. Here's how:&lt;/p&gt;

&lt;p&gt;Go to: &lt;a href="https://dev.azure.com" rel="noopener noreferrer"&gt;https://dev.azure.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sign in using your Microsoft or GitHub account.&lt;/p&gt;

&lt;p&gt;In the top-right corner, click on your profile picture → "Personal access tokens".&lt;/p&gt;

&lt;p&gt;Click New Token:&lt;/p&gt;

&lt;p&gt;Organization: All accessible organizations&lt;/p&gt;

&lt;p&gt;Scopes: Select only "Marketplace" → "Manage"&lt;/p&gt;

&lt;p&gt;Expiry: You can choose 90 days or custom&lt;/p&gt;

&lt;p&gt;Save the token (copy it somewhere safe — it's shown once).&lt;/p&gt;

&lt;p&gt;👤 Step 4: Create a Publisher&lt;br&gt;
Before publishing, you need to create a publisher (your dev alias or brand name):&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vsce create-publisher your-publisher-name&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
You'll be asked for:&lt;/p&gt;

&lt;p&gt;Your Personal Access Token&lt;/p&gt;

&lt;p&gt;Publisher display name&lt;/p&gt;

&lt;p&gt;This will register your publisher to the VS Code Marketplace.&lt;/p&gt;

&lt;p&gt;📦 Step 5: Package Your Extension&lt;br&gt;
Now, navigate into your extension folder and run:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vsce package&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will generate a .vsix file (e.g., my-extension-0.0.1.vsix) that contains your whole extension, ready for publishing or manual installation.&lt;/p&gt;

&lt;p&gt;🚀 Step 6: Publish to Marketplace&lt;br&gt;
Once packaged, you can publish directly:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vsce publish&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Or specify a version bump manually:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vsce publish minor&lt;br&gt;
vsce publish major&lt;br&gt;
vsce publish patch&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
🔑 You'll be prompted for your PAT again unless it's cached.&lt;/p&gt;

&lt;p&gt;🎯 Optional: Install Locally for Testing&lt;br&gt;
Before publishing, you can test your .vsix locally by running:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;code --install-extension my-extension-0.0.1.vsix&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;💰 Do People Earn from Publishing Extensions?&lt;br&gt;
Publishing alone doesn’t pay. However, you can monetize in several ways:&lt;/p&gt;

&lt;p&gt;Offer pro features via APIs or subscriptions&lt;/p&gt;

&lt;p&gt;Integrate SaaS tools (e.g., integrations with GPT, Firebase, etc.)&lt;/p&gt;

&lt;p&gt;Offer paid versions outside the marketplace&lt;/p&gt;

&lt;p&gt;Accept donations via GitHub Sponsors or Buy Me a Coffee&lt;/p&gt;

&lt;p&gt;Build a portfolio/brand that leads to freelance or dev job offers&lt;/p&gt;

&lt;p&gt;✅ Final Thoughts&lt;br&gt;
Now that your extension is published:&lt;/p&gt;

&lt;p&gt;Track downloads &amp;amp; installs via Visual Studio Marketplace&lt;/p&gt;

&lt;p&gt;Update frequently with new features and fixes&lt;/p&gt;

&lt;p&gt;Share it on GitHub, Reddit, Twitter, and developer forums&lt;/p&gt;

</description>
    </item>
    <item>
      <title>What is a Slug and Why Your Website Needs It for Better SEO</title>
      <dc:creator>Victor Maina</dc:creator>
      <pubDate>Thu, 10 Jul 2025 23:07:13 +0000</pubDate>
      <link>https://dev.to/jvicmaina/what-is-a-slug-and-why-your-website-needs-it-for-better-seo-hmc</link>
      <guid>https://dev.to/jvicmaina/what-is-a-slug-and-why-your-website-needs-it-for-better-seo-hmc</guid>
      <description>&lt;p&gt;When building modern websites  especially e-commerce stores or blogs — you'll often hear developers say, "Let's create a slug for this page." But what exactly is a slug, and why should you care?&lt;/p&gt;

&lt;p&gt;A slug is the part of a URL that comes after the domain name and identifies a specific page in a readable way.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;/hoodies&lt;/p&gt;

&lt;p&gt;/blog/why-seo-matters&lt;/p&gt;

&lt;p&gt;/product/254-streetwear-shirt&lt;/p&gt;

&lt;p&gt;Why Not Use an ID Instead?&lt;br&gt;
You could build URLs like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/product?id=12345&lt;/code&gt;&lt;br&gt;
But slugs are better because:&lt;/p&gt;

&lt;p&gt;✅ They're readable&lt;br&gt;
✅ They're memorable&lt;br&gt;
✅ They look cleaner&lt;br&gt;
✅ And... Google loves them!&lt;/p&gt;

&lt;p&gt;Why Slugs Help SEO&lt;br&gt;
Here’s why slugs are powerful for SEO (Search Engine Optimization):&lt;/p&gt;

&lt;p&gt;Keywords in Slugs Improve Ranking&lt;br&gt;
When someone searches “254 streetwear shirt”, Google checks if those words appear in your slug.&lt;/p&gt;

&lt;p&gt;Users Are More Likely to Click Clean URLs&lt;br&gt;
Which would you click?&lt;/p&gt;

&lt;p&gt;/product?id=12345&lt;/p&gt;

&lt;p&gt;/products/254-streetwear-shirt&lt;/p&gt;

&lt;p&gt;Slugs Help Build Trust&lt;br&gt;
Clean, human-readable URLs feel more legit and professional.&lt;/p&gt;

&lt;p&gt;🔧 How We Use Slugs in Code (Next.js Example)&lt;br&gt;
In our e-commerce project, we use Next.js with a dynamic route:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/app/[slug]/page.tsx&lt;/code&gt;&lt;br&gt;
This tells Next.js:&lt;/p&gt;

&lt;p&gt;"Any product or blog post that has a unique slug like /hoodies or /254-threads-cap will load this page."&lt;/p&gt;

&lt;p&gt;Then in code, we access that slug using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async function Page({ params }: { params: { slug: string } }) {
  const slug = params.slug;
  // Now you can query your database for the product with that slug
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🛍 Real World Example&lt;br&gt;
If you’re selling a hoodie named "254 Threads Hoodie", your product URL would look like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/products/254-threads-hoodie&lt;/code&gt;&lt;br&gt;
Instead of:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/products?id=76383&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;That last part — like "254-streetwear-shirt" — is the slug.&lt;/p&gt;

&lt;p&gt;Slugs are more than just fancy URLs. They’re:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A big part of your user experience&lt;/li&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;li&gt;A simple but powerful SEO strategy&lt;/li&gt;
&lt;li&gt;And a best practice for modern websites and apps&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;📣 So next time you're naming a blog post or product page, think about your slug — your future self (and Google) will thank you!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Why Your Favicon Isn't Updating Across All Browsers (And How to Fix It)</title>
      <dc:creator>Victor Maina</dc:creator>
      <pubDate>Tue, 01 Jul 2025 11:51:29 +0000</pubDate>
      <link>https://dev.to/jvicmaina/why-your-favicon-isnt-updating-across-all-browsers-and-how-to-fix-it-2i3c</link>
      <guid>https://dev.to/jvicmaina/why-your-favicon-isnt-updating-across-all-browsers-and-how-to-fix-it-2i3c</guid>
      <description>&lt;p&gt;Have you ever updated your favicon in a Next.js project, only to see the new icon show up in one browser (like Edge) but not in others like Brave or Chrome?&lt;/p&gt;

&lt;p&gt;You're not alone—and there's a good reason for this.&lt;/p&gt;

&lt;p&gt;Modern browsers—especially Chromium-based ones like Brave, Chrome, and Opera—aggressively cache favicons. This means even if you've updated the favicon.ico file and restarted your dev server, the browser might still display the old one from cache.&lt;/p&gt;

&lt;p&gt;This caching behavior improves performance, but it causes confusion during development.&lt;/p&gt;

&lt;p&gt;✅ How I Fixed It (in Brave)&lt;br&gt;
Here’s what finally worked:&lt;/p&gt;

&lt;p&gt;🔁 1. Hard Refresh the Tab&lt;br&gt;
Force Brave to reload without using cache:&lt;/p&gt;

&lt;p&gt;Windows/Linux: Ctrl + Shift + R&lt;/p&gt;

&lt;p&gt;macOS: Cmd + Shift + R&lt;/p&gt;

&lt;p&gt;If that fails…&lt;/p&gt;

&lt;p&gt;🧼 2. Clear the Favicon Cache&lt;br&gt;
Brave (and Chrome) provide a hidden tool for this:&lt;/p&gt;

&lt;p&gt;Open chrome://favicon-internals in Brave&lt;/p&gt;

&lt;p&gt;Click on Clear Favicon Cache&lt;/p&gt;

&lt;p&gt;Reload your site&lt;/p&gt;

&lt;p&gt;Still not working? Try one more thing…&lt;/p&gt;

&lt;p&gt;📝 3. Rename the Favicon File&lt;br&gt;
Browsers cache based on the URL. Renaming the file tricks the browser into thinking it’s a new one.&lt;/p&gt;

&lt;p&gt;Rename your file to something like favicon-v2.ico&lt;/p&gt;

&lt;p&gt;Update your Next.js metadata:&lt;/p&gt;

&lt;p&gt;tsx&lt;br&gt;
Copy&lt;br&gt;
Edit&lt;br&gt;
export const metadata = {&lt;br&gt;
  title: "254THREADS",&lt;br&gt;
  icons: {&lt;br&gt;
    icon: "/favicon-v2.ico",&lt;br&gt;
  },&lt;br&gt;
};&lt;br&gt;
Now restart your dev server and refresh the page.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>💥 That One Time globals.css Crashed My Next.js Build</title>
      <dc:creator>Victor Maina</dc:creator>
      <pubDate>Mon, 30 Jun 2025 21:33:24 +0000</pubDate>
      <link>https://dev.to/jvicmaina/that-one-time-globalscss-crashed-my-nextjs-build-5e2m</link>
      <guid>https://dev.to/jvicmaina/that-one-time-globalscss-crashed-my-nextjs-build-5e2m</guid>
      <description>&lt;p&gt;You ever update some colors in your tailwind.config.ts and suddenly your entire Next.js app refuses to compile? Yeah. That happened to me.&lt;/p&gt;

&lt;p&gt;Error I saw:&lt;/p&gt;

&lt;p&gt;SyntaxError: Unexpected token, expected "(" (18:19)&lt;br&gt;
Import trace for requested module:&lt;br&gt;
./src/app/globals.css&lt;br&gt;
And I was like... huh? That file only has three Tailwind directives. What gives?&lt;/p&gt;

&lt;p&gt;🔍 The Culprit? My PostCSS Config&lt;br&gt;
Turns out, the issue wasn’t in the CSS at all — it was my postcss.mjs file. I had:&lt;/p&gt;

&lt;p&gt;js&lt;br&gt;
plugins: {&lt;br&gt;
  tailwindcss: {},&lt;br&gt;
}&lt;br&gt;
What I didn't have was this essential plugin:&lt;/p&gt;

&lt;p&gt;js&lt;br&gt;
autoprefixer: {}, // &amp;lt;- 👀 this bad boy is mandatory&lt;br&gt;
Without autoprefixer, Next.js quietly panics when it tries to compile CSS — and throws an error totally unrelated to the root cause. Classic.&lt;/p&gt;

&lt;p&gt;🛠️ The Fix&lt;br&gt;
Install Autoprefixer&lt;/p&gt;

&lt;p&gt;bash&lt;br&gt;
npm install -D autoprefixer&lt;br&gt;
Update postcss.mjs&lt;/p&gt;

&lt;p&gt;js&lt;br&gt;
/** @type {import('postcss-load-config').Config} */&lt;br&gt;
const config = {&lt;br&gt;
  plugins: {&lt;br&gt;
    tailwindcss: {},&lt;br&gt;
    autoprefixer: {},&lt;br&gt;
  },&lt;br&gt;
};&lt;/p&gt;

&lt;p&gt;export default config;&lt;br&gt;
Clear the cache &amp;amp; restart&lt;/p&gt;

&lt;p&gt;bash&lt;br&gt;
rm -rf .next&lt;br&gt;
npm run dev&lt;br&gt;
Boom 💣 No more phantom syntax errors.&lt;/p&gt;

&lt;p&gt;💡 Final Tip&lt;br&gt;
If your Next.js build suddenly explodes and you didn’t even touch JavaScript, suspect your CSS pipeline. It’s always the quiet files 😅&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Don’t Click, Just grep: The Smart Way to Find Files Fast</title>
      <dc:creator>Victor Maina</dc:creator>
      <pubDate>Mon, 16 Jun 2025 19:12:24 +0000</pubDate>
      <link>https://dev.to/jvicmaina/dont-click-just-grep-the-smart-way-to-find-files-fast-4k6g</link>
      <guid>https://dev.to/jvicmaina/dont-click-just-grep-the-smart-way-to-find-files-fast-4k6g</guid>
      <description>&lt;p&gt;How to Use grep to Find Files by Extension Like a Command-Line Ninja&lt;br&gt;
Ever found yourself swimming in a sea of downloads trying to fish out all the .jpg images? If you love clean terminals and fast results, grep has your back.&lt;/p&gt;

&lt;p&gt;Here’s how to use grep like a pro to filter files by extension straight from your terminal.&lt;/p&gt;

&lt;p&gt;📁 List .jpg Files in Downloads&lt;br&gt;
&lt;strong&gt;bash&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ls ~/Downloads | grep '\.jpg$'&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;📁 Case-Insensitive Search (JPG, jpg, JpG...)&lt;br&gt;
&lt;strong&gt;bash&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ls ~/Downloads | grep -i '\.jpg$'&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;🔁 Search Recursively Through Subfolders&lt;br&gt;
&lt;strong&gt;bash&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;find ~/Downloads -type f | grep '\.jpg$'&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;💡 Bonus: Windows Equivalent&lt;br&gt;
&lt;strong&gt;CMD:&lt;/strong&gt;&lt;br&gt;
cmd&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dir %USERPROFILE%\Downloads\*.jpg&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PowerShell:&lt;/strong&gt;&lt;br&gt;
powershell&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Get-ChildItem "$env:USERPROFILE\Downloads" -Filter *.jpg&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Getting set with Athena in simple steps</title>
      <dc:creator>Victor Maina</dc:creator>
      <pubDate>Thu, 17 Apr 2025 12:53:40 +0000</pubDate>
      <link>https://dev.to/jvicmaina/getting-set-with-athena-in-simple-steps-10oo</link>
      <guid>https://dev.to/jvicmaina/getting-set-with-athena-in-simple-steps-10oo</guid>
      <description>&lt;p&gt;Getting Started with Amazon Athena: &lt;/p&gt;

&lt;p&gt;Query Your S3 Data with SQL&lt;br&gt;
Amazon Athena makes it incredibly easy to explore and analyze data stored in Amazon S3 using standard SQL queries. Whether you're working with log files, application data, or structured datasets, Athena allows you to treat your S3 files as a database—no ETL or server setup required.&lt;/p&gt;

&lt;p&gt;🧠 What Is Amazon Athena?&lt;br&gt;
Amazon Athena is a serverless, interactive query service that lets you analyze data in Amazon S3 using standard SQL. There's no infrastructure to manage, and you only pay for the queries you run.&lt;/p&gt;

&lt;p&gt;Athena supports various file formats including:&lt;/p&gt;

&lt;p&gt;CSV&lt;/p&gt;

&lt;p&gt;JSON&lt;/p&gt;

&lt;p&gt;ORC (Optimized Row Columnar)&lt;/p&gt;

&lt;p&gt;Apache Avro&lt;/p&gt;

&lt;p&gt;Parquet&lt;/p&gt;

&lt;p&gt;It’s also optimized for performance through parallelism, making it fast and efficient for large datasets.&lt;/p&gt;

&lt;p&gt;💸 How Much Does Athena Cost?&lt;br&gt;
Athena charges you based on the amount of data scanned per query. As of writing, the cost is $5 per TB scanned, so it’s important to optimize your data (e.g., by compressing it or using columnar formats like Parquet or ORC).&lt;/p&gt;

&lt;p&gt;📦 Step 1: Prepare Your S3 Bucket&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbiz04vmb3x1s2o55pjiw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbiz04vmb3x1s2o55pjiw.png" alt="Image description" width="800" height="449"&gt;&lt;/a&gt;&lt;br&gt;
If this is your first time using Athena, you’ll need to set up an S3 bucket to store your data. Here’s how:&lt;/p&gt;

&lt;p&gt;Go to the S3 console and create a new bucket.&lt;/p&gt;

&lt;p&gt;Make sure you note the AWS region—Athena and the S3 bucket must be in the same region.&lt;/p&gt;

&lt;p&gt;Upload your dataset. For this tutorial, we’re using a sample Order data CSV file.&lt;/p&gt;

&lt;p&gt;We’ll also create a second S3 bucket to store the results of our Athena queries (this is required by Athena).&lt;/p&gt;

&lt;p&gt;🧰 Step 2: Set Up AWS Glue for Schema Discovery&lt;br&gt;
Athena needs a schema to understand your data. Instead of defining it manually, we’ll use AWS Glue to automatically crawl and catalog our dataset.&lt;/p&gt;

&lt;p&gt;Go to the AWS Glue Console.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foc380hkwuwjhikcye0zs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foc380hkwuwjhikcye0zs.png" alt="Aws glue table schema  crawler" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create a new database (e.g., order_data_db).&lt;/p&gt;

&lt;p&gt;Create a crawler:&lt;/p&gt;

&lt;p&gt;Set the source as your S3 data bucket.&lt;/p&gt;

&lt;p&gt;Choose the database you just created.&lt;/p&gt;

&lt;p&gt;Run the crawler to populate the schema.&lt;/p&gt;

&lt;p&gt;🔍 Step 3: Query Your Data in Athena&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp9id2kiwl01w6p1n2k6o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp9id2kiwl01w6p1n2k6o.png" alt="Image description" width="800" height="449"&gt;&lt;/a&gt;&lt;br&gt;
Now that the table is ready, it’s time to query your data:&lt;/p&gt;

&lt;p&gt;Open the Athena Query Editor.&lt;/p&gt;

&lt;p&gt;Make sure the correct database is selected.&lt;/p&gt;

&lt;p&gt;Run a sample SQL query like:&lt;/p&gt;

&lt;p&gt;SELECT * FROM orders LIMIT 10;&lt;br&gt;
You’ll see the results right in your browser. Athena also saves them as CSV files in your specified results bucket.&lt;/p&gt;

&lt;p&gt;📊 Bonus: Visualize Your Data with Amazon QuickSight&lt;br&gt;
Want to turn your raw queries into dashboards? You can connect Athena to Amazon QuickSight to create dynamic visualizations of your data. This is great for exploring patterns or trends in logs, sales data, and more.&lt;/p&gt;

&lt;p&gt;🧹 Step 4: Clean Up Your Resources&lt;br&gt;
Once you're done, be sure to delete any AWS resources to avoid ongoing charges:&lt;/p&gt;

&lt;p&gt;Delete the S3 buckets you created (both the data and the results buckets).&lt;/p&gt;

&lt;p&gt;Delete the AWS Glue crawler and database.&lt;/p&gt;

&lt;p&gt;Remove any saved Athena queries or saved workgroups, if applicable.&lt;/p&gt;

&lt;p&gt;Remember, Athena’s billing is based on the volume of data scanned cleanups and query optimization are key to keeping costs low.&lt;/p&gt;

&lt;p&gt;✅ Wrapping Up&lt;br&gt;
Amazon Athena is a powerful tool that simplifies querying large datasets stored in S3 using familiar SQL syntax. It’s perfect for analysts, engineers, and data enthusiasts who want fast insights without the overhead of managing infrastructure.&lt;/p&gt;

&lt;p&gt;In this tutorial, we walked through setting up S3, using AWS Glue to create a schema, querying with Athena, and finally cleaning up your resources. Now you’re ready to start analyzing your own data!&lt;/p&gt;

&lt;p&gt;Would you like me to help turn this into a blog post or Markdown file, or add code blocks/screenshots for each step?&lt;/p&gt;

&lt;p&gt;Reason&lt;/p&gt;

</description>
      <category>athena</category>
      <category>s3</category>
      <category>aws</category>
      <category>cloudpractitioner</category>
    </item>
    <item>
      <title>Resolving CORS Issues</title>
      <dc:creator>Victor Maina</dc:creator>
      <pubDate>Mon, 10 Mar 2025 19:59:16 +0000</pubDate>
      <link>https://dev.to/jvicmaina/resolving-cors-issues-lme</link>
      <guid>https://dev.to/jvicmaina/resolving-cors-issues-lme</guid>
      <description>&lt;p&gt;CORS (Cross-Origin Resource Sharing) errors occur when the frontend and backend are hosted on different domains or ports. To fix this:&lt;/p&gt;

&lt;p&gt;Install CORS Middleware:&lt;br&gt;
In your backend, install the cors package:&lt;/p&gt;

&lt;p&gt;bash&lt;br&gt;
Copy&lt;br&gt;
npm install cors&lt;br&gt;
Enable CORS:&lt;br&gt;
Update your backend code to allow requests from the frontend:&lt;/p&gt;

&lt;p&gt;javascript&lt;br&gt;
Copy&lt;br&gt;
const cors = require('cors');&lt;br&gt;
const express = require('express');&lt;br&gt;
const app = express();&lt;/p&gt;

&lt;p&gt;app.use(cors({&lt;br&gt;
  origin: '&lt;a href="http://102.37.21.212:3000" rel="noopener noreferrer"&gt;http://102.37.21.212:3000&lt;/a&gt;', // Frontend URL&lt;br&gt;
  credentials: true&lt;br&gt;
}));&lt;/p&gt;

&lt;p&gt;app.post('/auth/login', (req, res) =&amp;gt; {&lt;br&gt;
  // Handle login&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;app.listen(4000, () =&amp;gt; {&lt;br&gt;
  console.log('Backend running on port 4000');&lt;br&gt;
});&lt;br&gt;
Restart the Backend:&lt;br&gt;
Restart the backend to apply the changes:&lt;/p&gt;

&lt;p&gt;bash&lt;br&gt;
Copy&lt;br&gt;
pm2 restart uvotake-backend&lt;br&gt;
This ensures the backend accepts requests from the frontend.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Opening Ports in Azure
To allow external access to your app, open the necessary ports in Azure:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Go to your VM in the Azure Portal.&lt;/p&gt;

&lt;p&gt;Under Networking, add inbound port rules:&lt;/p&gt;

&lt;p&gt;Frontend: Open port 3000 for HTTP access.&lt;/p&gt;

&lt;p&gt;Backend: Open port 4000 for API access.&lt;/p&gt;

&lt;p&gt;Save the rules and test connectivity:&lt;/p&gt;

&lt;p&gt;bash&lt;br&gt;
Copy&lt;br&gt;
curl http://:3000&lt;br&gt;
curl http://:4000/auth/login&lt;br&gt;
This ensures your app is accessible to users.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Using PM2 for Process Management
To keep your app running after disconnecting from the VM, use PM2:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Install PM2:&lt;/p&gt;

&lt;p&gt;bash&lt;br&gt;
Copy&lt;br&gt;
sudo npm install -g pm2&lt;br&gt;
Start the App:&lt;br&gt;
Use PM2 to serve the frontend:&lt;/p&gt;

&lt;p&gt;bash&lt;br&gt;
Copy&lt;br&gt;
pm2 serve build 3000 --name "uvotake-frontend"&lt;br&gt;
Save the Process:&lt;br&gt;
Ensure the app starts automatically after a reboot:&lt;/p&gt;

&lt;p&gt;bash&lt;br&gt;
Copy&lt;br&gt;
pm2 save&lt;br&gt;
pm2 startup&lt;br&gt;
PM2 ensures your app runs continuously.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Fixing "Reached Heap Limit" Errors</title>
      <dc:creator>Victor Maina</dc:creator>
      <pubDate>Mon, 10 Mar 2025 19:58:38 +0000</pubDate>
      <link>https://dev.to/jvicmaina/fixing-reached-heap-limit-errors-iig</link>
      <guid>https://dev.to/jvicmaina/fixing-reached-heap-limit-errors-iig</guid>
      <description>&lt;p&gt;When building your React app, you might encounter FATAL ERROR: Reached heap limit. This happens because the VM has limited memory (e.g., 1 GiB). Here’s how to fix it:&lt;/p&gt;

&lt;p&gt;Increase Memory for Node.js:&lt;br&gt;
Update the build script in package.json:&lt;/p&gt;

&lt;p&gt;json&lt;br&gt;
Copy&lt;br&gt;
"build": "node --max-old-space-size=2048 $(which react-scripts) build"&lt;br&gt;
This allocates 2 GB of memory for the build process.&lt;/p&gt;

&lt;p&gt;Add Swap Space:&lt;br&gt;
Create a swap file to provide additional virtual memory:&lt;/p&gt;

&lt;p&gt;bash&lt;br&gt;
Copy&lt;br&gt;
sudo fallocate -l 2G /swapfile&lt;br&gt;
sudo chmod 600 /swapfile&lt;br&gt;
sudo mkswap /swapfile&lt;br&gt;
sudo swapon /swapfile&lt;br&gt;
Rebuild the App:&lt;br&gt;
Run the build again:&lt;/p&gt;

&lt;p&gt;bash&lt;br&gt;
Copy&lt;br&gt;
npm run build&lt;br&gt;
This resolves memory issues during the build process.&lt;/p&gt;

</description>
      <category>react</category>
      <category>node</category>
      <category>howto</category>
    </item>
    <item>
      <title>Creating a Virtual Machine (VM) on Azure</title>
      <dc:creator>Victor Maina</dc:creator>
      <pubDate>Mon, 10 Mar 2025 19:56:53 +0000</pubDate>
      <link>https://dev.to/jvicmaina/creating-a-virtual-machine-vm-on-azure-5g5b</link>
      <guid>https://dev.to/jvicmaina/creating-a-virtual-machine-vm-on-azure-5g5b</guid>
      <description>&lt;p&gt;Hosting your app starts with creating a VM on Azure. Here’s how to do it:&lt;/p&gt;

&lt;p&gt;Go to the Azure Portal and click Create a Resource.&lt;/p&gt;

&lt;p&gt;Select Virtual Machine and choose a configuration (e.g., Ubuntu 24.04, Standard B1s).&lt;/p&gt;

&lt;p&gt;Configure networking, storage, and SSH keys for secure access.&lt;/p&gt;

&lt;p&gt;Once the VM is created, note its public IP address (e.g., 102.37.21.212).&lt;/p&gt;

&lt;p&gt;Use SSH to connect to the VM:&lt;/p&gt;

&lt;p&gt;bash&lt;br&gt;
Copy&lt;br&gt;
ssh -i  azureuser@&lt;br&gt;
This VM will serve as the hosting environment for your app.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Uploading Files to the VM Without Docker
To deploy your app without Docker:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Transfer Files:&lt;br&gt;
Use scp to copy your frontend and backend files to the VM:&lt;/p&gt;

&lt;p&gt;bash&lt;br&gt;
Copy&lt;br&gt;
scp -r -i   azureuser@:&lt;br&gt;
Example:&lt;/p&gt;

&lt;p&gt;bash&lt;br&gt;
Copy&lt;br&gt;
scp -r -i ~/keys/uvotakeV_key.pem ~/Desktop/frontend &lt;a href="mailto:azureuser@102.37.21.212"&gt;azureuser@102.37.21.212&lt;/a&gt;:/home/azureuser/frontend&lt;br&gt;
Install Dependencies:&lt;br&gt;
SSH into the VM and install dependencies:&lt;/p&gt;

&lt;p&gt;bash&lt;br&gt;
Copy&lt;br&gt;
cd ~/frontend&lt;br&gt;
npm install&lt;br&gt;
Build and Serve:&lt;br&gt;
Create a production build and serve it:&lt;/p&gt;

&lt;p&gt;bash&lt;br&gt;
Copy&lt;br&gt;
npm run build&lt;br&gt;
serve -s build -l 3000&lt;br&gt;
This approach avoids Docker and directly deploys your app to the VM.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
